[tor-commits] [tor/master] Split threading-related code out of compat.c

nickm at torproject.org nickm at torproject.org
Wed Jan 21 19:50:30 UTC 2015


commit c2f0d52b7fb937f3f66ef8b2b74b0fdf239b0e9b
Author: Nick Mathewson <nickm at torproject.org>
Date:   Sun Sep 22 21:30:46 2013 -0400

    Split threading-related code out of compat.c
    
    Also, re-enable the #if'd out condition-variable code.
    
    Work queues are going to make us hack on all of this stuff a bit more
    closely, so it might not be a terrible idea to make it easier to hack.
---
 configure.ac                   |    4 +
 src/common/compat.c            |  394 ----------------------------------------
 src/common/compat.h            |   57 +-----
 src/common/compat_pthreads.c   |  211 +++++++++++++++++++++
 src/common/compat_threads.c    |   42 +++++
 src/common/compat_threads.h    |   67 +++++++
 src/common/compat_winthreads.c |  161 ++++++++++++++++
 src/common/include.am          |   13 +-
 8 files changed, 499 insertions(+), 450 deletions(-)

diff --git a/configure.ac b/configure.ac
index c254725..65b3ff2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -393,6 +393,10 @@ fi
 AC_SEARCH_LIBS(pthread_create, [pthread])
 AC_SEARCH_LIBS(pthread_detach, [pthread])
 
+AM_CONDITIONAL(THREADS_WIN32, test "$enable_threads" = "yes" && test "$bwin32" = "true")
+AM_CONDITIONAL(THREADS_PTHREADS, test "$enable_threads" = "yes" && test "$bwin32" = "false")
+AM_CONDITIONAL(THREADS_NONE, test "$enable_threads" != "yes")
+
 dnl -------------------------------------------------------------------
 dnl Check for functions before libevent, since libevent-1.2 apparently
 dnl exports strlcpy without defining it in a header.
diff --git a/src/common/compat.c b/src/common/compat.c
index 6d36321..a22a61a 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -2544,109 +2544,6 @@ get_uname(void)
  *   Process control
  */
 
-#if defined(USE_PTHREADS)
-/** Wraps a void (*)(void*) function and its argument so we can
- * invoke them in a way pthreads would expect.
- */
-typedef struct tor_pthread_data_t {
-  void (*func)(void *);
-  void *data;
-} tor_pthread_data_t;
-/** Given a tor_pthread_data_t <b>_data</b>, call _data->func(d->data)
- * and free _data.  Used to make sure we can call functions the way pthread
- * expects. */
-static void *
-tor_pthread_helper_fn(void *_data)
-{
-  tor_pthread_data_t *data = _data;
-  void (*func)(void*);
-  void *arg;
-  /* mask signals to worker threads to avoid SIGPIPE, etc */
-  sigset_t sigs;
-  /* We're in a subthread; don't handle any signals here. */
-  sigfillset(&sigs);
-  pthread_sigmask(SIG_SETMASK, &sigs, NULL);
-
-  func = data->func;
-  arg = data->data;
-  tor_free(_data);
-  func(arg);
-  return NULL;
-}
-/**
- * A pthread attribute to make threads start detached.
- */
-static pthread_attr_t attr_detached;
-/** True iff we've called tor_threads_init() */
-static int threads_initialized = 0;
-#endif
-
-/** Minimalist interface to run a void function in the background.  On
- * Unix calls fork, on win32 calls beginthread.  Returns -1 on failure.
- * func should not return, but rather should call spawn_exit.
- *
- * NOTE: if <b>data</b> is used, it should not be allocated on the stack,
- * since in a multithreaded environment, there is no way to be sure that
- * the caller's stack will still be around when the called function is
- * running.
- */
-int
-spawn_func(void (*func)(void *), void *data)
-{
-#if defined(USE_WIN32_THREADS)
-  int rv;
-  rv = (int)_beginthread(func, 0, data);
-  if (rv == (int)-1)
-    return -1;
-  return 0;
-#elif defined(USE_PTHREADS)
-  pthread_t thread;
-  tor_pthread_data_t *d;
-  if (PREDICT_UNLIKELY(!threads_initialized))
-    tor_threads_init();
-  d = tor_malloc(sizeof(tor_pthread_data_t));
-  d->data = data;
-  d->func = func;
-  if (pthread_create(&thread,&attr_detached,tor_pthread_helper_fn,d))
-    return -1;
-  return 0;
-#else
-  pid_t pid;
-  pid = fork();
-  if (pid<0)
-    return -1;
-  if (pid==0) {
-    /* Child */
-    func(data);
-    tor_assert(0); /* Should never reach here. */
-    return 0; /* suppress "control-reaches-end-of-non-void" warning. */
-  } else {
-    /* Parent */
-    return 0;
-  }
-#endif
-}
-
-/** End the current thread/process.
- */
-void
-spawn_exit(void)
-{
-#if defined(USE_WIN32_THREADS)
-  _endthread();
-  //we should never get here. my compiler thinks that _endthread returns, this
-  //is an attempt to fool it.
-  tor_assert(0);
-  _exit(0);
-#elif defined(USE_PTHREADS)
-  pthread_exit(NULL);
-#else
-  /* http://www.erlenstar.demon.co.uk/unix/faq_2.html says we should
-   * call _exit, not exit, from child processes. */
-  _exit(0);
-#endif
-}
-
 /** Implementation logic for compute_num_cpus(). */
 static int
 compute_num_cpus_impl(void)
