Line data Source code
1 : /* Copyright (c) 2003-2004, Roger Dingledine
2 : * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 : * Copyright (c) 2007-2021, The Tor Project, Inc. */
4 : /* See LICENSE for licensing information */
5 :
6 : /**
7 : * \file compat_pthreads.c
8 : *
9 : * \brief Implementation for the pthreads-based multithreading backend
10 : * functions.
11 : */
12 :
13 : #include "orconfig.h"
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"
18 :
19 : #include <sys/time.h>
20 : #include <pthread.h>
21 : #include <signal.h>
22 : #include <time.h>
23 : #include <errno.h>
24 : #include <string.h>
25 :
26 : /** Wraps a void (*)(void*) function and its argument so we can
27 : * invoke them in a way pthreads would expect.
28 : */
29 : typedef struct tor_pthread_data_t {
30 : void (*func)(void *);
31 : void *data;
32 : } 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
35 : * expects. */
36 : static void *
37 66 : tor_pthread_helper_fn(void *_data)
38 : {
39 66 : tor_pthread_data_t *data = _data;
40 66 : void (*func)(void*);
41 66 : void *arg;
42 : /* mask signals to worker threads to avoid SIGPIPE, etc */
43 66 : sigset_t sigs;
44 : /* We're in a subthread; don't handle any signals here. */
45 66 : sigfillset(&sigs);
46 66 : pthread_sigmask(SIG_SETMASK, &sigs, NULL);
47 :
48 66 : func = data->func;
49 66 : arg = data->data;
50 66 : tor_free(_data);
51 66 : func(arg);
52 50 : return NULL;
53 : }
54 : /**
55 : * A pthread attribute to make threads start detached.
56 : */
57 : static pthread_attr_t attr_detached;
58 : /** True iff we've called tor_threads_init() */
59 : static int threads_initialized = 0;
60 :
61 : /** Minimalist interface to run a void function in the background. On
62 : * Unix calls pthread_create, on win32 calls beginthread. Returns -1 on
63 : * failure.
64 : * func should not return, but rather should call spawn_exit.
65 : *
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
69 : * running.
70 : */
71 : int
72 66 : spawn_func(void (*func)(void *), void *data)
73 : {
74 66 : pthread_t thread;
75 66 : tor_pthread_data_t *d;
76 66 : if (PREDICT_UNLIKELY(!threads_initialized)) {
77 7 : tor_threads_init();
78 : }
79 66 : d = tor_malloc(sizeof(tor_pthread_data_t));
80 66 : d->data = data;
81 66 : d->func = func;
82 66 : if (pthread_create(&thread, &attr_detached, tor_pthread_helper_fn, d)) {
83 0 : tor_free(d);
84 0 : return -1;
85 : }
86 :
87 : return 0;
88 : }
89 :
90 : /** End the current thread/process.
91 : */
92 : void
93 10 : spawn_exit(void)
94 : {
95 10 : pthread_exit(NULL);
96 : }
97 :
98 : /** Return an integer representing this thread. */
99 : unsigned long
100 5602 : tor_get_thread_id(void)
101 : {
102 5602 : union {
103 : pthread_t thr;
104 : unsigned long id;
105 : } r;
106 5602 : r.thr = pthread_self();
107 5602 : return r.id;
108 : }
109 :
110 : /* Conditions. */
111 :
112 : /** Initialize an already-allocated condition variable. */
113 : int
114 9 : tor_cond_init(tor_cond_t *cond)
115 : {
116 9 : pthread_condattr_t condattr;
117 :
118 9 : 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 9 : if (pthread_condattr_init(&condattr)) {
122 : return -1;
123 : }
124 :
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 9 : if (pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC)) {
131 : return -1;
132 : }
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.
137 : */
138 : #define USE_COND_CLOCK CLOCK_REALTIME
139 : #endif /* defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && ... */
140 : #endif /* defined(HAVE_CLOCK_GETTIME) */
141 9 : if (pthread_cond_init(&cond->cond, &condattr)) {
142 0 : return -1;
143 : }
144 : return 0;
145 : }
146 :
147 : /** Release all resources held by <b>cond</b>, but do not free <b>cond</b>
148 : * itself. */
149 : void
150 2 : tor_cond_uninit(tor_cond_t *cond)
151 : {
152 2 : if (pthread_cond_destroy(&cond->cond)) {
153 : // LCOV_EXCL_START
154 : log_warn(LD_GENERAL,"Error freeing condition: %s", strerror(errno));
155 : return;
156 : // LCOV_EXCL_STOP
157 : }
158 : }
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().
164 : *
165 : * Returns 0 on success, -1 on failure, 1 on timeout. */
166 : int
167 244 : tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex, const struct timeval *tv)
168 : {
169 244 : int r;
170 244 : if (tv == NULL) {
171 235 : while (1) {
172 235 : r = pthread_cond_wait(&cond->cond, &mutex->mutex);
173 235 : if (r == EINTR) {
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
178 : }
179 235 : return r ? -1 : 0;
180 : }
181 : } else {
182 9 : struct timeval tvnow, tvsum;
183 9 : struct timespec ts;
184 9 : while (1) {
185 : #if defined(HAVE_CLOCK_GETTIME) && defined(USE_COND_CLOCK)
186 9 : if (clock_gettime(USE_COND_CLOCK, &ts) < 0) {
187 : return -1;
188 : }
189 9 : tvnow.tv_sec = ts.tv_sec;
190 9 : tvnow.tv_usec = (int)(ts.tv_nsec / 1000);
191 9 : timeradd(tv, &tvnow, &tvsum);
192 : #else /* !(defined(HAVE_CLOCK_GETTIME) && defined(USE_COND_CLOCK)) */
193 : if (gettimeofday(&tvnow, NULL) < 0)
194 : return -1;
195 : timeradd(tv, &tvnow, &tvsum);
196 : #endif /* defined(HAVE_CLOCK_GETTIME) && defined(USE_COND_CLOCK) */
197 :
198 9 : ts.tv_sec = tvsum.tv_sec;
199 9 : ts.tv_nsec = tvsum.tv_usec * 1000;
200 :
201 9 : r = pthread_cond_timedwait(&cond->cond, &mutex->mutex, &ts);
202 9 : if (r == 0)
203 : return 0;
204 2 : else if (r == ETIMEDOUT)
205 : return 1;
206 0 : else if (r == EINTR)
207 0 : continue;
208 : else
209 : return -1;
210 : }
211 : }
212 : }
213 : /** Wake up one of the waiters on <b>cond</b>. */
214 : void
215 70011 : tor_cond_signal_one(tor_cond_t *cond)
216 : {
217 70011 : pthread_cond_signal(&cond->cond);
218 70011 : }
219 : /** Wake up all of the waiters on <b>cond</b>. */
220 : void
221 11 : tor_cond_signal_all(tor_cond_t *cond)
222 : {
223 11 : pthread_cond_broadcast(&cond->cond);
224 11 : }
225 :
226 : int
227 5575 : tor_threadlocal_init(tor_threadlocal_t *threadlocal)
228 : {
229 5575 : int err = pthread_key_create(&threadlocal->key, NULL);
230 5575 : return err ? -1 : 0;
231 : }
232 :
233 : void
234 235 : tor_threadlocal_destroy(tor_threadlocal_t *threadlocal)
235 : {
236 235 : pthread_key_delete(threadlocal->key);
237 235 : memset(threadlocal, 0, sizeof(tor_threadlocal_t));
238 235 : }
239 :
240 : void *
241 12695047 : tor_threadlocal_get(tor_threadlocal_t *threadlocal)
242 : {
243 12695047 : return pthread_getspecific(threadlocal->key);
244 : }
245 :
246 : void
247 207 : tor_threadlocal_set(tor_threadlocal_t *threadlocal, void *value)
248 : {
249 207 : int err = pthread_setspecific(threadlocal->key, value);
250 207 : tor_assert(err == 0);
251 207 : }
252 :
253 : /** Set up common structures for use by threading. */
254 : void
255 5560 : tor_threads_init(void)
256 : {
257 5560 : if (!threads_initialized) {
258 5560 : tor_locking_init();
259 5560 : const int ret1 = pthread_attr_init(&attr_detached);
260 5560 : tor_assert(ret1 == 0);
261 : #ifndef PTHREAD_CREATE_DETACHED
262 : #define PTHREAD_CREATE_DETACHED 1
263 : #endif
264 5560 : const int ret2 =
265 5560 : pthread_attr_setdetachstate(&attr_detached, PTHREAD_CREATE_DETACHED);
266 5560 : tor_assert(ret2 == 0);
267 5560 : threads_initialized = 1;
268 : }
269 5560 : set_main_thread();
270 5560 : }
|