1 /* Copyright (c) 2003-2004, Roger Dingledine
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2019, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
7 * \file compat_pthreads.c
9 * \brief Implementation for the pthreads-based multithreading backend
14 #include "lib/thread/threads.h"
15 #include "lib/wallclock/timeval.h"
16 #include "lib/log/log.h"
17 #include "lib/log/util_bug.h"
26 /** Wraps a void (*)(void*) function and its argument so we can
27 * invoke them in a way pthreads would expect.
29 typedef struct tor_pthread_data_t
{
33 /** Given a tor_pthread_data_t <b>_data</b>, call _data->func(d->data)
34 * and free _data. Used to make sure we can call functions the way pthread
37 tor_pthread_helper_fn(void *_data
)
39 tor_pthread_data_t
*data
= _data
;
42 /* mask signals to worker threads to avoid SIGPIPE, etc */
44 /* We're in a subthread; don't handle any signals here. */
46 pthread_sigmask(SIG_SETMASK
, &sigs
, NULL
);
55 * A pthread attribute to make threads start detached.
57 static pthread_attr_t attr_detached
;
58 /** True iff we've called tor_threads_init() */
59 static int threads_initialized
= 0;
61 /** Minimalist interface to run a void function in the background. On
62 * Unix calls pthread_create, on win32 calls beginthread. Returns -1 on
64 * func should not return, but rather should call spawn_exit.
66 * NOTE: if <b>data</b> is used, it should not be allocated on the stack,
67 * since in a multithreaded environment, there is no way to be sure that
68 * the caller's stack will still be around when the called function is
72 spawn_func(void (*func
)(void *), void *data
)
75 tor_pthread_data_t
*d
;
76 if (PREDICT_UNLIKELY(!threads_initialized
)) {
79 d
= tor_malloc(sizeof(tor_pthread_data_t
));
82 if (pthread_create(&thread
, &attr_detached
, tor_pthread_helper_fn
, d
)) {
90 /** End the current thread/process.
98 /** Return an integer representing this thread. */
100 tor_get_thread_id(void)
106 r
.thr
= pthread_self();
112 /** Initialize an already-allocated condition variable. */
114 tor_cond_init(tor_cond_t
*cond
)
116 pthread_condattr_t condattr
;
118 memset(cond
, 0, sizeof(tor_cond_t
));
119 /* Default condition attribute. Might be used if clock monotonic is
120 * available else this won't affect anything. */
121 if (pthread_condattr_init(&condattr
)) {
125 #if defined(HAVE_CLOCK_GETTIME)
126 #if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && \
127 defined(CLOCK_MONOTONIC)
128 /* Use monotonic time so when we timedwait() on it, any clock adjustment
129 * won't affect the timeout value. */
130 if (pthread_condattr_setclock(&condattr
, CLOCK_MONOTONIC
)) {
133 #define USE_COND_CLOCK CLOCK_MONOTONIC
134 #else /* !(defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && ...) */
135 /* On OSX Sierra, there is no pthread_condattr_setclock, so we are stuck
136 * with the realtime clock.
138 #define USE_COND_CLOCK CLOCK_REALTIME
139 #endif /* defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && ... */
140 #endif /* defined(HAVE_CLOCK_GETTIME) */
141 if (pthread_cond_init(&cond
->cond
, &condattr
)) {
147 /** Release all resources held by <b>cond</b>, but do not free <b>cond</b>
150 tor_cond_uninit(tor_cond_t
*cond
)
152 if (pthread_cond_destroy(&cond
->cond
)) {
154 log_warn(LD_GENERAL
,"Error freeing condition: %s", strerror(errno
));
159 /** Wait until one of the tor_cond_signal functions is called on <b>cond</b>.
160 * (If <b>tv</b> is set, and that amount of time passes with no signal to
161 * <b>cond</b>, return anyway. All waiters on the condition must wait holding
162 * the same <b>mutex</b>. All signallers should hold that mutex. The mutex
163 * needs to have been allocated with tor_mutex_init_for_cond().
165 * Returns 0 on success, -1 on failure, 1 on timeout. */
167 tor_cond_wait(tor_cond_t
*cond
, tor_mutex_t
*mutex
, const struct timeval
*tv
)
172 r
= pthread_cond_wait(&cond
->cond
, &mutex
->mutex
);
174 /* EINTR should be impossible according to POSIX, but POSIX, like the
175 * Pirate's Code, is apparently treated "more like what you'd call
176 * guidelines than actual rules." */
177 continue; // LCOV_EXCL_LINE
182 struct timeval tvnow
, tvsum
;
185 #if defined(HAVE_CLOCK_GETTIME) && defined(USE_COND_CLOCK)
186 if (clock_gettime(USE_COND_CLOCK
, &ts
) < 0) {
189 tvnow
.tv_sec
= ts
.tv_sec
;
190 tvnow
.tv_usec
= (int)(ts
.tv_nsec
/ 1000);
191 timeradd(tv
, &tvnow
, &tvsum
);
192 #else /* !(defined(HAVE_CLOCK_GETTIME) && defined(USE_COND_CLOCK)) */
193 if (gettimeofday(&tvnow
, NULL
) < 0)
195 timeradd(tv
, &tvnow
, &tvsum
);
196 #endif /* defined(HAVE_CLOCK_GETTIME) && defined(USE_COND_CLOCK) */
198 ts
.tv_sec
= tvsum
.tv_sec
;
199 ts
.tv_nsec
= tvsum
.tv_usec
* 1000;
201 r
= pthread_cond_timedwait(&cond
->cond
, &mutex
->mutex
, &ts
);
204 else if (r
== ETIMEDOUT
)
213 /** Wake up one of the waiters on <b>cond</b>. */
215 tor_cond_signal_one(tor_cond_t
*cond
)
217 pthread_cond_signal(&cond
->cond
);
219 /** Wake up all of the waiters on <b>cond</b>. */
221 tor_cond_signal_all(tor_cond_t
*cond
)
223 pthread_cond_broadcast(&cond
->cond
);
227 tor_threadlocal_init(tor_threadlocal_t
*threadlocal
)
229 int err
= pthread_key_create(&threadlocal
->key
, NULL
);
234 tor_threadlocal_destroy(tor_threadlocal_t
*threadlocal
)
236 pthread_key_delete(threadlocal
->key
);
237 memset(threadlocal
, 0, sizeof(tor_threadlocal_t
));
241 tor_threadlocal_get(tor_threadlocal_t
*threadlocal
)
243 return pthread_getspecific(threadlocal
->key
);
247 tor_threadlocal_set(tor_threadlocal_t
*threadlocal
, void *value
)
249 int err
= pthread_setspecific(threadlocal
->key
, value
);
250 tor_assert(err
== 0);
253 /** Set up common structures for use by threading. */
255 tor_threads_init(void)
257 if (!threads_initialized
) {
259 const int ret1
= pthread_attr_init(&attr_detached
);
260 tor_assert(ret1
== 0);
261 #ifndef PTHREAD_CREATE_DETACHED
262 #define PTHREAD_CREATE_DETACHED 1
265 pthread_attr_setdetachstate(&attr_detached
, PTHREAD_CREATE_DETACHED
);
266 tor_assert(ret2
== 0);
267 threads_initialized
= 1;