@@ -2935,280 +2832,6 @@ tor_gmtime_r(const time_t *timep, struct tm *result)
 }
 #endif
 
-#if defined(USE_WIN32_THREADS)
-void
-tor_mutex_init(tor_mutex_t *m)
-{
-  InitializeCriticalSection(&m->mutex);
-}
-void
-tor_mutex_uninit(tor_mutex_t *m)
-{
-  DeleteCriticalSection(&m->mutex);
-}
-void
-tor_mutex_acquire(tor_mutex_t *m)
-{
-  tor_assert(m);
-  EnterCriticalSection(&m->mutex);
-}
-void
-tor_mutex_release(tor_mutex_t *m)
-{
-  LeaveCriticalSection(&m->mutex);
-}
-unsigned long
-tor_get_thread_id(void)
-{
-  return (unsigned long)GetCurrentThreadId();
-}
-#elif defined(USE_PTHREADS)
-/** A mutex attribute that we're going to use to tell pthreads that we want
- * "reentrant" mutexes (i.e., once we can re-lock if we're already holding
- * them.) */
-static pthread_mutexattr_t attr_reentrant;
-/** Initialize <b>mutex</b> so it can be locked.  Every mutex must be set
- * up with tor_mutex_init() or tor_mutex_new(); not both. */
-void
-tor_mutex_init(tor_mutex_t *mutex)
-{
-  int err;
-  if (PREDICT_UNLIKELY(!threads_initialized))
-    tor_threads_init();
-  err = pthread_mutex_init(&mutex->mutex, &attr_reentrant);
-  if (PREDICT_UNLIKELY(err)) {
-    log_err(LD_GENERAL, "Error %d creating a mutex.", err);
-    tor_fragile_assert();
-  }
-}
-/** Wait until <b>m</b> is free, then acquire it. */
-void
-tor_mutex_acquire(tor_mutex_t *m)
-{
-  int err;
-  tor_assert(m);
-  err = pthread_mutex_lock(&m->mutex);
-  if (PREDICT_UNLIKELY(err)) {
-    log_err(LD_GENERAL, "Error %d locking a mutex.", err);
-    tor_fragile_assert();
-  }
-}
-/** Release the lock <b>m</b> so another thread can have it. */
-void
-tor_mutex_release(tor_mutex_t *m)
-{
-  int err;
-  tor_assert(m);
-  err = pthread_mutex_unlock(&m->mutex);
-  if (PREDICT_UNLIKELY(err)) {
-    log_err(LD_GENERAL, "Error %d unlocking a mutex.", err);
-    tor_fragile_assert();
-  }
-}
-/** Clean up the mutex <b>m</b> so that it no longer uses any system
- * resources.  Does not free <b>m</b>.  This function must only be called on
- * mutexes from tor_mutex_init(). */
-void
-tor_mutex_uninit(tor_mutex_t *m)
-{
-  int err;
-  tor_assert(m);
-  err = pthread_mutex_destroy(&m->mutex);
-  if (PREDICT_UNLIKELY(err)) {
-    log_err(LD_GENERAL, "Error %d destroying a mutex.", err);
-    tor_fragile_assert();
-  }
-}
-/** Return an integer representing this thread. */
-unsigned long
-tor_get_thread_id(void)
-{
-  union {
-    pthread_t thr;
-    unsigned long id;
-  } r;
-  r.thr = pthread_self();
-  return r.id;
-}
-#endif
-
-/** Return a newly allocated, ready-for-use mutex. */
-tor_mutex_t *
-tor_mutex_new(void)
-{
-  tor_mutex_t *m = tor_malloc_zero(sizeof(tor_mutex_t));
-  tor_mutex_init(m);
-  return m;
-}
-/** Release all storage and system resources held by <b>m</b>. */
-void
-tor_mutex_free(tor_mutex_t *m)
-{
-  if (!m)
-    return;
-  tor_mutex_uninit(m);
-  tor_free(m);
-}
-
-/* Conditions. */
-#ifdef USE_PTHREADS
-#if 0
-/** Cross-platform condition implementation. */
-struct tor_cond_t {
-  pthread_cond_t cond;
-};
-/** Return a newly allocated condition, with nobody waiting on it. */
-tor_cond_t *
-tor_cond_new(void)
-{
-  tor_cond_t *cond = tor_malloc_zero(sizeof(tor_cond_t));
-  if (pthread_cond_init(&cond->cond, NULL)) {
-    tor_free(cond);
-    return NULL;
-  }
-  return cond;
-}
-/** Release all resources held by <b>cond</b>. */
-void
-tor_cond_free(tor_cond_t *cond)
-{
-  if (!cond)
-    return;
-  if (pthread_cond_destroy(&cond->cond)) {
-    log_warn(LD_GENERAL,"Error freeing condition: %s", strerror(errno));
-    return;
-  }
-  tor_free(cond);
-}
-/** Wait until one of the tor_cond_signal functions is called on <b>cond</b>.
- * All waiters on the condition must wait holding the same <b>mutex</b>.
- * Returns 0 on success, negative on failure. */
-int
-tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex)
-{
-  return pthread_cond_wait(&cond->cond, &mutex->mutex) ? -1 : 0;
-}
-/** Wake up one of the waiters on <b>cond</b>. */
-void
-tor_cond_signal_one(tor_cond_t *cond)
-{
-  pthread_cond_signal(&cond->cond);
-}
-/** Wake up all of the waiters on <b>cond</b>. */
-void
-tor_cond_signal_all(tor_cond_t *cond)
-{
-  pthread_cond_broadcast(&cond->cond);
-}
-#endif
-/** Set up common structures for use by threading. */
-void
-tor_threads_init(void)
-{
-  if (!threads_initialized) {
-    pthread_mutexattr_init(&attr_reentrant);
-    pthread_mutexattr_settype(&attr_reentrant, PTHREAD_MUTEX_RECURSIVE);
-    tor_assert(0==pthread_attr_init(&attr_detached));
-    tor_assert(0==pthread_attr_setdetachstate(&attr_detached, 1));
-    threads_initialized = 1;
-    set_main_thread();
-  }
-}
-#elif defined(USE_WIN32_THREADS)
-#if 0
-static DWORD cond_event_tls_index;
-struct tor_cond_t {
-  CRITICAL_SECTION mutex;
-  smartlist_t *events;
-};
-tor_cond_t *
-tor_cond_new(void)
-{
-  tor_cond_t *cond = tor_malloc_zero(sizeof(tor_cond_t));
-  InitializeCriticalSection(&cond->mutex);
-  cond->events = smartlist_new();
-  return cond;
-}
-void
-tor_cond_free(tor_cond_t *cond)
-{
-  if (!cond)
-    return;
-  DeleteCriticalSection(&cond->mutex);
-  /* XXXX notify? */
-  smartlist_free(cond->events);
-  tor_free(cond);
-}
-int
-tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex)
-{
-  HANDLE event;
-  int r;
-  tor_assert(cond);
-  tor_assert(mutex);
-  event = TlsGetValue(cond_event_tls_index);
-  if (!event) {
-    event = CreateEvent(0, FALSE, FALSE, NULL);
-    TlsSetValue(cond_event_tls_index, event);
-  }
-  EnterCriticalSection(&cond->mutex);
-
-  tor_assert(WaitForSingleObject(event, 0) == WAIT_TIMEOUT);
-  tor_assert(!smartlist_contains(cond->events, event));
-  smartlist_add(cond->events, event);
-
-  LeaveCriticalSection(&cond->mutex);
-
-  tor_mutex_release(mutex);
-  r = WaitForSingleObject(event, INFINITE);
-  tor_mutex_acquire(mutex);
-
-  switch (r) {
-    case WAIT_OBJECT_0: /* we got the mutex normally. */
-      break;
-    case WAIT_ABANDONED: /* holding thread exited. */
-    case WAIT_TIMEOUT: /* Should never happen. */
-      tor_assert(0);
-      break;
-    case WAIT_FAILED:
-      log_warn(LD_GENERAL, "Failed to acquire mutex: %d",(int) GetLastError());
-  }
-  return 0;
-}
-void
-tor_cond_signal_one(tor_cond_t *cond)
-{
-  HANDLE event;
-  tor_assert(cond);
-
-  EnterCriticalSection(&cond->mutex);
-
-  if ((event = smartlist_pop_last(cond->events)))
-    SetEvent(event);
-
-  LeaveCriticalSection(&cond->mutex);
-}
-void
-tor_cond_signal_all(tor_cond_t *cond)
-{
-  tor_assert(cond);
-
-  EnterCriticalSection(&cond->mutex);
-  SMARTLIST_FOREACH(cond->events, HANDLE, event, SetEvent(event));
-  smartlist_clear(cond->events);
-  LeaveCriticalSection(&cond->mutex);
-}
-#endif
-void
-tor_threads_init(void)
-{
-#if 0
-  cond_event_tls_index = TlsAlloc();
-#endif
-  set_main_thread();
-}
-#endif
-
 #if defined(HAVE_MLOCKALL) && HAVE_DECL_MLOCKALL && defined(RLIMIT_MEMLOCK)
 /** Attempt to raise the current and max rlimit to infinity for our process.
  * This only needs to be done once and can probably only be done when we have
@@ -3292,23 +2915,6 @@ tor_mlockall(void)
 #endif
 }
 
-/** Identity of the "main" thread */
-static unsigned long main_thread_id = -1;
-
-/** Start considering the current thread to be the 'main thread'.  This has
- * no effect on anything besides in_main_thread(). */
-void
-set_main_thread(void)
-{
-  main_thread_id = tor_get_thread_id();
-}
-/** Return true iff called from the main thread. */
-int
-in_main_thread(void)
-{
-  return main_thread_id == tor_get_thread_id();
-}
-
 /**
  * On Windows, WSAEWOULDBLOCK is not always correct: when you see it,
  * you need to ask the socket for its actual errno.  Also, you need to
diff --git a/src/common/compat.h b/src/common/compat.h
index 04e8cb2..23f8614 100644
--- a/src/common/compat.h
+++ b/src/common/compat.h
@@ -36,9 +36,6 @@
 #ifdef HAVE_STRING_H
 #include <string.h>
 #endif
-#if defined(HAVE_PTHREAD_H) && !defined(_WIN32)
-#include <pthread.h>
-#endif
 #include <stdarg.h>
 #ifdef HAVE_SYS_RESOURCE_H
 #include <sys/resource.h>
@@ -642,61 +639,10 @@ char **get_environment(void);
 
 int get_total_system_memory(size_t *mem_out);
 
-int spawn_func(void (*func)(void *), void *data);
-void spawn_exit(void) ATTR_NORETURN;
-
-#if defined(_WIN32)
-#define USE_WIN32_THREADS
-#elif defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_CREATE)
-#define USE_PTHREADS
-#else
-#error "No threading system was found"
-#endif
-
 int compute_num_cpus(void);
 
-/* Because we use threads instead of processes on most platforms (Windows,
- * Linux, etc), we need locking for them.  On platforms with poor thread
- * support or broken gethostbyname_r, these functions are no-ops. */
-
-/** A generic lock structure for multithreaded builds. */
-typedef struct tor_mutex_t {
-#if defined(USE_WIN32_THREADS)
-  /** Windows-only: on windows, we implement locks with CRITICAL_SECTIONS. */
-  CRITICAL_SECTION mutex;
-#elif defined(USE_PTHREADS)
-  /** Pthreads-only: with pthreads, we implement locks with
-   * pthread_mutex_t. */
-  pthread_mutex_t mutex;
-#else
-  /** No-threads only: Dummy variable so that tor_mutex_t takes up space. */
-  int _unused;
-#endif
-} tor_mutex_t;
-
 int tor_mlockall(void);
 
