Rizin
unix-like reverse engineering framework and cli tools
mythread.h
Go to the documentation of this file.
1 //
5 //
6 // Author: Lasse Collin
7 //
8 // This file has been put into the public domain.
9 // You can do whatever you want with this file.
10 //
12 
13 #ifndef MYTHREAD_H
14 #define MYTHREAD_H
15 
16 #include "sysdefs.h"
17 
18 // If any type of threading is enabled, #define MYTHREAD_ENABLED.
19 #if defined(MYTHREAD_POSIX) || defined(MYTHREAD_WIN95) \
20  || defined(MYTHREAD_VISTA)
21 # define MYTHREAD_ENABLED 1
22 #endif
23 
24 
25 #ifdef MYTHREAD_ENABLED
26 
28 // Shared between all threading types //
30 
31 // Locks a mutex for a duration of a block.
32 //
33 // Perform mythread_mutex_lock(&mutex) in the beginning of a block
34 // and mythread_mutex_unlock(&mutex) at the end of the block. "break"
35 // may be used to unlock the mutex and jump out of the block.
36 // mythread_sync blocks may be nested.
37 //
38 // Example:
39 //
40 // mythread_sync(mutex) {
41 // foo();
42 // if (some_error)
43 // break; // Skips bar()
44 // bar();
45 // }
46 //
47 // At least GCC optimizes the loops completely away so it doesn't slow
48 // things down at all compared to plain mythread_mutex_lock(&mutex)
49 // and mythread_mutex_unlock(&mutex) calls.
50 //
51 #define mythread_sync(mutex) mythread_sync_helper1(mutex, __LINE__)
52 #define mythread_sync_helper1(mutex, line) mythread_sync_helper2(mutex, line)
53 #define mythread_sync_helper2(mutex, line) \
54  for (unsigned int mythread_i_ ## line = 0; \
55  mythread_i_ ## line \
56  ? (mythread_mutex_unlock(&(mutex)), 0) \
57  : (mythread_mutex_lock(&(mutex)), 1); \
58  mythread_i_ ## line = 1) \
59  for (unsigned int mythread_j_ ## line = 0; \
60  !mythread_j_ ## line; \
61  mythread_j_ ## line = 1)
62 #endif
63 
64 
65 #if !defined(MYTHREAD_ENABLED)
66 
68 // No threading //
70 
71 // Calls the given function once. This isn't thread safe.
72 #define mythread_once(func) \
73 do { \
74  static bool once_ = false; \
75  if (!once_) { \
76  func(); \
77  once_ = true; \
78  } \
79 } while (0)
80 
81 
82 #if !(defined(_WIN32) && !defined(__CYGWIN__))
83 // Use sigprocmask() to set the signal mask in single-threaded programs.
84 #include <signal.h>
85 
86 static inline void
87 mythread_sigmask(int how, const sigset_t *restrict set,
88  sigset_t *restrict oset)
89 {
90  int ret = sigprocmask(how, set, oset);
91  assert(ret == 0);
92  (void)ret;
93 }
94 #endif
95 
96 
97 #elif defined(MYTHREAD_POSIX)
98 
100 // Using pthreads //
102 
103 #include <sys/time.h>
104 #include <pthread.h>
105 #include <signal.h>
106 #include <time.h>
107 #include <errno.h>
108 
109 #define MYTHREAD_RET_TYPE void *
110 #define MYTHREAD_RET_VALUE NULL
111 
112 typedef pthread_t mythread;
113 typedef pthread_mutex_t mythread_mutex;
114 
115 typedef struct {
116  pthread_cond_t cond;
117 #ifdef HAVE_CLOCK_GETTIME
118  // Clock ID (CLOCK_REALTIME or CLOCK_MONOTONIC) associated with
119  // the condition variable.
120  clockid_t clk_id;
121 #endif
122 } mythread_cond;
123 
124 typedef struct timespec mythread_condtime;
125 
126 
127 // Calls the given function once in a thread-safe way.
128 #define mythread_once(func) \
129  do { \
130  static pthread_once_t once_ = PTHREAD_ONCE_INIT; \
131  pthread_once(&once_, &func); \
132  } while (0)
133 
134 
135 // Use pthread_sigmask() to set the signal mask in multi-threaded programs.
136 // Do nothing on OpenVMS since it lacks pthread_sigmask().
137 static inline void
138 mythread_sigmask(int how, const sigset_t *restrict set,
139  sigset_t *restrict oset)
140 {
141 #ifdef __VMS
142  (void)how;
143  (void)set;
144  (void)oset;
145 #else
146  int ret = pthread_sigmask(how, set, oset);
147  assert(ret == 0);
148  (void)ret;
149 #endif
150 }
151 
152 
153 // Creates a new thread with all signals blocked. Returns zero on success
154 // and non-zero on error.
155 static inline int
156 mythread_create(mythread *thread, void *(*func)(void *arg), void *arg)
157 {
158  sigset_t old;
159  sigset_t all;
160  sigfillset(&all);
161 
162  mythread_sigmask(SIG_SETMASK, &all, &old);
163  const int ret = pthread_create(thread, NULL, func, arg);
164  mythread_sigmask(SIG_SETMASK, &old, NULL);
165 
166  return ret;
167 }
168 
169 // Joins a thread. Returns zero on success and non-zero on error.
170 static inline int
171 mythread_join(mythread thread)
172 {
173  return pthread_join(thread, NULL);
174 }
175 
176 
177 // Initiatlizes a mutex. Returns zero on success and non-zero on error.
178 static inline int
179 mythread_mutex_init(mythread_mutex *mutex)
180 {
181  return pthread_mutex_init(mutex, NULL);
182 }
183 
184 static inline void
185 mythread_mutex_destroy(mythread_mutex *mutex)
186 {
187  int ret = pthread_mutex_destroy(mutex);
188  assert(ret == 0);
189  (void)ret;
190 }
191 
192 static inline void
193 mythread_mutex_lock(mythread_mutex *mutex)
194 {
195  int ret = pthread_mutex_lock(mutex);
196  assert(ret == 0);
197  (void)ret;
198 }
199 
200 static inline void
201 mythread_mutex_unlock(mythread_mutex *mutex)
202 {
203  int ret = pthread_mutex_unlock(mutex);
204  assert(ret == 0);
205  (void)ret;
206 }
207 
208 
209 // Initializes a condition variable.
210 //
211 // Using CLOCK_MONOTONIC instead of the default CLOCK_REALTIME makes the
212 // timeout in pthread_cond_timedwait() work correctly also if system time
213 // is suddenly changed. Unfortunately CLOCK_MONOTONIC isn't available
214 // everywhere while the default CLOCK_REALTIME is, so the default is
215 // used if CLOCK_MONOTONIC isn't available.
216 //
217 // If clock_gettime() isn't available at all, gettimeofday() will be used.
218 static inline int
219 mythread_cond_init(mythread_cond *mycond)
220 {
221 #ifdef HAVE_CLOCK_GETTIME
222  // NOTE: HAVE_DECL_CLOCK_MONOTONIC is always defined to 0 or 1.
223 # if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && HAVE_DECL_CLOCK_MONOTONIC
224  struct timespec ts;
225  pthread_condattr_t condattr;
226 
227  // POSIX doesn't seem to *require* that pthread_condattr_setclock()
228  // will fail if given an unsupported clock ID. Test that
229  // CLOCK_MONOTONIC really is supported using clock_gettime().
230  if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0
231  && pthread_condattr_init(&condattr) == 0) {
232  int ret = pthread_condattr_setclock(
233  &condattr, CLOCK_MONOTONIC);
234  if (ret == 0)
235  ret = pthread_cond_init(&mycond->cond, &condattr);
236 
237  pthread_condattr_destroy(&condattr);
238 
239  if (ret == 0) {
240  mycond->clk_id = CLOCK_MONOTONIC;
241  return 0;
242  }
243  }
244 
245  // If anything above fails, fall back to the default CLOCK_REALTIME.
246  // POSIX requires that all implementations of clock_gettime() must
247  // support at least CLOCK_REALTIME.
248 # endif
249 
250  mycond->clk_id = CLOCK_REALTIME;
251 #endif
252 
253  return pthread_cond_init(&mycond->cond, NULL);
254 }
255 
256 static inline void
257 mythread_cond_destroy(mythread_cond *cond)
258 {
259  int ret = pthread_cond_destroy(&cond->cond);
260  assert(ret == 0);
261  (void)ret;
262 }
263 
264 static inline void
265 mythread_cond_signal(mythread_cond *cond)
266 {
267  int ret = pthread_cond_signal(&cond->cond);
268  assert(ret == 0);
269  (void)ret;
270 }
271 
272 static inline void
273 mythread_cond_wait(mythread_cond *cond, mythread_mutex *mutex)
274 {
275  int ret = pthread_cond_wait(&cond->cond, mutex);
276  assert(ret == 0);
277  (void)ret;
278 }
279 
280 // Waits on a condition or until a timeout expires. If the timeout expires,
281 // non-zero is returned, otherwise zero is returned.
282 static inline int
283 mythread_cond_timedwait(mythread_cond *cond, mythread_mutex *mutex,
284  const mythread_condtime *condtime)
285 {
286  int ret = pthread_cond_timedwait(&cond->cond, mutex, condtime);
287  assert(ret == 0 || ret == ETIMEDOUT);
288  return ret;
289 }
290 
291 // Sets condtime to the absolute time that is timeout_ms milliseconds
292 // in the future. The type of the clock to use is taken from cond.
293 static inline void
294 mythread_condtime_set(mythread_condtime *condtime, const mythread_cond *cond,
295  uint32_t timeout_ms)
296 {
297  condtime->tv_sec = timeout_ms / 1000;
298  condtime->tv_nsec = (timeout_ms % 1000) * 1000000;
299 
300 #ifdef HAVE_CLOCK_GETTIME
301  struct timespec now;
302  int ret = clock_gettime(cond->clk_id, &now);
303  assert(ret == 0);
304  (void)ret;
305 
306  condtime->tv_sec += now.tv_sec;
307  condtime->tv_nsec += now.tv_nsec;
308 #else
309  (void)cond;
310 
311  struct timeval now;
312  gettimeofday(&now, NULL);
313 
314  condtime->tv_sec += now.tv_sec;
315  condtime->tv_nsec += now.tv_usec * 1000L;
316 #endif
317 
318  // tv_nsec must stay in the range [0, 999_999_999].
319  if (condtime->tv_nsec >= 1000000000L) {
320  condtime->tv_nsec -= 1000000000L;
321  ++condtime->tv_sec;
322  }
323 }
324 
325 
326 #elif defined(MYTHREAD_WIN95) || defined(MYTHREAD_VISTA)
327 
329 // Windows threads //
331 
332 #define WIN32_LEAN_AND_MEAN
333 #ifdef MYTHREAD_VISTA
334 # undef _WIN32_WINNT
335 # define _WIN32_WINNT 0x0600
336 #endif
337 #include <windows.h>
338 #include <process.h>
339 
340 #define MYTHREAD_RET_TYPE unsigned int __stdcall
341 #define MYTHREAD_RET_VALUE 0
342 
343 typedef HANDLE mythread;
344 typedef CRITICAL_SECTION mythread_mutex;
345 
346 #ifdef MYTHREAD_WIN95
347 typedef HANDLE mythread_cond;
348 #else
349 typedef CONDITION_VARIABLE mythread_cond;
350 #endif
351 
352 typedef struct {
353  // Tick count (milliseconds) in the beginning of the timeout.
354  // NOTE: This is 32 bits so it wraps around after 49.7 days.
355  // Multi-day timeouts may not work as expected.
356  DWORD start;
357 
358  // Length of the timeout in milliseconds. The timeout expires
359  // when the current tick count minus "start" is equal or greater
360  // than "timeout".
361  DWORD timeout;
362 } mythread_condtime;
363 
364 
365 // mythread_once() is only available with Vista threads.
366 #ifdef MYTHREAD_VISTA
367 #define mythread_once(func) \
368  do { \
369  static INIT_ONCE once_ = INIT_ONCE_STATIC_INIT; \
370  BOOL pending_; \
371  if (!InitOnceBeginInitialize(&once_, 0, &pending_, NULL)) \
372  abort(); \
373  if (pending_) \
374  func(); \
375  if (!InitOnceComplete(&once, 0, NULL)) \
376  abort(); \
377  } while (0)
378 #endif
379 
380 
381 // mythread_sigmask() isn't available on Windows. Even a dummy version would
382 // make no sense because the other POSIX signal functions are missing anyway.
383 
384 
385 static inline int
386 mythread_create(mythread *thread,
387  unsigned int (__stdcall *func)(void *arg), void *arg)
388 {
389  uintptr_t ret = _beginthreadex(NULL, 0, func, arg, 0, NULL);
390  if (ret == 0)
391  return -1;
392 
393  *thread = (HANDLE)ret;
394  return 0;
395 }
396 
397 static inline int
398 mythread_join(mythread thread)
399 {
400  int ret = 0;
401 
402  if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0)
403  ret = -1;
404 
405  if (!CloseHandle(thread))
406  ret = -1;
407 
408  return ret;
409 }
410 
411 
412 static inline int
413 mythread_mutex_init(mythread_mutex *mutex)
414 {
415  InitializeCriticalSection(mutex);
416  return 0;
417 }
418 
419 static inline void
420 mythread_mutex_destroy(mythread_mutex *mutex)
421 {
422  DeleteCriticalSection(mutex);
423 }
424 
425 static inline void
426 mythread_mutex_lock(mythread_mutex *mutex)
427 {
428  EnterCriticalSection(mutex);
429 }
430 
431 static inline void
432 mythread_mutex_unlock(mythread_mutex *mutex)
433 {
434  LeaveCriticalSection(mutex);
435 }
436 
437 
438 static inline int
439 mythread_cond_init(mythread_cond *cond)
440 {
441 #ifdef MYTHREAD_WIN95
442  *cond = CreateEvent(NULL, FALSE, FALSE, NULL);
443  return *cond == NULL ? -1 : 0;
444 #else
445  InitializeConditionVariable(cond);
446  return 0;
447 #endif
448 }
449 
450 static inline void
451 mythread_cond_destroy(mythread_cond *cond)
452 {
453 #ifdef MYTHREAD_WIN95
454  CloseHandle(*cond);
455 #else
456  (void)cond;
457 #endif
458 }
459 
460 static inline void
461 mythread_cond_signal(mythread_cond *cond)
462 {
463 #ifdef MYTHREAD_WIN95
464  SetEvent(*cond);
465 #else
466  WakeConditionVariable(cond);
467 #endif
468 }
469 
470 static inline void
471 mythread_cond_wait(mythread_cond *cond, mythread_mutex *mutex)
472 {
473 #ifdef MYTHREAD_WIN95
474  LeaveCriticalSection(mutex);
475  WaitForSingleObject(*cond, INFINITE);
476  EnterCriticalSection(mutex);
477 #else
478  BOOL ret = SleepConditionVariableCS(cond, mutex, INFINITE);
479  assert(ret);
480  (void)ret;
481 #endif
482 }
483 
484 static inline int
485 mythread_cond_timedwait(mythread_cond *cond, mythread_mutex *mutex,
486  const mythread_condtime *condtime)
487 {
488 #ifdef MYTHREAD_WIN95
489  LeaveCriticalSection(mutex);
490 #endif
491 
492  DWORD elapsed = GetTickCount() - condtime->start;
493  DWORD timeout = elapsed >= condtime->timeout
494  ? 0 : condtime->timeout - elapsed;
495 
496 #ifdef MYTHREAD_WIN95
497  DWORD ret = WaitForSingleObject(*cond, timeout);
498  assert(ret == WAIT_OBJECT_0 || ret == WAIT_TIMEOUT);
499 
500  EnterCriticalSection(mutex);
501 
502  return ret == WAIT_TIMEOUT;
503 #else
504  BOOL ret = SleepConditionVariableCS(cond, mutex, timeout);
505  assert(ret || GetLastError() == ERROR_TIMEOUT);
506  return !ret;
507 #endif
508 }
509 
510 static inline void
511 mythread_condtime_set(mythread_condtime *condtime, const mythread_cond *cond,
513 {
514  (void)cond;
515  condtime->start = GetTickCount();
516  condtime->timeout = timeout;
517 }
518 
519 #endif
520 
521 #endif
#define NULL
Definition: cris-opc.c:27
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset struct stat static buf void long static basep static whence static length const void static len static semflg const void static shmflg const struct timespec struct timespec static rem const char static group const void start
Definition: sflib.h:133
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog gettimeofday
Definition: sflib.h:79
#define restrict
assert(limit<=UINT32_MAX/2)
#define FALSE
Definition: mybfd.h:102
static void mythread_sigmask(int how, const sigset_t *restrict set, sigset_t *restrict oset)
Definition: mythread.h:87
unsigned int uint32_t
Definition: sftypes.h:29
#define ETIMEDOUT
Definition: sftypes.h:170
int sigset_t
Definition: sftypes.h:63
#define cond(bop, top, mask, flags)
_W64 unsigned int uintptr_t
uv_timer_t timeout
Definition: main.c:9
Common includes, definitions, system-specific things etc.
static uv_mutex_t mutex
Definition: threadpool.c:34
PVOID CONDITION_VARIABLE
Definition: win.h:203
DWORD * HANDLE
DWORD