aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/support
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/support')
-rw-r--r--src/core/support/alloc.c67
-rw-r--r--src/core/support/cancellable.c156
-rw-r--r--src/core/support/cmdline.c292
-rw-r--r--src/core/support/cpu.h49
-rw-r--r--src/core/support/cpu_posix.c71
-rw-r--r--src/core/support/histogram.c226
-rw-r--r--src/core/support/host_port.c49
-rw-r--r--src/core/support/log.c48
-rw-r--r--src/core/support/log_android.c86
-rw-r--r--src/core/support/log_linux.c85
-rw-r--r--src/core/support/log_posix.c83
-rw-r--r--src/core/support/log_win32.c55
-rw-r--r--src/core/support/murmur_hash.c94
-rw-r--r--src/core/support/murmur_hash.h44
-rw-r--r--src/core/support/slice.c325
-rw-r--r--src/core/support/slice_buffer.c155
-rw-r--r--src/core/support/string.c124
-rw-r--r--src/core/support/string_posix.c86
-rw-r--r--src/core/support/sync.c135
-rw-r--r--src/core/support/sync_posix.c82
-rw-r--r--src/core/support/sync_win32.c120
-rw-r--r--src/core/support/thd_internal.h39
-rw-r--r--src/core/support/thd_posix.c78
-rw-r--r--src/core/support/thd_win32.c80
-rw-r--r--src/core/support/time.c243
-rw-r--r--src/core/support/time_posix.c81
-rw-r--r--src/core/support/time_win32.c52
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;
+ le.prev->next = &le;
+ 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 */