[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [tor/master] Split threading-related code out of compat.c
commit c2f0d52b7fb937f3f66ef8b2b74b0fdf239b0e9b
Author: Nick Mathewson <nickm@xxxxxxxxxxxxxx>
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 \
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits