diff options
Diffstat (limited to 'src/core/support')
27 files changed, 3005 insertions, 0 deletions
diff --git a/src/core/support/alloc.c b/src/core/support/alloc.c new file mode 100644 index 0000000000..658408f334 --- /dev/null +++ b/src/core/support/alloc.c @@ -0,0 +1,67 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <grpc/support/alloc.h> + +#include <stdlib.h> +#include <grpc/support/port_platform.h> + +void *gpr_malloc(size_t size) { + void *p = malloc(size); + if (!p) { + abort(); + } + return p; +} + +void gpr_free(void *p) { free(p); } + +void *gpr_realloc(void *p, size_t size) { + p = realloc(p, size); + if (!p) { + abort(); + } + return p; +} + +void *gpr_malloc_aligned(size_t size, size_t alignment) { + size_t extra = alignment - 1 + sizeof(void *); + void *p = gpr_malloc(size + extra); + void **ret = (void **)(((gpr_uintptr)p + extra) & ~(alignment - 1)); + ret[-1] = p; + return (void *)ret; +} + +void gpr_free_aligned(void *ptr) { + free(((void **)ptr)[-1]); +} diff --git a/src/core/support/cancellable.c b/src/core/support/cancellable.c new file mode 100644 index 0000000000..5596413fba --- /dev/null +++ b/src/core/support/cancellable.c @@ -0,0 +1,156 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* Implementation for gpr_cancellable */ + +#include <grpc/support/atm.h> +#include <grpc/support/sync.h> +#include <grpc/support/time.h> + +void gpr_cancellable_init(gpr_cancellable *c) { + gpr_mu_init(&c->mu); + c->cancelled = 0; + c->waiters.next = &c->waiters; + c->waiters.prev = &c->waiters; + c->waiters.mu = NULL; + c->waiters.cv = NULL; +} + +void gpr_cancellable_destroy(gpr_cancellable *c) { gpr_mu_destroy(&c->mu); } + +int gpr_cancellable_is_cancelled(gpr_cancellable *c) { + return gpr_atm_acq_load(&c->cancelled) != 0; +} + +/* Threads in gpr_cv_cancellable_wait(cv, mu, ..., c) place themselves on a + linked list c->waiters of gpr_cancellable_list_ before waiting on their + condition variables. They check for cancellation while holding *mu. Thus, + to wake a thread from gpr_cv_cancellable_wait(), it suffices to: + - set c->cancelled + - acquire and release *mu + - gpr_cv_broadcast(cv) + + However, gpr_cancellable_cancel() may not use gpr_mu_lock(mu), since the + caller may already hold *mu---a possible deadlock. (If we knew the caller + did not hold *mu, care would still be needed, because c->mu follows *mu in + the locking order, so *mu could not be acquired while holding c->mu---which + is needed to iterate over c->waiters.) + + Therefore, gpr_cancellable_cancel() uses gpr_mu_trylock() rather than + gpr_mu_lock(), and retries until either gpr_mu_trylock() succeeds or the + thread leaves gpr_cv_cancellable_wait() for other reasons. In the first + case, gpr_cancellable_cancel() removes the entry from the waiters list; in + the second, the waiting thread removes itself from the list. + + A one-entry cache of mutexes and condition variables processed is kept to + avoid doing the same work again and again if many threads are blocked in the + same place. However, it's important to broadcast on a condition variable if + the corresponding mutex has been locked successfully, even if the condition + variable has been signalled before. */ + +void gpr_cancellable_cancel(gpr_cancellable *c) { + if (!gpr_cancellable_is_cancelled(c)) { + int failures; + int backoff = 1; + do { + struct gpr_cancellable_list_ *l; + struct gpr_cancellable_list_ *nl; + gpr_mu *omu = 0; /* one-element cache of a processed gpr_mu */ + gpr_cv *ocv = 0; /* one-element cache of a processd gpr_cv */ + gpr_mu_lock(&c->mu); + gpr_atm_rel_store(&c->cancelled, 1); + failures = 0; + for (l = c->waiters.next; l != &c->waiters; l = nl) { + nl = l->next; + if (omu != l->mu) { + omu = l->mu; + if (gpr_mu_trylock(l->mu)) { + gpr_mu_unlock(l->mu); + l->next->prev = l->prev; /* remove *l from list */ + l->prev->next = l->next; + /* allow unconditional dequeue in gpr_cv_cancellable_wait() */ + l->next = l; + l->prev = l; + ocv = 0; /* force broadcast */ + } else { + failures++; + } + } + if (ocv != l->cv) { + ocv = l->cv; + gpr_cv_broadcast(l->cv); + } + } + gpr_mu_unlock(&c->mu); + if (failures != 0) { + if (backoff < 10) { + volatile int i; + for (i = 0; i != (1 << backoff); i++) { + } + backoff++; + } else { + gpr_event ev; + gpr_event_init(&ev); + gpr_event_wait(&ev, + gpr_time_add(gpr_now(), gpr_time_from_micros(1000))); + } + } + } while (failures != 0); + } +} + +int gpr_cv_cancellable_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline, + gpr_cancellable *c) { + gpr_int32 timeout; + gpr_mu_lock(&c->mu); + timeout = gpr_cancellable_is_cancelled(c); + if (!timeout) { + struct gpr_cancellable_list_ le; + le.mu = mu; + le.cv = cv; + le.next = c->waiters.next; + le.prev = &c->waiters; + le.next->prev = ≤ + le.prev->next = ≤ + gpr_mu_unlock(&c->mu); + timeout = gpr_cv_wait(cv, mu, abs_deadline); + gpr_mu_lock(&c->mu); + le.next->prev = le.prev; + le.prev->next = le.next; + if (!timeout) { + timeout = gpr_cancellable_is_cancelled(c); + } + } + gpr_mu_unlock(&c->mu); + return timeout; +} diff --git a/src/core/support/cmdline.c b/src/core/support/cmdline.c new file mode 100644 index 0000000000..ff163a1f6c --- /dev/null +++ b/src/core/support/cmdline.c @@ -0,0 +1,292 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <grpc/support/cmdline.h> + +#include <limits.h> +#include <stdio.h> +#include <string.h> + +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> +#include <grpc/support/string.h> + +typedef enum { ARGTYPE_INT, ARGTYPE_BOOL, ARGTYPE_STRING } argtype; + +typedef struct arg { + const char *name; + const char *help; + argtype type; + void *value; + struct arg *next; +} arg; + +struct gpr_cmdline { + const char *description; + arg *args; + const char *argv0; + + const char *extra_arg_name; + const char *extra_arg_help; + void (*extra_arg)(void *user_data, const char *arg); + void *extra_arg_user_data; + + void (*state)(gpr_cmdline *cl, char *arg); + arg *cur_arg; +}; + +static void normal_state(gpr_cmdline *cl, char *arg); + +gpr_cmdline *gpr_cmdline_create(const char *description) { + gpr_cmdline *cl = gpr_malloc(sizeof(gpr_cmdline)); + memset(cl, 0, sizeof(gpr_cmdline)); + + cl->description = description; + cl->state = normal_state; + + return cl; +} + +void gpr_cmdline_destroy(gpr_cmdline *cl) { + while (cl->args) { + arg *a = cl->args; + cl->args = a->next; + gpr_free(a); + } + gpr_free(cl); +} + +static void add_arg(gpr_cmdline *cl, const char *name, const char *help, + argtype type, void *value) { + arg *a; + + for (a = cl->args; a; a = a->next) { + GPR_ASSERT(0 != strcmp(a->name, name)); + } + + a = gpr_malloc(sizeof(arg)); + memset(a, 0, sizeof(arg)); + a->name = name; + a->help = help; + a->type = type; + a->value = value; + a->next = cl->args; + cl->args = a; +} + +void gpr_cmdline_add_int(gpr_cmdline *cl, const char *name, const char *help, + int *value) { + add_arg(cl, name, help, ARGTYPE_INT, value); +} + +void gpr_cmdline_add_flag(gpr_cmdline *cl, const char *name, const char *help, + int *value) { + add_arg(cl, name, help, ARGTYPE_BOOL, value); +} + +void gpr_cmdline_add_string(gpr_cmdline *cl, const char *name, const char *help, + char **value) { + add_arg(cl, name, help, ARGTYPE_STRING, value); +} + +void gpr_cmdline_on_extra_arg( + gpr_cmdline *cl, const char *name, const char *help, + void (*on_extra_arg)(void *user_data, const char *arg), void *user_data) { + GPR_ASSERT(!cl->extra_arg); + GPR_ASSERT(on_extra_arg); + + cl->extra_arg = on_extra_arg; + cl->extra_arg_user_data = user_data; + cl->extra_arg_name = name; + cl->extra_arg_help = help; +} + +static void print_usage_and_die(gpr_cmdline *cl) { + /* TODO(ctiller): make this prettier */ + arg *a; + const char *name = strrchr(cl->argv0, '/'); + if (name) { + name++; + } else { + name = cl->argv0; + } + fprintf(stderr, "Usage: %s", name); + for (a = cl->args; a; a = a->next) { + switch (a->type) { + case ARGTYPE_BOOL: + fprintf(stderr, " [--%s|--no-%s]", a->name, a->name); + break; + case ARGTYPE_STRING: + fprintf(stderr, " [--%s=string]", a->name); + break; + case ARGTYPE_INT: + fprintf(stderr, " [--%s=int]", a->name); + break; + } + } + if (cl->extra_arg) { + fprintf(stderr, " [%s...]", cl->extra_arg_name); + } + fprintf(stderr, "\n"); + exit(1); +} + +static void extra_state(gpr_cmdline *cl, char *arg) { + if (!cl->extra_arg) print_usage_and_die(cl); + cl->extra_arg(cl->extra_arg_user_data, arg); +} + +static arg *find_arg(gpr_cmdline *cl, char *name) { + arg *a; + + for (a = cl->args; a; a = a->next) { + if (0 == strcmp(a->name, name)) { + break; + } + } + + if (!a) { + fprintf(stderr, "Unknown argument: %s\n", name); + print_usage_and_die(cl); + } + + return a; +} + +static void value_state(gpr_cmdline *cl, char *arg) { + long intval; + char *end; + + GPR_ASSERT(cl->cur_arg); + + switch (cl->cur_arg->type) { + case ARGTYPE_INT: + intval = strtol(arg, &end, 0); + if (*end || intval < INT_MIN || intval > INT_MAX) { + fprintf(stderr, "expected integer, got '%s' for %s\n", arg, + cl->cur_arg->name); + print_usage_and_die(cl); + } + *(int *)cl->cur_arg->value = intval; + break; + case ARGTYPE_BOOL: + if (0 == strcmp(arg, "1") || 0 == strcmp(arg, "true")) { + *(int *)cl->cur_arg->value = 1; + } else if (0 == strcmp(arg, "0") || 0 == strcmp(arg, "false")) { + *(int *)cl->cur_arg->value = 0; + } else { + fprintf(stderr, "expected boolean, got '%s' for %s\n", arg, + cl->cur_arg->name); + print_usage_and_die(cl); + } + break; + case ARGTYPE_STRING: + *(char **)cl->cur_arg->value = arg; + break; + } + + cl->state = normal_state; +} + +static void normal_state(gpr_cmdline *cl, char *arg) { + char *eq = NULL; + char *tmp = NULL; + char *arg_name = NULL; + + if (0 == strcmp(arg, "-help") || 0 == strcmp(arg, "--help") || + 0 == strcmp(arg, "-h")) { + print_usage_and_die(cl); + } + + cl->cur_arg = NULL; + + if (arg[0] == '-') { + if (arg[1] == '-') { + if (arg[2] == 0) { + /* handle '--' to move to just extra args */ + cl->state = extra_state; + return; + } + arg += 2; + } else { + arg += 1; + } + /* first byte of arg is now past the leading '-' or '--' */ + if (arg[0] == 'n' && arg[1] == 'o' && arg[2] == '-') { + /* arg is of the form '--no-foo' - it's a flag disable */ + arg += 3; + cl->cur_arg = find_arg(cl, arg); + if (cl->cur_arg->type != ARGTYPE_BOOL) { + fprintf(stderr, "%s is not a flag argument\n", arg); + print_usage_and_die(cl); + } + *(int *)cl->cur_arg->value = 0; + return; /* early out */ + } + eq = strchr(arg, '='); + if (eq != NULL) { + /* copy the string into a temp buffer and extract the name */ + tmp = arg_name = gpr_malloc(eq - arg + 1); + memcpy(arg_name, arg, eq - arg); + arg_name[eq - arg] = 0; + } else { + arg_name = arg; + } + cl->cur_arg = find_arg(cl, arg_name); + if (eq != NULL) { + /* arg was of the type --foo=value, parse the value */ + value_state(cl, eq + 1); + } else if (cl->cur_arg->type != ARGTYPE_BOOL) { + /* flag types don't have a '--foo value' variant, other types do */ + cl->state = value_state; + } else { + /* flag parameter: just set the value */ + *(int *)cl->cur_arg->value = 1; + } + } else { + extra_state(cl, arg); + } + + gpr_free(tmp); +} + +void gpr_cmdline_parse(gpr_cmdline *cl, int argc, char **argv) { + int i; + + GPR_ASSERT(argc >= 1); + cl->argv0 = argv[0]; + + for (i = 1; i < argc; i++) { + cl->state(cl, argv[i]); + } +} diff --git a/src/core/support/cpu.h b/src/core/support/cpu.h new file mode 100644 index 0000000000..6ac0db35e5 --- /dev/null +++ b/src/core/support/cpu.h @@ -0,0 +1,49 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __GRPC_INTERNAL_SUPPORT_CPU_H__ +#define __GRPC_INTERNAL_SUPPORT_CPU_H__ + +/* Interface providing CPU information for currently running system */ + +/* Return the number of CPU cores on the current system. Will return 0 if + if information is not available. */ +int gpr_cpu_num_cores(); + +/* Return the CPU on which the current thread is executing; N.B. This should + be considered advisory only - it is possible that the thread is switched + to a different CPU at any time. Returns a value in range + [0, gpr_cpu_num_cores() - 1] */ +int gpr_cpu_current_cpu(); + +#endif /* __GRPC_INTERNAL_SUPPORT_CPU_H__ */ diff --git a/src/core/support/cpu_posix.c b/src/core/support/cpu_posix.c new file mode 100644 index 0000000000..82d58de2b4 --- /dev/null +++ b/src/core/support/cpu_posix.c @@ -0,0 +1,71 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/support/cpu.h" + +#ifdef __linux__ +#include <errno.h> +#include <unistd.h> +#define _GNU_SOURCE +#define __USE_GNU +#define __USE_MISC +#include <sched.h> +#undef _GNU_SOURCE +#undef __USE_GNU +#undef __USE_MISC +#include <string.h> + +#include <grpc/support/log.h> + +int gpr_cpu_num_cores() { + static int ncpus = 0; + if (ncpus == 0) { + ncpus = sysconf(_SC_NPROCESSORS_ONLN); + if (ncpus < 1) { + gpr_log(GPR_ERROR, "Cannot determine number of CPUs: assuming 1"); + ncpus = 1; + } + } + return ncpus; +} + +int gpr_cpu_current_cpu() { + int cpu = sched_getcpu(); + if (cpu < 0) { + gpr_log(GPR_ERROR, "Error determining current CPU: %s\n", strerror(errno)); + return 0; + } + return cpu; +} + +#endif /* __linux__ */ diff --git a/src/core/support/histogram.c b/src/core/support/histogram.c new file mode 100644 index 0000000000..a3ecd3e152 --- /dev/null +++ b/src/core/support/histogram.c @@ -0,0 +1,226 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <grpc/support/histogram.h> + +#include <math.h> +#include <stddef.h> +#include <string.h> + +#include <grpc/support/alloc.h> +#include <grpc/support/port_platform.h> +#include <grpc/support/log.h> +#include <grpc/support/useful.h> + +/* Histograms are stored with exponentially increasing bucket sizes. + The first bucket is [0, m) where m = 1 + resolution + Bucket n (n>=1) contains [m**n, m**(n+1)) + There are sufficient buckets to reach max_bucket_start */ + +struct gpr_histogram { + /* Sum of all values seen so far */ + double sum; + /* Sum of squares of all values seen so far */ + double sum_of_squares; + /* number of values seen so far */ + double count; + /* m in the description */ + double multiplier; + double one_on_log_multiplier; + /* minimum value seen */ + double min_seen; + /* maximum value seen */ + double max_seen; + /* maximum representable value */ + double max_possible; + /* number of buckets */ + size_t num_buckets; + /* the buckets themselves */ + gpr_uint32 *buckets; +}; + +/* determine a bucket index given a value - does no bounds checking */ +static size_t bucket_for_unchecked(gpr_histogram *h, double x) { + return (size_t)(log(x) * h->one_on_log_multiplier); +} + +/* bounds checked version of the above */ +static size_t bucket_for(gpr_histogram *h, double x) { + size_t bucket = bucket_for_unchecked(h, GPR_CLAMP(x, 0, h->max_possible)); + GPR_ASSERT(bucket >= 0); + GPR_ASSERT(bucket < h->num_buckets); + return bucket; +} + +/* at what value does a bucket start? */ +static double bucket_start(gpr_histogram *h, double x) { + return pow(h->multiplier, x); +} + +gpr_histogram *gpr_histogram_create(double resolution, + double max_bucket_start) { + gpr_histogram *h = gpr_malloc(sizeof(gpr_histogram)); + GPR_ASSERT(resolution > 0.0); + GPR_ASSERT(max_bucket_start > resolution); + h->sum = 0.0; + h->sum_of_squares = 0.0; + h->multiplier = 1.0 + resolution; + h->one_on_log_multiplier = 1.0 / log(1.0 + resolution); + h->max_possible = max_bucket_start; + h->count = 0.0; + h->min_seen = max_bucket_start; + h->max_seen = 0.0; + h->num_buckets = bucket_for_unchecked(h, max_bucket_start) + 1; + GPR_ASSERT(h->num_buckets > 1); + GPR_ASSERT(h->num_buckets < 100000000); + h->buckets = gpr_malloc(sizeof(gpr_uint32) * h->num_buckets); + memset(h->buckets, 0, sizeof(gpr_uint32) * h->num_buckets); + return h; +} + +void gpr_histogram_destroy(gpr_histogram *h) { + gpr_free(h->buckets); + gpr_free(h); +} + +void gpr_histogram_add(gpr_histogram *h, double x) { + h->sum += x; + h->sum_of_squares += x * x; + h->count++; + if (x < h->min_seen) { + h->min_seen = x; + } + if (x > h->max_seen) { + h->max_seen = x; + } + h->buckets[bucket_for(h, x)]++; +} + +int gpr_histogram_merge(gpr_histogram *dst, gpr_histogram *src) { + int i; + if ((dst->num_buckets != src->num_buckets) || + (dst->multiplier != src->multiplier)) { + /* Fail because these histograms don't match */ + return 0; + } + dst->sum += src->sum; + dst->sum_of_squares += src->sum_of_squares; + dst->count += src->count; + if (src->min_seen < dst->min_seen) { + dst->min_seen = src->min_seen; + } + if (src->max_seen > dst->max_seen) { + dst->max_seen = src->max_seen; + } + for (i = 0; i < dst->num_buckets; i++) { + dst->buckets[i] += src->buckets[i]; + } + return 1; +} + +static double threshold_for_count_below(gpr_histogram *h, double count_below) { + double count_so_far; + double lower_bound; + double upper_bound; + int lower_idx; + int upper_idx; + + GPR_ASSERT(h->count >= 1); + + if (count_below <= 0) { + return h->min_seen; + } + if (count_below >= h->count) { + return h->max_seen; + } + + /* find the lowest bucket that gets us above count_below */ + count_so_far = 0.0; + for (lower_idx = 0; lower_idx < h->num_buckets; lower_idx++) { + count_so_far += h->buckets[lower_idx]; + if (count_so_far >= count_below) { + break; + } + } + if (count_so_far == count_below) { + /* this bucket hits the threshold exactly... we should be midway through + any run of zero values following the bucket */ + for (upper_idx = lower_idx + 1; upper_idx < h->num_buckets; upper_idx++) { + if (h->buckets[upper_idx]) { + break; + } + } + return (bucket_start(h, lower_idx) + bucket_start(h, upper_idx)) / 2.0; + } else { + /* treat values as uniform throughout the bucket, and find where this value + should lie */ + lower_bound = bucket_start(h, lower_idx); + upper_bound = bucket_start(h, lower_idx + 1); + return GPR_CLAMP(upper_bound - + (upper_bound - lower_bound) * + (count_so_far - count_below) / + h->buckets[lower_idx], + h->min_seen, h->max_seen); + } +} + +double gpr_histogram_percentile(gpr_histogram *h, double percentile) { + return threshold_for_count_below(h, h->count * percentile / 100.0); +} + +double gpr_histogram_mean(gpr_histogram *h) { + GPR_ASSERT(h->count); + return h->sum / h->count; +} + +double gpr_histogram_stddev(gpr_histogram *h) { + return sqrt(gpr_histogram_variance(h)); +} + +double gpr_histogram_variance(gpr_histogram *h) { + if (h->count == 0) return 0.0; + return (h->sum_of_squares * h->count - h->sum * h->sum) / + (h->count * h->count); +} + +double gpr_histogram_maximum(gpr_histogram *h) { return h->max_seen; } + +double gpr_histogram_minimum(gpr_histogram *h) { return h->min_seen; } + +double gpr_histogram_count(gpr_histogram *h) { return h->count; } + +double gpr_histogram_sum(gpr_histogram *h) { return h->sum; } + +double gpr_histogram_sum_of_squares(gpr_histogram *h) { + return h->sum_of_squares; +} diff --git a/src/core/support/host_port.c b/src/core/support/host_port.c new file mode 100644 index 0000000000..02500551fc --- /dev/null +++ b/src/core/support/host_port.c @@ -0,0 +1,49 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <grpc/support/host_port.h> + +#include <string.h> + +#include <grpc/support/log.h> +#include <grpc/support/string.h> + +int gpr_join_host_port(char **out, const char *host, int port) { + if (host[0] != '[' && strchr(host, ':') != NULL) { + /* IPv6 literals must be enclosed in brackets. */ + return gpr_asprintf(out, "[%s]:%d", host, port); + } else { + /* Ordinary non-bracketed host:port. */ + return gpr_asprintf(out, "%s:%d", host, port); + } +} diff --git a/src/core/support/log.c b/src/core/support/log.c new file mode 100644 index 0000000000..79321f7ffe --- /dev/null +++ b/src/core/support/log.c @@ -0,0 +1,48 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <grpc/support/log.h> + +#include <stdio.h> + +const char *gpr_log_severity_string(gpr_log_severity severity) { + switch (severity) { + case GPR_LOG_SEVERITY_DEBUG: + return "D"; + case GPR_LOG_SEVERITY_INFO: + return "I"; + case GPR_LOG_SEVERITY_ERROR: + return "E"; + } + return "UNKNOWN"; +} diff --git a/src/core/support/log_android.c b/src/core/support/log_android.c new file mode 100644 index 0000000000..9e2b03471f --- /dev/null +++ b/src/core/support/log_android.c @@ -0,0 +1,86 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <grpc/support/port_platform.h> + +#ifdef GPR_ANDROID + +#include <grpc/support/log.h> +#include <grpc/support/time.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <android/log.h> + +static android_LogPriority severity_to_log_priority(gpr_log_severity severity) { + switch (severity) { + case GPR_LOG_SEVERITY_DEBUG: + return ANDROID_LOG_DEBUG; + case GPR_LOG_SEVERITY_INFO: + return ANDROID_LOG_INFO; + case GPR_LOG_SEVERITY_ERROR: + return ANDROID_LOG_ERROR; + } + return ANDROID_LOG_DEFAULT; +} + +void gpr_log(const char *file, int line, gpr_log_severity severity, + const char *format, ...) { + char *final_slash; + const char *display_file; + char *prefix = NULL; + char *suffix = NULL; + char *output = NULL; + va_list args; + va_start(args, format); + + final_slash = strrchr(file, '/'); + if (final_slash == NULL) + display_file = file; + else + display_file = final_slash + 1; + + asprintf(&prefix, "%s:%d] ", display_file, line); + vasprintf(&suffix, format, args); + asprintf(&output, "%s%s", prefix, suffix); + va_end(args); + + __android_log_write(severity_to_log_priority(severity), "GRPC", output); + + /* allocated by asprintf => use free, not gpr_free */ + free(prefix); + free(suffix); + free(output); +} + +#endif /* GPR_ANDROID */ diff --git a/src/core/support/log_linux.c b/src/core/support/log_linux.c new file mode 100644 index 0000000000..e39e2cc166 --- /dev/null +++ b/src/core/support/log_linux.c @@ -0,0 +1,85 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#define _POSIX_SOURCE +#define _GNU_SOURCE +#include <grpc/support/port_platform.h> + +#ifdef GPR_LINUX + +#include <grpc/support/log.h> +#include <grpc/support/time.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <time.h> +#include <linux/unistd.h> +#include <sys/syscall.h> +#include <unistd.h> + +static long gettid() { return syscall(__NR_gettid); } + +void gpr_log(const char *file, int line, gpr_log_severity severity, + const char *format, ...) { + char *final_slash; + const char *display_file; + char time_buffer[64]; + gpr_timespec now = gpr_now(); + struct tm tm; + va_list args; + va_start(args, format); + + final_slash = strrchr(file, '/'); + if (final_slash == NULL) + display_file = file; + else + display_file = final_slash + 1; + + if (!localtime_r(&now.tv_sec, &tm)) { + strcpy(time_buffer, "error:localtime"); + } else if (0 == + strftime(time_buffer, sizeof(time_buffer), "%m%d %H:%M:%S", &tm)) { + strcpy(time_buffer, "error:strftime"); + } + + flockfile(stderr); + fprintf(stderr, "%s%s.%09d %7ld %s:%d] ", gpr_log_severity_string(severity), + time_buffer, (int)(now.tv_nsec), gettid(), display_file, line); + vfprintf(stderr, format, args); + fputc('\n', stderr); + funlockfile(stderr); + + va_end(args); +} + +#endif diff --git a/src/core/support/log_posix.c b/src/core/support/log_posix.c new file mode 100644 index 0000000000..68882f7e89 --- /dev/null +++ b/src/core/support/log_posix.c @@ -0,0 +1,83 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#define _POSIX_SOURCE +#define _GNU_SOURCE +#include <grpc/support/port_platform.h> + +#if defined(GPR_POSIX_LOG) + +#include <grpc/support/log.h> +#include <grpc/support/time.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <time.h> +#include <pthread.h> + +static long gettid() { return pthread_self(); } + +void gpr_log(const char *file, int line, gpr_log_severity severity, + const char *format, ...) { + char *final_slash; + const char *display_file; + char time_buffer[64]; + gpr_timespec now = gpr_now(); + struct tm tm; + va_list args; + va_start(args, format); + + final_slash = strrchr(file, '/'); + if (final_slash == NULL) + display_file = file; + else + display_file = final_slash + 1; + + if (!localtime_r(&now.tv_sec, &tm)) { + strcpy(time_buffer, "error:localtime"); + } else if (0 == + strftime(time_buffer, sizeof(time_buffer), "%m%d %H:%M:%S", &tm)) { + strcpy(time_buffer, "error:strftime"); + } + + flockfile(stderr); + fprintf(stderr, "%s%s.%09d %7ld %s:%d] ", gpr_log_severity_string(severity), + time_buffer, (int)(now.tv_nsec), gettid(), display_file, line); + vfprintf(stderr, format, args); + fputc('\n', stderr); + funlockfile(stderr); + + va_end(args); +} + +#endif /* defined(GPR_POSIX_LOG) */ diff --git a/src/core/support/log_win32.c b/src/core/support/log_win32.c new file mode 100644 index 0000000000..f5710fa179 --- /dev/null +++ b/src/core/support/log_win32.c @@ -0,0 +1,55 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <grpc/support/port_platform.h> + +#ifdef GPR_WIN32 + +#include <grpc/support/log.h> +#include <stdio.h> +#include <stdarg.h> + +/* Simple starter implementation */ +void gpr_log(char *file, int line, gpr_log_severity severity, char *format, + ...) { + va_list args; + va_start(args, format); + + fprintf(stderr, "%s %s:%d: ", gpr_log_severity_string(severity), file, line); + vfprintf(stderr, format, args); + fputc('\n', stderr); + + va_end(args); +} + +#endif diff --git a/src/core/support/murmur_hash.c b/src/core/support/murmur_hash.c new file mode 100644 index 0000000000..5d30263e52 --- /dev/null +++ b/src/core/support/murmur_hash.c @@ -0,0 +1,94 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/support/murmur_hash.h" + +#define ROTL32(x, r) ((x) << (r)) | ((x) >> (32 - (r))) + +#define FMIX32(h) \ + (h) ^= (h) >> 16; \ + (h) *= 0x85ebca6b; \ + (h) ^= (h) >> 13; \ + (h) *= 0xc2b2ae35; \ + (h) ^= (h) >> 16; + +/* Block read - if your platform needs to do endian-swapping or can only + handle aligned reads, do the conversion here */ +#define GETBLOCK32(p, i) (p)[(i)] + +gpr_uint32 gpr_murmur_hash3(const void* key, size_t len, gpr_uint32 seed) { + const gpr_uint8* data = (const gpr_uint8*)key; + const int nblocks = len / 4; + int i; + + gpr_uint32 h1 = seed; + gpr_uint32 k1 = 0; + + const gpr_uint32 c1 = 0xcc9e2d51; + const gpr_uint32 c2 = 0x1b873593; + + const gpr_uint32* blocks = (const uint32_t*)(data + nblocks * 4); + const uint8_t* tail = (const uint8_t*)(data + nblocks * 4); + + /* body */ + for (i = -nblocks; i; i++) { + gpr_uint32 k1 = GETBLOCK32(blocks, i); + + k1 *= c1; + k1 = ROTL32(k1, 15); + k1 *= c2; + + h1 ^= k1; + h1 = ROTL32(h1, 13); + h1 = h1 * 5 + 0xe6546b64; + } + + /* tail */ + switch (len & 3) { + case 3: + k1 ^= tail[2] << 16; + case 2: + k1 ^= tail[1] << 8; + case 1: + k1 ^= tail[0]; + k1 *= c1; + k1 = ROTL32(k1, 15); + k1 *= c2; + h1 ^= k1; + }; + + /* finalization */ + h1 ^= len; + FMIX32(h1); + return h1; +} diff --git a/src/core/support/murmur_hash.h b/src/core/support/murmur_hash.h new file mode 100644 index 0000000000..5643717cd2 --- /dev/null +++ b/src/core/support/murmur_hash.h @@ -0,0 +1,44 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __GRPC_INTERNAL_SUPPORT_MURMUR_HASH_H__ +#define __GRPC_INTERNAL_SUPPORT_MURMUR_HASH_H__ + +#include <grpc/support/port_platform.h> + +#include <stddef.h> + +/* compute the hash of key (length len) */ +gpr_uint32 gpr_murmur_hash3(const void *key, size_t len, gpr_uint32 seed); + +#endif /* __GRPC_INTERNAL_SUPPORT_MURMUR_HASH_H__ */ diff --git a/src/core/support/slice.c b/src/core/support/slice.c new file mode 100644 index 0000000000..fcdeb478fb --- /dev/null +++ b/src/core/support/slice.c @@ -0,0 +1,325 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> +#include <grpc/support/slice.h> + +#include <string.h> + +gpr_slice gpr_empty_slice() { + gpr_slice out; + out.refcount = 0; + out.data.inlined.length = 0; + return out; +} + +gpr_slice gpr_slice_ref(gpr_slice slice) { + if (slice.refcount) { + slice.refcount->ref(slice.refcount); + } + return slice; +} + +void gpr_slice_unref(gpr_slice slice) { + if (slice.refcount) { + slice.refcount->unref(slice.refcount); + } +} + +/* gpr_slice_new support structures - we create a refcount object extended + with the user provided data pointer & destroy function */ +typedef struct new_slice_refcount { + gpr_slice_refcount rc; + gpr_refcount refs; + void (*user_destroy)(void *); + void *user_data; +} new_slice_refcount; + +static void new_slice_ref(void *p) { + new_slice_refcount *r = p; + gpr_ref(&r->refs); +} + +static void new_slice_unref(void *p) { + new_slice_refcount *r = p; + if (gpr_unref(&r->refs)) { + r->user_destroy(r->user_data); + gpr_free(r); + } +} + +gpr_slice gpr_slice_new(void *p, size_t len, void (*destroy)(void *)) { + gpr_slice slice; + new_slice_refcount *rc = gpr_malloc(sizeof(new_slice_refcount)); + gpr_ref_init(&rc->refs, 1); + rc->rc.ref = new_slice_ref; + rc->rc.unref = new_slice_unref; + rc->user_destroy = destroy; + rc->user_data = p; + + slice.refcount = &rc->rc; + slice.data.refcounted.bytes = p; + slice.data.refcounted.length = len; + return slice; +} + +/* gpr_slice_new_with_len support structures - we create a refcount object + extended with the user provided data pointer & destroy function */ +typedef struct new_with_len_slice_refcount { + gpr_slice_refcount rc; + gpr_refcount refs; + void *user_data; + size_t user_length; + void (*user_destroy)(void *, size_t); +} new_with_len_slice_refcount; + +static void new_with_len_ref(void *p) { + new_with_len_slice_refcount *r = p; + gpr_ref(&r->refs); +} + +static void new_with_len_unref(void *p) { + new_with_len_slice_refcount *r = p; + if (gpr_unref(&r->refs)) { + r->user_destroy(r->user_data, r->user_length); + gpr_free(r); + } +} + +gpr_slice gpr_slice_new_with_len(void *p, size_t len, + void (*destroy)(void *, size_t)) { + gpr_slice slice; + new_with_len_slice_refcount *rc = + gpr_malloc(sizeof(new_with_len_slice_refcount)); + gpr_ref_init(&rc->refs, 1); + rc->rc.ref = new_with_len_ref; + rc->rc.unref = new_with_len_unref; + rc->user_destroy = destroy; + rc->user_data = p; + rc->user_length = len; + + slice.refcount = &rc->rc; + slice.data.refcounted.bytes = p; + slice.data.refcounted.length = len; + return slice; +} + +gpr_slice gpr_slice_from_copied_buffer(const char *source, size_t length) { + gpr_slice slice = gpr_slice_malloc(length); + memcpy(GPR_SLICE_START_PTR(slice), source, length); + return slice; +} + +gpr_slice gpr_slice_from_copied_string(const char *source) { + return gpr_slice_from_copied_buffer(source, strlen(source)); +} + +typedef struct { + gpr_slice_refcount base; + gpr_refcount refs; +} malloc_refcount; + +static void malloc_ref(void *p) { + malloc_refcount *r = p; + gpr_ref(&r->refs); +} + +static void malloc_unref(void *p) { + malloc_refcount *r = p; + if (gpr_unref(&r->refs)) { + gpr_free(r); + } +} + +gpr_slice gpr_slice_malloc(size_t length) { + gpr_slice slice; + + if (length > sizeof(slice.data.inlined.bytes)) { + /* Memory layout used by the slice created here: + + +-----------+----------------------------------------------------------+ + | refcount | bytes | + +-----------+----------------------------------------------------------+ + + refcount is a malloc_refcount + bytes is an array of bytes of the requested length + Both parts are placed in the same allocation returned from gpr_malloc */ + malloc_refcount *rc = gpr_malloc(sizeof(malloc_refcount) + length); + + /* Initial refcount on rc is 1 - and it's up to the caller to release + this reference. */ + gpr_ref_init(&rc->refs, 1); + + rc->base.ref = malloc_ref; + rc->base.unref = malloc_unref; + + /* Build up the slice to be returned. */ + /* The slices refcount points back to the allocated block. */ + slice.refcount = &rc->base; + /* The data bytes are placed immediately after the refcount struct */ + slice.data.refcounted.bytes = (gpr_uint8 *)(rc + 1); + /* And the length of the block is set to the requested length */ + slice.data.refcounted.length = length; + } else { + /* small slice: just inline the data */ + slice.refcount = NULL; + slice.data.inlined.length = length; + } + return slice; +} + +gpr_slice gpr_slice_sub_no_ref(gpr_slice source, size_t begin, size_t end) { + gpr_slice subset; + + if (source.refcount) { + /* Enforce preconditions */ + GPR_ASSERT(source.data.refcounted.length >= begin); + GPR_ASSERT(source.data.refcounted.length >= end); + GPR_ASSERT(end >= begin); + + /* Build the result */ + subset.refcount = source.refcount; + /* Point into the source array */ + subset.data.refcounted.bytes = source.data.refcounted.bytes + begin; + subset.data.refcounted.length = end - begin; + } else { + subset.refcount = NULL; + subset.data.inlined.length = end - begin; + memcpy(subset.data.inlined.bytes, source.data.inlined.bytes + begin, + end - begin); + } + return subset; +} + +gpr_slice gpr_slice_sub(gpr_slice source, size_t begin, size_t end) { + gpr_slice subset; + + if (end - begin <= sizeof(subset.data.inlined.bytes)) { + subset.refcount = NULL; + subset.data.inlined.length = end - begin; + memcpy(subset.data.inlined.bytes, GPR_SLICE_START_PTR(source) + begin, + end - begin); + } else { + subset = gpr_slice_sub_no_ref(source, begin, end); + /* Bump the refcount */ + subset.refcount->ref(subset.refcount); + } + return subset; +} + +gpr_slice gpr_slice_split_tail(gpr_slice *source, size_t split) { + gpr_slice tail; + + if (source->refcount == NULL) { + /* inlined data, copy it out */ + GPR_ASSERT(source->data.inlined.length >= split); + tail.refcount = NULL; + tail.data.inlined.length = source->data.inlined.length - split; + memcpy(tail.data.inlined.bytes, source->data.inlined.bytes + split, + tail.data.inlined.length); + source->data.inlined.length = split; + } else { + size_t tail_length = source->data.refcounted.length - split; + GPR_ASSERT(source->data.refcounted.length >= split); + if (tail_length < sizeof(tail.data.inlined.bytes)) { + /* Copy out the bytes - it'll be cheaper than refcounting */ + tail.refcount = NULL; + tail.data.inlined.length = tail_length; + memcpy(tail.data.inlined.bytes, source->data.refcounted.bytes + split, + tail_length); + } else { + /* Build the result */ + tail.refcount = source->refcount; + /* Bump the refcount */ + tail.refcount->ref(tail.refcount); + /* Point into the source array */ + tail.data.refcounted.bytes = source->data.refcounted.bytes + split; + tail.data.refcounted.length = tail_length; + } + source->data.refcounted.length = split; + } + + return tail; +} + +gpr_slice gpr_slice_split_head(gpr_slice *source, size_t split) { + gpr_slice head; + + if (source->refcount == NULL) { + GPR_ASSERT(source->data.inlined.length >= split); + + head.refcount = NULL; + head.data.inlined.length = split; + memcpy(head.data.inlined.bytes, source->data.inlined.bytes, split); + source->data.inlined.length -= split; + memmove(source->data.inlined.bytes, source->data.inlined.bytes + split, + source->data.inlined.length); + } else if (split < sizeof(head.data.inlined.bytes)) { + GPR_ASSERT(source->data.refcounted.length >= split); + + head.refcount = NULL; + head.data.inlined.length = split; + memcpy(head.data.inlined.bytes, source->data.refcounted.bytes, split); + source->data.refcounted.bytes += split; + source->data.refcounted.length -= split; + } else { + GPR_ASSERT(source->data.refcounted.length >= split); + + /* Build the result */ + head.refcount = source->refcount; + /* Bump the refcount */ + head.refcount->ref(head.refcount); + /* Point into the source array */ + head.data.refcounted.bytes = source->data.refcounted.bytes; + head.data.refcounted.length = split; + source->data.refcounted.bytes += split; + source->data.refcounted.length -= split; + } + + return head; +} + +int gpr_slice_cmp(gpr_slice a, gpr_slice b) { + int d = GPR_SLICE_LENGTH(a) - GPR_SLICE_LENGTH(b); + if (d != 0) return d; + return memcmp(GPR_SLICE_START_PTR(a), GPR_SLICE_START_PTR(b), + GPR_SLICE_LENGTH(a)); +} + +int gpr_slice_str_cmp(gpr_slice a, const char *b) { + size_t b_length = strlen(b); + int d = GPR_SLICE_LENGTH(a) - b_length; + if (d != 0) return d; + return memcmp(GPR_SLICE_START_PTR(a), b, b_length); +} diff --git a/src/core/support/slice_buffer.c b/src/core/support/slice_buffer.c new file mode 100644 index 0000000000..2ade049c89 --- /dev/null +++ b/src/core/support/slice_buffer.c @@ -0,0 +1,155 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <grpc/support/slice_buffer.h> + +#include <string.h> + +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> + +/* initial allocation size (# of slices) */ +#define INITIAL_CAPACITY 4 +/* grow a buffer; requires INITIAL_CAPACITY > 1 */ +#define GROW(x) (3 * (x) / 2) + +void gpr_slice_buffer_init(gpr_slice_buffer *sb) { + sb->count = 0; + sb->length = 0; + sb->capacity = INITIAL_CAPACITY; + sb->slices = gpr_malloc(sizeof(gpr_slice) * INITIAL_CAPACITY); +} + +void gpr_slice_buffer_destroy(gpr_slice_buffer *sb) { + gpr_slice_buffer_reset_and_unref(sb); + gpr_free(sb->slices); +} + +gpr_uint8 *gpr_slice_buffer_tiny_add(gpr_slice_buffer *sb, int n) { + gpr_slice *back; + gpr_uint8 *out; + + sb->length += n; + + if (sb->count == 0) goto add_new; + back = &sb->slices[sb->count - 1]; + if (back->refcount) goto add_new; + if (back->data.inlined.length + n > sizeof(back->data.inlined.bytes)) + goto add_new; + out = back->data.inlined.bytes + back->data.inlined.length; + back->data.inlined.length += n; + return out; + +add_new: + if (sb->count == sb->capacity) { + sb->capacity = GROW(sb->capacity); + GPR_ASSERT(sb->capacity > sb->count); + sb->slices = gpr_realloc(sb->slices, sb->capacity * sizeof(gpr_slice)); + } + back = &sb->slices[sb->count]; + sb->count++; + back->refcount = NULL; + back->data.inlined.length = n; + return back->data.inlined.bytes; +} + +size_t gpr_slice_buffer_add_indexed(gpr_slice_buffer *sb, gpr_slice s) { + size_t out = sb->count; + if (out == sb->capacity) { + sb->capacity = GROW(sb->capacity); + GPR_ASSERT(sb->capacity > sb->count); + sb->slices = gpr_realloc(sb->slices, sb->capacity * sizeof(gpr_slice)); + } + sb->slices[out] = s; + sb->length += GPR_SLICE_LENGTH(s); + sb->count = out + 1; + return out; +} + +void gpr_slice_buffer_add(gpr_slice_buffer *sb, gpr_slice s) { + size_t n = sb->count; + /* if both the last slice in the slice buffer and the slice being added + are inlined (that is, that they carry their data inside the slice data + structure), and the back slice is not full, then concatenate directly + into the back slice, preventing many small slices being passed into + writes */ + if (!s.refcount && n) { + gpr_slice *back = &sb->slices[n - 1]; + if (!back->refcount && back->data.inlined.length < GPR_SLICE_INLINED_SIZE) { + if (s.data.inlined.length + back->data.inlined.length <= + GPR_SLICE_INLINED_SIZE) { + memcpy(back->data.inlined.bytes + back->data.inlined.length, + s.data.inlined.bytes, s.data.inlined.length); + back->data.inlined.length += s.data.inlined.length; + } else { + size_t cp1 = GPR_SLICE_INLINED_SIZE - back->data.inlined.length; + memcpy(back->data.inlined.bytes + back->data.inlined.length, + s.data.inlined.bytes, cp1); + back->data.inlined.length = GPR_SLICE_INLINED_SIZE; + if (n == sb->capacity) { + sb->capacity = GROW(sb->capacity); + GPR_ASSERT(sb->capacity > sb->count); + sb->slices = + gpr_realloc(sb->slices, sb->capacity * sizeof(gpr_slice)); + } + back = &sb->slices[n]; + sb->count = n + 1; + back->refcount = NULL; + back->data.inlined.length = s.data.inlined.length - cp1; + memcpy(back->data.inlined.bytes, s.data.inlined.bytes + cp1, + s.data.inlined.length - cp1); + } + sb->length += s.data.inlined.length; + return; /* early out */ + } + } + gpr_slice_buffer_add_indexed(sb, s); +} + +void gpr_slice_buffer_addn(gpr_slice_buffer *sb, gpr_slice *s, size_t n) { + size_t i; + for (i = 0; i < n; i++) { + gpr_slice_buffer_add(sb, s[i]); + } +} + +void gpr_slice_buffer_reset_and_unref(gpr_slice_buffer *sb) { + size_t i; + + for (i = 0; i < sb->count; i++) { + gpr_slice_unref(sb->slices[i]); + } + + sb->count = 0; + sb->length = 0; +} diff --git a/src/core/support/string.c b/src/core/support/string.c new file mode 100644 index 0000000000..b1f0795846 --- /dev/null +++ b/src/core/support/string.c @@ -0,0 +1,124 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <grpc/support/string.h> + +#include <ctype.h> +#include <stddef.h> +#include <string.h> + +#include <grpc/support/alloc.h> +#include <grpc/support/port_platform.h> +#include <grpc/support/useful.h> + +char *gpr_strdup(const char *src) { + char *dst; + size_t len; + + if (!src) { + return NULL; + } + + len = strlen(src) + 1; + dst = gpr_malloc(len); + + memcpy(dst, src, len); + + return dst; +} + +typedef struct { + size_t capacity; + size_t length; + char *data; +} hexout; + +static hexout hexout_create() { + hexout r = {0, 0, NULL}; + return r; +} + +static void hexout_append(hexout *out, char c) { + if (out->length == out->capacity) { + out->capacity = GPR_MAX(8, 2 * out->capacity); + out->data = gpr_realloc(out->data, out->capacity); + } + out->data[out->length++] = c; +} + +char *gpr_hexdump(const char *buf, size_t len, gpr_uint32 flags) { + static const char hex[16] = "0123456789abcdef"; + hexout out = hexout_create(); + + const gpr_uint8 *const beg = (const gpr_uint8 *)buf; + const gpr_uint8 *const end = beg + len; + const gpr_uint8 *cur; + + for (cur = beg; cur != end; ++cur) { + if (cur != beg) hexout_append(&out, ' '); + hexout_append(&out, hex[*cur >> 4]); + hexout_append(&out, hex[*cur & 0xf]); + } + + if (flags & GPR_HEXDUMP_PLAINTEXT) { + cur = beg; + if (len) hexout_append(&out, ' '); + hexout_append(&out, '\''); + for (cur = beg; cur != end; ++cur) { + hexout_append(&out, isprint(*cur) ? *cur : '.'); + } + hexout_append(&out, '\''); + } + + hexout_append(&out, 0); + + return out.data; +} + +int gpr_parse_bytes_to_uint32(const char *buf, size_t len, gpr_uint32 *result) { + gpr_uint32 out = 0; + gpr_uint32 new; + size_t i; + + if (len == 0) return 0; /* must have some bytes */ + + for (i = 0; i < len; i++) { + if (buf[i] < '0' || buf[i] > '9') return 0; /* bad char */ + new = 10 * out + (buf[i] - '0'); + if (new < out) return 0; /* overflow */ + out = new; + } + + *result = out; + return 1; +} diff --git a/src/core/support/string_posix.c b/src/core/support/string_posix.c new file mode 100644 index 0000000000..d1da37923f --- /dev/null +++ b/src/core/support/string_posix.c @@ -0,0 +1,86 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* Posix code for gpr snprintf support. */ + +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200112L +#endif + +#include <stdio.h> +#include <stdarg.h> +#include <string.h> + +#include <grpc/support/alloc.h> + +int gpr_asprintf(char **strp, const char *format, ...) { + va_list args; + int ret; + char buf[64]; + size_t strp_buflen; + + /* Use a constant-sized buffer to determine the length. */ + va_start(args, format); + ret = vsnprintf(buf, sizeof(buf), format, args); + va_end(args); + if (!(0 <= ret && ret < ~(size_t)0)) { + *strp = NULL; + return -1; + } + + /* Allocate a new buffer, with space for the NUL terminator. */ + strp_buflen = (size_t)ret + 1; + if ((*strp = gpr_malloc(strp_buflen)) == NULL) { + /* This shouldn't happen, because gpr_malloc() calls abort(). */ + return -1; + } + + /* Return early if we have all the bytes. */ + if (strp_buflen <= sizeof(buf)) { + memcpy(*strp, buf, strp_buflen); + return ret; + } + + /* Try again using the larger buffer. */ + va_start(args, format); + ret = vsnprintf(*strp, strp_buflen, format, args); + va_end(args); + if (ret == strp_buflen - 1) { + return ret; + } + + /* This should never happen. */ + gpr_free(*strp); + *strp = NULL; + return -1; +} diff --git a/src/core/support/sync.c b/src/core/support/sync.c new file mode 100644 index 0000000000..40e5465e5d --- /dev/null +++ b/src/core/support/sync.c @@ -0,0 +1,135 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* Generic implementation of synchronization primitives. */ + +#include <grpc/support/log.h> +#include <grpc/support/sync.h> +#include <grpc/support/atm.h> + +/* Number of mutexes to allocate for events, to avoid lock contention. + Should be a prime. */ +enum { event_sync_partitions = 31 }; + +/* Event are partitioned by address to avoid lock contention. */ +static struct sync_array_s { + gpr_mu mu; + gpr_cv cv; +} sync_array[event_sync_partitions]; + +/* This routine is executed once on first use, via event_once */ +static gpr_once event_once = GPR_ONCE_INIT; +static void event_initialize(void) { + int i; + for (i = 0; i != event_sync_partitions; i++) { + gpr_mu_init(&sync_array[i].mu); + gpr_cv_init(&sync_array[i].cv); + } +} + +/* Hash ev into an element of sync_array[]. */ +static struct sync_array_s *hash(gpr_event *ev) { + return &sync_array[((gpr_uintptr)ev) % event_sync_partitions]; +} + +void gpr_event_init(gpr_event *ev) { + gpr_once_init(&event_once, &event_initialize); + ev->state = 0; +} + +void gpr_event_set(gpr_event *ev, void *value) { + struct sync_array_s *s = hash(ev); + gpr_mu_lock(&s->mu); + GPR_ASSERT(gpr_atm_acq_load(&ev->state) == 0); + GPR_ASSERT(value != NULL); + gpr_atm_rel_store(&ev->state, (gpr_atm)value); + gpr_cv_broadcast(&s->cv); + gpr_mu_unlock(&s->mu); +} + +void *gpr_event_get(gpr_event *ev) { + return (void *)gpr_atm_acq_load(&ev->state); +} + +void *gpr_event_wait(gpr_event *ev, gpr_timespec abs_deadline) { + void *result = (void *)gpr_atm_acq_load(&ev->state); + if (result == NULL) { + struct sync_array_s *s = hash(ev); + gpr_mu_lock(&s->mu); + do { + result = (void *)gpr_atm_acq_load(&ev->state); + } while (result == NULL && !gpr_cv_wait(&s->cv, &s->mu, abs_deadline)); + gpr_mu_unlock(&s->mu); + } + return result; +} + +void *gpr_event_cancellable_wait(gpr_event *ev, gpr_timespec abs_deadline, + gpr_cancellable *c) { + void *result = (void *)gpr_atm_acq_load(&ev->state); + if (result == NULL) { + struct sync_array_s *s = hash(ev); + gpr_mu_lock(&s->mu); + do { + result = (void *)gpr_atm_acq_load(&ev->state); + } while (result == NULL && + !gpr_cv_cancellable_wait(&s->cv, &s->mu, abs_deadline, c)); + gpr_mu_unlock(&s->mu); + } + return result; +} + +void gpr_ref_init(gpr_refcount *r, int n) { gpr_atm_rel_store(&r->count, n); } + +void gpr_ref(gpr_refcount *r) { gpr_atm_no_barrier_fetch_add(&r->count, 1); } + +void gpr_refn(gpr_refcount *r, int n) { + gpr_atm_no_barrier_fetch_add(&r->count, n); +} + +int gpr_unref(gpr_refcount *r) { + return gpr_atm_full_fetch_add(&r->count, -1) == 1; +} + +void gpr_stats_init(gpr_stats_counter *c, gpr_intptr n) { + gpr_atm_rel_store(&c->value, n); +} + +void gpr_stats_inc(gpr_stats_counter *c, gpr_intptr inc) { + gpr_atm_no_barrier_fetch_add(&c->value, inc); +} + +gpr_intptr gpr_stats_read(const gpr_stats_counter *c) { + /* don't need acquire-load, but we have no no-barrier load yet */ + return gpr_atm_acq_load(&c->value); +} diff --git a/src/core/support/sync_posix.c b/src/core/support/sync_posix.c new file mode 100644 index 0000000000..257a7fbf4e --- /dev/null +++ b/src/core/support/sync_posix.c @@ -0,0 +1,82 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* Posix gpr synchroization support code. */ + +#include <errno.h> +#include <grpc/support/log.h> +#include <grpc/support/sync.h> +#include <grpc/support/time.h> + +void gpr_mu_init(gpr_mu *mu) { GPR_ASSERT(pthread_mutex_init(mu, NULL) == 0); } + +void gpr_mu_destroy(gpr_mu *mu) { GPR_ASSERT(pthread_mutex_destroy(mu) == 0); } + +void gpr_mu_lock(gpr_mu *mu) { GPR_ASSERT(pthread_mutex_lock(mu) == 0); } + +void gpr_mu_unlock(gpr_mu *mu) { GPR_ASSERT(pthread_mutex_unlock(mu) == 0); } + +int gpr_mu_trylock(gpr_mu *mu) { + int err = pthread_mutex_trylock(mu); + GPR_ASSERT(err == 0 || err == EBUSY); + return err == 0; +} + +/*----------------------------------------*/ + +void gpr_cv_init(gpr_cv *cv) { GPR_ASSERT(pthread_cond_init(cv, NULL) == 0); } + +void gpr_cv_destroy(gpr_cv *cv) { GPR_ASSERT(pthread_cond_destroy(cv) == 0); } + +int gpr_cv_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline) { + int err = 0; + if (gpr_time_cmp(abs_deadline, gpr_inf_future) == 0) { + err = pthread_cond_wait(cv, mu); + } else { + err = pthread_cond_timedwait(cv, mu, &abs_deadline); + } + GPR_ASSERT(err == 0 || err == ETIMEDOUT || err == EAGAIN); + return err == ETIMEDOUT; +} + +void gpr_cv_signal(gpr_cv *cv) { GPR_ASSERT(pthread_cond_signal(cv) == 0); } + +void gpr_cv_broadcast(gpr_cv *cv) { + GPR_ASSERT(pthread_cond_broadcast(cv) == 0); +} + +/*----------------------------------------*/ + +void gpr_once_init(gpr_once *once, void (*init_function)(void)) { + GPR_ASSERT(pthread_once(once, init_function) == 0); +} diff --git a/src/core/support/sync_win32.c b/src/core/support/sync_win32.c new file mode 100644 index 0000000000..63dd4eb708 --- /dev/null +++ b/src/core/support/sync_win32.c @@ -0,0 +1,120 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* Win32 code for gpr synchronization support. */ + +#define _WIN32_WINNT 0x0600 +#include <windows.h> +#include <grpc/support/log.h> +#include <grpc/support/sync.h> +#include <grpc/support/time.h> + +void gpr_mu_init(gpr_mu *mu) { + InitializeCriticalSection(&mu->cs); + mu->locked = 0; +} + +void gpr_mu_destroy(gpr_mu *mu) { DeleteCriticalSection(&mu->cs); } + +void gpr_mu_lock(gpr_mu *mu) { + EnterCriticalSection(&mu->cs); + GPR_ASSERT(!mu->locked); + mu->locked = 1; +} + +void gpr_mu_unlock(gpr_mu *mu) { + mu->locked = 0; + LeaveCriticalSection(&mu->cs); +} + +int gpr_mu_trylock(gpr_mu *mu) { + int result = TryEnterCriticalSection(&mu->cs); + if (result) { + if (mu->locked) { /* This thread already holds the lock. */ + LeaveCriticalSection(&mu->cs); /* Decrement lock count. */ + result = 0; /* Indicate failure */ + } + mu->locked = 1; + } + return result; +} + +/*----------------------------------------*/ + +void gpr_cv_init(gpr_cv *cv) { InitializeConditionVariable(cv); } + +void gpr_cv_destroy(gpr_cv *cv) { + /* Condition variables don't need destruction in Win32. */ +} + +int gpr_cv_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline) { + int timeout = 0; + if (gpr_time_cmp(abs_deadline, gpr_inf_future) == 0) { + SleepConditionVariableCS(cv, &mu->cs, INFINITE); + } else { + gpr_timespec now = gpr_now(); + gpr_int64 now_ms = now.tv_sec * 1000 + now.tv_nsec / 1000000; + gpr_int64 deadline_ms = + abs_deadline.tv_sec * 1000 + abs_deadline.tv_nsec / 1000000; + if (now_ms >= deadline_ms) { + timeout = 1; + } else { + timeout = + (SleepConditionVariableCS(cv, &mu->cs, deadline_ms - now_ms) == 0 && + GetLastError() == ERROR_TIMEOUT); + } + } + return timeout; +} + +void gpr_cv_signal(gpr_cv *cv) { WakeConditionVariable(cv); } + +void gpr_cv_broadcast(gpr_cv *cv) { WakeAllConditionVariable(cv); } + +/*----------------------------------------*/ + +static void *dummy; +struct run_once_func_arg { + void (*init_function)(void); +}; +static int run_once_func(gpr_once *once, void *v, void **pv) { + struct run_once_func_arg *arg = v; + (*arg->init_function)(); + return 1; +} + +void gpr_once_init(gpr_once *once, void (*init_function)(void)) { + struct run_once_func_arg arg; + arg.init_function = init_function; + InitOnceExecuteOnce(once, &run_once_func, &arg, &dummy); +} diff --git a/src/core/support/thd_internal.h b/src/core/support/thd_internal.h new file mode 100644 index 0000000000..519177a555 --- /dev/null +++ b/src/core/support/thd_internal.h @@ -0,0 +1,39 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __GRPC_INTERNAL_SUPPORT_THD_INTERNAL_H__ +#define __GRPC_INTERNAL_SUPPORT_THD_INTERNAL_H__ + +/* Internal interfaces between modules within the gpr support library. */ + +#endif /* __GRPC_INTERNAL_SUPPORT_THD_INTERNAL_H__ */ diff --git a/src/core/support/thd_posix.c b/src/core/support/thd_posix.c new file mode 100644 index 0000000000..c86eea415d --- /dev/null +++ b/src/core/support/thd_posix.c @@ -0,0 +1,78 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* Posix implementation for gpr threads. */ + +#include <pthread.h> +#include <stdlib.h> +#include <string.h> +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> +#include <grpc/support/thd.h> + +struct thd_arg { + void (*body)(void *arg); /* body of a thread */ + void *arg; /* argument to a thread */ +}; + +/* Body of every thread started via gpr_thd_new. */ +static void *thread_body(void *v) { + struct thd_arg a = *(struct thd_arg *)v; + gpr_free(v); + (*a.body)(a.arg); + return NULL; +} + +int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg, + const gpr_thd_options *options) { + int thread_started; + pthread_attr_t attr; + struct thd_arg *a = gpr_malloc(sizeof(*a)); + a->body = thd_body; + a->arg = arg; + + GPR_ASSERT(pthread_attr_init(&attr) == 0); + GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) == 0); + thread_started = (pthread_create(t, &attr, &thread_body, a) == 0); + GPR_ASSERT(pthread_attr_destroy(&attr) == 0); + if (!thread_started) { + gpr_free(a); + } + return thread_started; +} + +gpr_thd_options gpr_thd_options_default(void) { + gpr_thd_options options; + memset(&options, 0, sizeof(options)); + return options; +} diff --git a/src/core/support/thd_win32.c b/src/core/support/thd_win32.c new file mode 100644 index 0000000000..8440479520 --- /dev/null +++ b/src/core/support/thd_win32.c @@ -0,0 +1,80 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* Posix implementation for gpr threads. */ + +#include <grpc/support/port_platform.h> + +#ifdef GPR_WIN32 + +#include <windows.h> +#include <string.h> +#include <grpc/support/alloc.h> +#include <grpc/support/thd.h> + +struct thd_arg { + void (*body)(void *arg); /* body of a thread */ + void *arg; /* argument to a thread */ +}; + +/* Body of every thread started via gpr_thd_new. */ +static DWORD thread_body(void *v) { + struct thd_arg a = *(struct thd_arg *)v; + gpr_free(v); + (*a.body)(a.arg); + return 0; +} + +int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg, + const gpr_thd_options *options) { + HANDLE handle; + struct thd_arg *a = gpr_malloc(sizeof(*a)); + a->body = thd_body; + a->arg = arg; + *t = 0; + handle = CreateThread(NULL, 64 * 1024, &thread_body, a, 0, NULL); + if (handle == NULL) { + gpr_free(a); + } else { + CloseHandle(handle); /* threads are "detached" */ + } + return handle != NULL; +} + +gpr_thd_options gpr_thd_options_default(void) { + gpr_thd_options options; + memset(&options, 0, sizeof(options)); + return options; +} + +#endif /* GPR_WIN32 */ diff --git a/src/core/support/time.c b/src/core/support/time.c new file mode 100644 index 0000000000..1d8765f8cc --- /dev/null +++ b/src/core/support/time.c @@ -0,0 +1,243 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* Generic implementation of time calls. */ + +#include <grpc/support/time.h> +#include <limits.h> +#include <stdio.h> +#include <string.h> +#include <grpc/support/log.h> + +int gpr_time_cmp(gpr_timespec a, gpr_timespec b) { + int cmp = (a.tv_sec > b.tv_sec) - (a.tv_sec < b.tv_sec); + if (cmp == 0) { + cmp = (a.tv_nsec > b.tv_nsec) - (a.tv_nsec < b.tv_nsec); + } + return cmp; +} + +/* There's no standard TIME_T_MIN and TIME_T_MAX, so we construct them. The + following assumes that signed types are two's-complement and that bytes are + 8 bits. */ + +/* The top bit of integral type t. */ +#define TOP_BIT_OF_TYPE(t) (((gpr_uintmax)1) << ((8 * sizeof(t)) - 1)) + +/* Return whether integral type t is signed. */ +#define TYPE_IS_SIGNED(t) (((t)1) > (t) ~(t)0) + +/* The minimum and maximum value of integral type t. */ +#define TYPE_MIN(t) ((t)(TYPE_IS_SIGNED(t) ? TOP_BIT_OF_TYPE(t) : 0)) +#define TYPE_MAX(t) \ + ((t)(TYPE_IS_SIGNED(t) ? (TOP_BIT_OF_TYPE(t) - 1) \ + : ((TOP_BIT_OF_TYPE(t) - 1) << 1) + 1)) + +const gpr_timespec gpr_time_0 = {0, 0}; +const gpr_timespec gpr_inf_future = {TYPE_MAX(time_t), 0}; +const gpr_timespec gpr_inf_past = {TYPE_MIN(time_t), 0}; + +/* TODO(ctiller): consider merging _nanos, _micros, _millis into a single + function for maintainability. Similarly for _seconds, _minutes, and _hours */ + +gpr_timespec gpr_time_from_nanos(long ns) { + gpr_timespec result; + if (ns == LONG_MAX) { + result = gpr_inf_future; + } else if (ns == LONG_MIN) { + result = gpr_inf_past; + } else if (ns >= 0) { + result.tv_sec = ns / 1000000000; + result.tv_nsec = ns - result.tv_sec * 1000000000; + } else { + /* Calculation carefully formulated to avoid any possible under/overflow. */ + result.tv_sec = (-(999999999 - (ns + 1000000000)) / 1000000000) - 1; + result.tv_nsec = ns - result.tv_sec * 1000000000; + } + return result; +} + +gpr_timespec gpr_time_from_micros(long us) { + gpr_timespec result; + if (us == LONG_MAX) { + result = gpr_inf_future; + } else if (us == LONG_MIN) { + result = gpr_inf_past; + } else if (us >= 0) { + result.tv_sec = us / 1000000; + result.tv_nsec = (us - result.tv_sec * 1000000) * 1000; + } else { + /* Calculation carefully formulated to avoid any possible under/overflow. */ + result.tv_sec = (-(999999 - (us + 1000000)) / 1000000) - 1; + result.tv_nsec = (us - result.tv_sec * 1000000) * 1000; + } + return result; +} + +gpr_timespec gpr_time_from_millis(long ms) { + gpr_timespec result; + if (ms == LONG_MAX) { + result = gpr_inf_future; + } else if (ms == LONG_MIN) { + result = gpr_inf_past; + } else if (ms >= 0) { + result.tv_sec = ms / 1000; + result.tv_nsec = (ms - result.tv_sec * 1000) * 1000000; + } else { + /* Calculation carefully formulated to avoid any possible under/overflow. */ + result.tv_sec = (-(999 - (ms + 1000)) / 1000) - 1; + result.tv_nsec = (ms - result.tv_sec * 1000) * 1000000; + } + return result; +} + +gpr_timespec gpr_time_from_seconds(long s) { + gpr_timespec result; + if (s == LONG_MAX) { + result = gpr_inf_future; + } else if (s == LONG_MIN) { + result = gpr_inf_past; + } else { + result.tv_sec = s; + result.tv_nsec = 0; + } + return result; +} + +gpr_timespec gpr_time_from_minutes(long m) { + gpr_timespec result; + if (m >= LONG_MAX / 60) { + result = gpr_inf_future; + } else if (m <= LONG_MIN / 60) { + result = gpr_inf_past; + } else { + result.tv_sec = m * 60; + result.tv_nsec = 0; + } + return result; +} + +gpr_timespec gpr_time_from_hours(long h) { + gpr_timespec result; + if (h >= LONG_MAX / 3600) { + result = gpr_inf_future; + } else if (h <= LONG_MIN / 3600) { + result = gpr_inf_past; + } else { + result.tv_sec = h * 3600; + result.tv_nsec = 0; + } + return result; +} + +gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b) { + gpr_timespec sum; + int inc = 0; + sum.tv_nsec = a.tv_nsec + b.tv_nsec; + if (sum.tv_nsec >= 1000000000) { + sum.tv_nsec -= 1000000000; + inc++; + } + if (a.tv_sec == TYPE_MAX(time_t) || a.tv_sec == TYPE_MIN(time_t)) { + sum = a; + } else if (b.tv_sec == TYPE_MAX(time_t) || + (b.tv_sec >= 0 && a.tv_sec >= TYPE_MAX(time_t) - b.tv_sec)) { + sum = gpr_inf_future; + } else if (b.tv_sec == TYPE_MIN(time_t) || + (b.tv_sec <= 0 && a.tv_sec <= TYPE_MIN(time_t) - b.tv_sec)) { + sum = gpr_inf_past; + } else { + sum.tv_sec = a.tv_sec + b.tv_sec; + if (inc != 0 && sum.tv_sec == TYPE_MAX(time_t) - 1) { + sum = gpr_inf_future; + } else { + sum.tv_sec += inc; + } + } + return sum; +} + +gpr_timespec gpr_time_sub(gpr_timespec a, gpr_timespec b) { + gpr_timespec diff; + int dec = 0; + diff.tv_nsec = a.tv_nsec - b.tv_nsec; + if (diff.tv_nsec < 0) { + diff.tv_nsec += 1000000000; + dec++; + } + if (a.tv_sec == TYPE_MAX(time_t) || a.tv_sec == TYPE_MIN(time_t)) { + diff = a; + } else if (b.tv_sec == TYPE_MIN(time_t) || + (b.tv_sec <= 0 && a.tv_sec >= TYPE_MAX(time_t) + b.tv_sec)) { + diff = gpr_inf_future; + } else if (b.tv_sec == TYPE_MAX(time_t) || + (b.tv_sec >= 0 && a.tv_sec <= TYPE_MIN(time_t) + b.tv_sec)) { + diff = gpr_inf_past; + } else { + diff.tv_sec = a.tv_sec - b.tv_sec; + if (dec != 0 && diff.tv_sec == TYPE_MIN(time_t) + 1) { + diff = gpr_inf_past; + } else { + diff.tv_sec -= dec; + } + } + return diff; +} + +int gpr_time_similar(gpr_timespec a, gpr_timespec b, gpr_timespec threshold) { + int cmp_ab; + + cmp_ab = gpr_time_cmp(a, b); + if (cmp_ab == 0) return 1; + if (cmp_ab < 0) { + return gpr_time_cmp(gpr_time_sub(b, a), threshold) <= 0; + } else { + return gpr_time_cmp(gpr_time_sub(a, b), threshold) <= 0; + } +} + +struct timeval gpr_timeval_from_timespec(gpr_timespec t) { + /* TODO(klempner): Consider whether this should round up, since it is likely + to be used for delays */ + struct timeval tv; + tv.tv_sec = t.tv_sec; + tv.tv_usec = t.tv_nsec / 1000; + return tv; +} + +gpr_timespec gpr_timespec_from_timeval(struct timeval t) { + gpr_timespec ts; + ts.tv_sec = t.tv_sec; + ts.tv_nsec = t.tv_usec * 1000; + return ts; +} diff --git a/src/core/support/time_posix.c b/src/core/support/time_posix.c new file mode 100644 index 0000000000..e7b79d10b1 --- /dev/null +++ b/src/core/support/time_posix.c @@ -0,0 +1,81 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* Posix code for gpr time support. */ + +/* So we get nanosleep and clock_* */ +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 199309L +#endif +#include <stdlib.h> +#include <time.h> +#include <unistd.h> +#include <grpc/support/time.h> + +#if _POSIX_TIMERS > 0 +gpr_timespec gpr_now(void) { + gpr_timespec now; + clock_gettime(CLOCK_REALTIME, &now); + return now; +} +#else +/* For some reason Apple's OSes haven't implemented clock_gettime. */ +/* TODO(klempner): Add special handling for Apple. */ +gpr_timespec gpr_now(void) { + gpr_timespec now; + struct timeval now_tv; + gettimeofday(&now_tv, NULL); + now.tv_sec = now_tv.tv_sec; + now.tv_nsec = now_tv.tv_usec / 1000; + return now; +} +#endif + +void gpr_sleep_until(gpr_timespec until) { + gpr_timespec now; + gpr_timespec delta; + + for (;;) { + /* We could simplify by using clock_nanosleep instead, but it might be + * slightly less portable. */ + now = gpr_now(); + if (gpr_time_cmp(until, now) <= 0) { + return; + } + + delta = gpr_time_sub(until, now); + if (nanosleep(&delta, NULL) == 0) { + break; + } + } +} diff --git a/src/core/support/time_win32.c b/src/core/support/time_win32.c new file mode 100644 index 0000000000..425809144c --- /dev/null +++ b/src/core/support/time_win32.c @@ -0,0 +1,52 @@ +/* + * + * Copyright 2014, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* Win32 code for gpr time support. */ + +#include <grpc/support/port_platform.h> + +#ifdef GPR_WIN32 + +#include <grpc/support/time.h> +#include <windows.h> + +gpr_timespec gpr_now(void) { + gpr_timespec now_tv; + struct _timeb64 now_tb; + _ftime64(&now_tb); + now_tv.tv_sec = now_tb.time; + now_tv.tv_nsec = now_tb.millitm * 1000000; + return now_tv; +} + +#endif /* GPR_WIN32 */ |