don't init threads as side effect of assertion
[tor.git] / src / common / compat_pthreads.c
blob70259a8a53c2a10aa81e9cca3433bfd11de056d3
1 /* Copyright (c) 2003-2004, Roger Dingledine
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2015, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
6 #define _GNU_SOURCE
8 #include "orconfig.h"
9 #include <pthread.h>
10 #include <signal.h>
11 #include <time.h>
13 #include "compat.h"
14 #include "torlog.h"
15 #include "util.h"
17 /** Wraps a void (*)(void*) function and its argument so we can
18 * invoke them in a way pthreads would expect.
20 typedef struct tor_pthread_data_t {
21 void (*func)(void *);
22 void *data;
23 } tor_pthread_data_t;
24 /** Given a tor_pthread_data_t <b>_data</b>, call _data-&gt;func(d-&gt;data)
25 * and free _data. Used to make sure we can call functions the way pthread
26 * expects. */
27 static void *
28 tor_pthread_helper_fn(void *_data)
30 tor_pthread_data_t *data = _data;
31 void (*func)(void*);
32 void *arg;
33 /* mask signals to worker threads to avoid SIGPIPE, etc */
34 sigset_t sigs;
35 /* We're in a subthread; don't handle any signals here. */
36 sigfillset(&sigs);
37 pthread_sigmask(SIG_SETMASK, &sigs, NULL);
39 func = data->func;
40 arg = data->data;
41 tor_free(_data);
42 func(arg);
43 return NULL;
45 /**
46 * A pthread attribute to make threads start detached.
48 static pthread_attr_t attr_detached;
49 /** True iff we've called tor_threads_init() */
50 static int threads_initialized = 0;
52 /** Minimalist interface to run a void function in the background. On
53 * Unix calls fork, on win32 calls beginthread. Returns -1 on failure.
54 * func should not return, but rather should call spawn_exit.
56 * NOTE: if <b>data</b> is used, it should not be allocated on the stack,
57 * since in a multithreaded environment, there is no way to be sure that
58 * the caller's stack will still be around when the called function is
59 * running.
61 int
62 spawn_func(void (*func)(void *), void *data)
64 pthread_t thread;
65 tor_pthread_data_t *d;
66 if (PREDICT_UNLIKELY(!threads_initialized))
67 tor_threads_init();
68 d = tor_malloc(sizeof(tor_pthread_data_t));
69 d->data = data;
70 d->func = func;
71 if (pthread_create(&thread,&attr_detached,tor_pthread_helper_fn,d))
72 return -1;
73 return 0;
76 /** End the current thread/process.
78 void
79 spawn_exit(void)
81 pthread_exit(NULL);
84 /** A mutex attribute that we're going to use to tell pthreads that we want
85 * "recursive" mutexes (i.e., once we can re-lock if we're already holding
86 * them.) */
87 static pthread_mutexattr_t attr_recursive;
89 /** Initialize <b>mutex</b> so it can be locked. Every mutex must be set
90 * up with tor_mutex_init() or tor_mutex_new(); not both. */
91 void
92 tor_mutex_init(tor_mutex_t *mutex)
94 int err;
95 if (PREDICT_UNLIKELY(!threads_initialized))
96 tor_threads_init();
97 err = pthread_mutex_init(&mutex->mutex, &attr_recursive);
98 if (PREDICT_UNLIKELY(err)) {
99 log_err(LD_GENERAL, "Error %d creating a mutex.", err);
100 tor_fragile_assert();
104 /** As tor_mutex_init, but initialize a mutex suitable that may be
105 * non-recursive, if the OS supports that. */
106 void
107 tor_mutex_init_nonrecursive(tor_mutex_t *mutex)
109 int err;
110 if (PREDICT_UNLIKELY(!threads_initialized))
111 tor_threads_init();
112 err = pthread_mutex_init(&mutex->mutex, NULL);
113 if (PREDICT_UNLIKELY(err)) {
114 log_err(LD_GENERAL, "Error %d creating a mutex.", err);
115 tor_fragile_assert();
119 /** Wait until <b>m</b> is free, then acquire it. */
120 void
121 tor_mutex_acquire(tor_mutex_t *m)
123 int err;
124 tor_assert(m);
125 err = pthread_mutex_lock(&m->mutex);
126 if (PREDICT_UNLIKELY(err)) {
127 log_err(LD_GENERAL, "Error %d locking a mutex.", err);
128 tor_fragile_assert();
131 /** Release the lock <b>m</b> so another thread can have it. */
132 void
133 tor_mutex_release(tor_mutex_t *m)
135 int err;
136 tor_assert(m);
137 err = pthread_mutex_unlock(&m->mutex);
138 if (PREDICT_UNLIKELY(err)) {
139 log_err(LD_GENERAL, "Error %d unlocking a mutex.", err);
140 tor_fragile_assert();
143 /** Clean up the mutex <b>m</b> so that it no longer uses any system
144 * resources. Does not free <b>m</b>. This function must only be called on
145 * mutexes from tor_mutex_init(). */
146 void
147 tor_mutex_uninit(tor_mutex_t *m)
149 int err;
150 tor_assert(m);
151 err = pthread_mutex_destroy(&m->mutex);
152 if (PREDICT_UNLIKELY(err)) {
153 log_err(LD_GENERAL, "Error %d destroying a mutex.", err);
154 tor_fragile_assert();
157 /** Return an integer representing this thread. */
158 unsigned long
159 tor_get_thread_id(void)
161 union {
162 pthread_t thr;
163 unsigned long id;
164 } r;
165 r.thr = pthread_self();
166 return r.id;
169 /* Conditions. */
171 /** Initialize an already-allocated condition variable. */
173 tor_cond_init(tor_cond_t *cond)
175 pthread_condattr_t condattr;
177 memset(cond, 0, sizeof(tor_cond_t));
178 /* Default condition attribute. Might be used if clock monotonic is
179 * available else this won't affect anything. */
180 if (pthread_condattr_init(&condattr)) {
181 return -1;
184 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
185 /* Use monotonic time so when we timedwait() on it, any clock adjustment
186 * won't affect the timeout value. */
187 if (pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC)) {
188 return -1;
190 #endif
191 if (pthread_cond_init(&cond->cond, &condattr)) {
192 return -1;
194 return 0;
197 /** Release all resources held by <b>cond</b>, but do not free <b>cond</b>
198 * itself. */
199 void
200 tor_cond_uninit(tor_cond_t *cond)
202 if (pthread_cond_destroy(&cond->cond)) {
203 log_warn(LD_GENERAL,"Error freeing condition: %s", strerror(errno));
204 return;
207 /** Wait until one of the tor_cond_signal functions is called on <b>cond</b>.
208 * (If <b>tv</b> is set, and that amount of time passes with no signal to
209 * <b>cond</b>, return anyway. All waiters on the condition must wait holding
210 * the same <b>mutex</b>. All signallers should hold that mutex. The mutex
211 * needs to have been allocated with tor_mutex_init_for_cond().
213 * Returns 0 on success, -1 on failure, 1 on timeout. */
215 tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex, const struct timeval *tv)
217 int r;
218 if (tv == NULL) {
219 while (1) {
220 r = pthread_cond_wait(&cond->cond, &mutex->mutex);
221 if (r == EINTR) {
222 /* EINTR should be impossible according to POSIX, but POSIX, like the
223 * Pirate's Code, is apparently treated "more like what you'd call
224 * guidelines than actual rules." */
225 continue;
227 return r ? -1 : 0;
229 } else {
230 struct timeval tvnow, tvsum;
231 struct timespec ts;
232 while (1) {
233 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
234 if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
235 return -1;
237 tvnow.tv_sec = ts.tv_sec;
238 tvnow.tv_usec = ts.tv_nsec / 1000;
239 timeradd(tv, &tvnow, &tvsum);
240 #else
241 if (gettimeofday(&tvnow, NULL) < 0)
242 return -1;
243 timeradd(tv, &tvnow, &tvsum);
244 #endif /* HAVE_CLOCK_GETTIME, CLOCK_MONOTONIC */
246 ts.tv_sec = tvsum.tv_sec;
247 ts.tv_nsec = tvsum.tv_usec * 1000;
249 r = pthread_cond_timedwait(&cond->cond, &mutex->mutex, &ts);
250 if (r == 0)
251 return 0;
252 else if (r == ETIMEDOUT)
253 return 1;
254 else if (r == EINTR)
255 continue;
256 else
257 return -1;
261 /** Wake up one of the waiters on <b>cond</b>. */
262 void
263 tor_cond_signal_one(tor_cond_t *cond)
265 pthread_cond_signal(&cond->cond);
267 /** Wake up all of the waiters on <b>cond</b>. */
268 void
269 tor_cond_signal_all(tor_cond_t *cond)
271 pthread_cond_broadcast(&cond->cond);
274 /** Set up common structures for use by threading. */
275 void
276 tor_threads_init(void)
278 if (!threads_initialized) {
279 int ret;
280 pthread_mutexattr_init(&attr_recursive);
281 pthread_mutexattr_settype(&attr_recursive, PTHREAD_MUTEX_RECURSIVE);
282 ret = pthread_attr_init(&attr_detached);
283 tor_assert(ret == 0);
284 #ifndef PTHREAD_CREATE_DETACHED
285 #define PTHREAD_CREATE_DETACHED 1
286 #endif
287 ret = pthread_attr_setdetachstate(&attr_detached, PTHREAD_CREATE_DETACHED);
288 tor_assert(ret == 0);
289 threads_initialized = 1;
290 set_main_thread();