-tor_mutex_t *tor_mutex_new(void);
-void tor_mutex_init(tor_mutex_t *m);
-void tor_mutex_acquire(tor_mutex_t *m);
-void tor_mutex_release(tor_mutex_t *m);
-void tor_mutex_free(tor_mutex_t *m);
-void tor_mutex_uninit(tor_mutex_t *m);
-unsigned long tor_get_thread_id(void);
-void tor_threads_init(void);
-
-void set_main_thread(void);
-int in_main_thread(void);
-
-#if 0
-typedef struct tor_cond_t tor_cond_t;
-tor_cond_t *tor_cond_new(void);
-void tor_cond_free(tor_cond_t *cond);
-int tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex);
-void tor_cond_signal_one(tor_cond_t *cond);
-void tor_cond_signal_all(tor_cond_t *cond);
-#endif
-
 /** Macros for MIN/MAX.  Never use these when the arguments could have
  * side-effects.
  * {With GCC extensions we could probably define a safer MIN/MAX.  But
@@ -742,5 +688,8 @@ STATIC int tor_ersatz_socketpair(int family, int type, int protocol,
 #endif
 #endif
 
+/* This needs some of the declarations above so we include it here. */
+#include "compat_threads.h"
+
 #endif
 
diff --git a/src/common/compat_pthreads.c b/src/common/compat_pthreads.c
new file mode 100644
index 0000000..276b244
--- /dev/null
+++ b/src/common/compat_pthreads.c
@@ -0,0 +1,211 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#include <pthread.h>
+
+#include "compat.h"
+#include "torlog.h"
+#include "util.h"
+
+/** Wraps a void (*)(void*) function and its argument so we can
+ * invoke them in a way pthreads would expect.
+ */
+typedef struct tor_pthread_data_t {
+  void (*func)(void *);
+  void *data;
+} tor_pthread_data_t;
+/** Given a tor_pthread_data_t <b>_data</b>, call _data->func(d->data)
+ * and free _data.  Used to make sure we can call functions the way pthread
+ * expects. */
+static void *
+tor_pthread_helper_fn(void *_data)
+{
+  tor_pthread_data_t *data = _data;
+  void (*func)(void*);
+  void *arg;
+  /* mask signals to worker threads to avoid SIGPIPE, etc */
+  sigset_t sigs;
+  /* We're in a subthread; don't handle any signals here. */
+  sigfillset(&sigs);
+  pthread_sigmask(SIG_SETMASK, &sigs, NULL);
+
+  func = data->func;
+  arg = data->data;
+  tor_free(_data);
+  func(arg);
+  return NULL;
+}
+/**
+ * A pthread attribute to make threads start detached.
+ */
+static pthread_attr_t attr_detached;
+/** True iff we've called tor_threads_init() */
+static int threads_initialized = 0;
+
+
+/** Minimalist interface to run a void function in the background.  On
+ * Unix calls fork, on win32 calls beginthread.  Returns -1 on failure.
+ * func should not return, but rather should call spawn_exit.
+ *
+ * NOTE: if <b>data</b> is used, it should not be allocated on the stack,
+ * since in a multithreaded environment, there is no way to be sure that
+ * the caller's stack will still be around when the called function is
+ * running.
+ */
+int
+spawn_func(void (*func)(void *), void *data)
+{
+  pthread_t thread;
+  tor_pthread_data_t *d;
+  if (PREDICT_UNLIKELY(!threads_initialized))
+    tor_threads_init();
+  d = tor_malloc(sizeof(tor_pthread_data_t));
+  d->data = data;
+  d->func = func;
+  if (pthread_create(&thread,&attr_detached,tor_pthread_helper_fn,d))
+    return -1;
+  return 0;
+}
+
+/** End the current thread/process.
+ */
+void
+spawn_exit(void)
+{
+  pthread_exit(NULL);
+}
+
+/** A mutex attribute that we're going to use to tell pthreads that we want
+ * "reentrant" mutexes (i.e., once we can re-lock if we're already holding
+ * them.) */
+static pthread_mutexattr_t attr_reentrant;
+/** Initialize <b>mutex</b> so it can be locked.  Every mutex must be set
+ * up with tor_mutex_init() or tor_mutex_new(); not both. */
+void
+tor_mutex_init(tor_mutex_t *mutex)
+{
+  int err;
+  if (PREDICT_UNLIKELY(!threads_initialized))
+    tor_threads_init();
+  err = pthread_mutex_init(&mutex->mutex, &attr_reentrant);
+  if (PREDICT_UNLIKELY(err)) {
+    log_err(LD_GENERAL, "Error %d creating a mutex.", err);
+    tor_fragile_assert();
+  }
+}
+/** Wait until <b>m</b> is free, then acquire it. */
+void
+tor_mutex_acquire(tor_mutex_t *m)
+{
+  int err;
+  tor_assert(m);
+  err = pthread_mutex_lock(&m->mutex);
+  if (PREDICT_UNLIKELY(err)) {
+    log_err(LD_GENERAL, "Error %d locking a mutex.", err);
+    tor_fragile_assert();
+  }
+}
+/** Release the lock <b>m</b> so another thread can have it. */
+void
+tor_mutex_release(tor_mutex_t *m)
+{
+  int err;
+  tor_assert(m);
+  err = pthread_mutex_unlock(&m->mutex);
+  if (PREDICT_UNLIKELY(err)) {
+    log_err(LD_GENERAL, "Error %d unlocking a mutex.", err);
+    tor_fragile_assert();
+  }
+}
+/** Clean up the mutex <b>m</b> so that it no longer uses any system
+ * resources.  Does not free <b>m</b>.  This function must only be called on
+ * mutexes from tor_mutex_init(). */
+void
+tor_mutex_uninit(tor_mutex_t *m)
+{
+  int err;
+  tor_assert(m);
+  err = pthread_mutex_destroy(&m->mutex);
+  if (PREDICT_UNLIKELY(err)) {
+    log_err(LD_GENERAL, "Error %d destroying a mutex.", err);
+    tor_fragile_assert();
+  }
+}
+/** Return an integer representing this thread. */
+unsigned long
+tor_get_thread_id(void)
+{
+  union {
+    pthread_t thr;
+    unsigned long id;
+  } r;
+  r.thr = pthread_self();
+  return r.id;
+}
+
+/* Conditions. */
+
+/** Cross-platform condition implementation. */
+struct tor_cond_t {
+  pthread_cond_t cond;
+};
+/** Return a newly allocated condition, with nobody waiting on it. */
+tor_cond_t *
+tor_cond_new(void)
+{
+  tor_cond_t *cond = tor_malloc_zero(sizeof(tor_cond_t));
+  if (pthread_cond_init(&cond->cond, NULL)) {
+    tor_free(cond);
+    return NULL;
+  }
+  return cond;
+}
+/** Release all resources held by <b>cond</b>. */
+void
+tor_cond_free(tor_cond_t *cond)
+{
+  if (!cond)
+    return;
+  if (pthread_cond_destroy(&cond->cond)) {
+    log_warn(LD_GENERAL,"Error freeing condition: %s", strerror(errno));
+    return;
+  }
+  tor_free(cond);
+}
+/** Wait until one of the tor_cond_signal functions is called on <b>cond</b>.
+ * All waiters on the condition must wait holding the same <b>mutex</b>.
+ * Returns 0 on success, negative on failure. */
+int
+tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex)
+{
+  return pthread_cond_wait(&cond->cond, &mutex->mutex) ? -1 : 0;
+}
+/** Wake up one of the waiters on <b>cond</b>. */
+void
+tor_cond_signal_one(tor_cond_t *cond)
+{
+  pthread_cond_signal(&cond->cond);
+}
+/** Wake up all of the waiters on <b>cond</b>. */
+void
+tor_cond_signal_all(tor_cond_t *cond)
+{
+  pthread_cond_broadcast(&cond->cond);
+}
+
+/** Set up common structures for use by threading. */
+void
+tor_threads_init(void)
+{
+  if (!threads_initialized) {
+    pthread_mutexattr_init(&attr_reentrant);
+    pthread_mutexattr_settype(&attr_reentrant, PTHREAD_MUTEX_RECURSIVE);
+    tor_assert(0==pthread_attr_init(&attr_detached));
+    tor_assert(0==pthread_attr_setdetachstate(&attr_detached, 1));
+    threads_initialized = 1;
+    set_main_thread();
+  }
+}
diff --git a/src/common/compat_threads.c b/src/common/compat_threads.c
new file mode 100644
index 0000000..84a8a21
--- /dev/null
+++ b/src/common/compat_threads.c
@@ -0,0 +1,42 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "compat.h"
+#include "util.h"
+
+/** Return a newly allocated, ready-for-use mutex. */
+tor_mutex_t *
+tor_mutex_new(void)
+{
+  tor_mutex_t *m = tor_malloc_zero(sizeof(tor_mutex_t));
+  tor_mutex_init(m);
+  return m;
+}
+/** Release all storage and system resources held by <b>m</b>. */
+void
+tor_mutex_free(tor_mutex_t *m)
+{
+  if (!m)
+    return;
+  tor_mutex_uninit(m);
+  tor_free(m);
+}
+
+/** Identity of the "main" thread */
+static unsigned long main_thread_id = -1;
+
+/** Start considering the current thread to be the 'main thread'.  This has
+ * no effect on anything besides in_main_thread(). */
+void
+set_main_thread(void)
+{
+  main_thread_id = tor_get_thread_id();
+}
+/** Return true iff called from the main thread. */
+int
+in_main_thread(void)
+{
+  return main_thread_id == tor_get_thread_id();
+}
diff --git a/src/common/compat_threads.h b/src/common/compat_threads.h
new file mode 100644
index 0000000..f43e74a
--- /dev/null
+++ b/src/common/compat_threads.h
@@ -0,0 +1,67 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_COMPAT_THREADS_H
+#define TOR_COMPAT_THREADS_H
+
+#include "orconfig.h"
+#include "torint.h"
+#include "testsupport.h"
+
+#if defined(HAVE_PTHREAD_H) && !defined(_WIN32)
+#include <pthread.h>
+#endif
+
+#if defined(_WIN32)
+#define USE_WIN32_THREADS
+#elif defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_CREATE)
+#define USE_PTHREADS
+#else
+#error "No threading system was found"
+#endif
+
+int spawn_func(void (*func)(void *), void *data);
+void spawn_exit(void) ATTR_NORETURN;
+
+/* Because we use threads instead of processes on most platforms (Windows,
+ * Linux, etc), we need locking for them.  On platforms with poor thread
+ * support or broken gethostbyname_r, these functions are no-ops. */
+
+/** A generic lock structure for multithreaded builds. */
+typedef struct tor_mutex_t {
+#if defined(USE_WIN32_THREADS)
+  /** Windows-only: on windows, we implement locks with CRITICAL_SECTIONS. */
+  CRITICAL_SECTION mutex;
+#elif defined(USE_PTHREADS)
+  /** Pthreads-only: with pthreads, we implement locks with
+   * pthread_mutex_t. */
+  pthread_mutex_t mutex;
+#else
+  /** No-threads only: Dummy variable so that tor_mutex_t takes up space. */
+  int _unused;
+#endif
+} tor_mutex_t;
+
+
+tor_mutex_t *tor_mutex_new(void);
+void tor_mutex_init(tor_mutex_t *m);
+void tor_mutex_acquire(tor_mutex_t *m);
+void tor_mutex_release(tor_mutex_t *m);
+void tor_mutex_free(tor_mutex_t *m);
+void tor_mutex_uninit(tor_mutex_t *m);
+unsigned long tor_get_thread_id(void);
+void tor_threads_init(void);
+
+void set_main_thread(void);
+int in_main_thread(void);
+
+typedef struct tor_cond_t tor_cond_t;
+tor_cond_t *tor_cond_new(void);
+void tor_cond_free(tor_cond_t *cond);
+int tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex);
+void tor_cond_signal_one(tor_cond_t *cond);
+void tor_cond_signal_all(tor_cond_t *cond);
+
+#endif
diff --git a/src/common/compat_winthreads.c b/src/common/compat_winthreads.c
new file mode 100644
index 0000000..01332fd
--- /dev/null
+++ b/src/common/compat_winthreads.c
@@ -0,0 +1,161 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "compat.h"
+#include <windows.h>
+#include <process.h>
+#include "util.h"
+#include "container.h"
+#include "torlog.h"
+
+/** Minimalist interface to run a void function in the background.  On
+ * Unix calls fork, on win32 calls beginthread.  Returns -1 on failure.
+ * func should not return, but rather should call spawn_exit.
+ *
+ * NOTE: if <b>data</b> is used, it should not be allocated on the stack,
+ * since in a multithreaded environment, there is no way to be sure that
+ * the caller's stack will still be around when the called function is
+ * running.
+ */
+int
+spawn_func(void (*func)(void *), void *data)
+{
+  int rv;
+  rv = (int)_beginthread(func, 0, data);
+  if (rv == (int)-1)
+    return -1;
+  return 0;
+}
+
+
+/** End the current thread/process.
+ */
+void
+spawn_exit(void)
+{
+  _endthread();
+  //we should never get here. my compiler thinks that _endthread returns, this
+  //is an attempt to fool it.
+  tor_assert(0);
+  _exit(0);
+}
+
+
+void
+tor_mutex_init(tor_mutex_t *m)
+{
+  InitializeCriticalSection(&m->mutex);
+}
+void
+tor_mutex_uninit(tor_mutex_t *m)
+{
+  DeleteCriticalSection(&m->mutex);
+}
+void
+tor_mutex_acquire(tor_mutex_t *m)
+{
+  tor_assert(m);
+  EnterCriticalSection(&m->mutex);
+}
+void
+tor_mutex_release(tor_mutex_t *m)
+{
+  LeaveCriticalSection(&m->mutex);
+}
+unsigned long
+tor_get_thread_id(void)
+{
+  return (unsigned long)GetCurrentThreadId();
+}
+
+static DWORD cond_event_tls_index;
+struct tor_cond_t {
+  CRITICAL_SECTION mutex;
+  smartlist_t *events;
+};
+tor_cond_t *
+tor_cond_new(void)
+{
+  tor_cond_t *cond = tor_malloc_zero(sizeof(tor_cond_t));
+  InitializeCriticalSection(&cond->mutex);
+  cond->events = smartlist_new();
+  return cond;
+}
+void
+tor_cond_free(tor_cond_t *cond)
+{
+  if (!cond)
+    return;
+  DeleteCriticalSection(&cond->mutex);
+  /* XXXX notify? */
+  smartlist_free(cond->events);
+  tor_free(cond);
+}
+int
+tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex)
+{
+  HANDLE event;
+  int r;
+  tor_assert(cond);
+  tor_assert(mutex);
+  event = TlsGetValue(cond_event_tls_index);
+  if (!event) {
+    event = CreateEvent(0, FALSE, FALSE, NULL);
+    TlsSetValue(cond_event_tls_index, event);
+  }
+  EnterCriticalSection(&cond->mutex);
+
+  tor_assert(WaitForSingleObject(event, 0) == WAIT_TIMEOUT);
+  tor_assert(!smartlist_contains(cond->events, event));
+  smartlist_add(cond->events, event);
+
+  LeaveCriticalSection(&cond->mutex);
+
+  tor_mutex_release(mutex);
+  r = WaitForSingleObject(event, INFINITE);
+  tor_mutex_acquire(mutex);
+
+  switch (r) {
+    case WAIT_OBJECT_0: /* we got the mutex normally. */
+      break;
+    case WAIT_ABANDONED: /* holding thread exited. */
+    case WAIT_TIMEOUT: /* Should never happen. */
+      tor_assert(0);
+      break;
+    case WAIT_FAILED:
+      log_warn(LD_GENERAL, "Failed to acquire mutex: %d",(int) GetLastError());
+  }
+  return 0;
+}
+void
+tor_cond_signal_one(tor_cond_t *cond)
+{
+  HANDLE event;
+  tor_assert(cond);
+
+  EnterCriticalSection(&cond->mutex);
+
+  if ((event = smartlist_pop_last(cond->events)))
+    SetEvent(event);
+
+  LeaveCriticalSection(&cond->mutex);
+}
+void
+tor_cond_signal_all(tor_cond_t *cond)
+{
+  tor_assert(cond);
+
+  EnterCriticalSection(&cond->mutex);
+  SMARTLIST_FOREACH(cond->events, HANDLE, event, SetEvent(event));
+  smartlist_clear(cond->events);
+  LeaveCriticalSection(&cond->mutex);
+}
+
+void
+tor_threads_init(void)
+{
+  cond_event_tls_index = TlsAlloc();
+  set_main_thread();
+}
diff --git a/src/common/include.am b/src/common/include.am
index 6441596..e4eeba6 100644
--- a/src/common/include.am
+++ b/src/common/include.am
@@ -54,10 +54,18 @@ endif
 
 LIBDONNA += $(LIBED25519_REF10)
 
+if THREADS_PTHREADS
+threads_impl_source=src/common/compat_pthreads.c
+endif
+if THREADS_WIN32
+threads_impl_source=src/common/compat_winthreads.c
+endif
+
 LIBOR_A_SOURCES = \
   src/common/address.c					\
   src/common/backtrace.c				\
   src/common/compat.c					\
+  src/common/compat_threads.c				\
   src/common/container.c				\
   src/common/di_ops.c					\
   src/common/log.c					\
@@ -69,7 +77,8 @@ LIBOR_A_SOURCES = \
   src/ext/csiphash.c					\
   src/ext/trunnel/trunnel.c				\
   $(libor_extra_source)					\
-  $(libor_mempool_source)
+  $(libor_mempool_source)				\
+  $(threads_impl_source)
 
 LIBOR_CRYPTO_A_SOURCES = \
   src/common/aes.c		\
@@ -102,7 +111,6 @@ src_common_libor_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
 src_common_libor_crypto_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
 src_common_libor_event_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
 
-
 COMMONHEADERS = \
   src/common/address.h				\
   src/common/backtrace.h			\
@@ -110,6 +118,7 @@ COMMONHEADERS = \
   src/common/ciphers.inc			\
   src/common/compat.h				\
   src/common/compat_libevent.h			\
+  src/common/compat_threads.h			\
   src/common/container.h			\
   src/common/crypto.h				\
   src/common/crypto_curve25519.h		\





More information about the tor-commits mailing list