1 ///////////////////////////////////////////////////////////////////////////////
4 /// \brief Some threading related helper macros and functions
6 // Author: Lasse Collin
8 // This file has been put into the public domain.
9 // You can do whatever you want with this file.
11 ///////////////////////////////////////////////////////////////////////////////
16 #ifndef _POSIX_C_SOURCE
17 #define _POSIX_C_SOURCE 199309L
22 // If any type of threading is enabled, #define MYTHREAD_ENABLED.
23 #if defined(MYTHREAD_POSIX) || defined(MYTHREAD_WIN95) \
24 || defined(MYTHREAD_VISTA)
25 # define MYTHREAD_ENABLED 1
28 #ifdef MYTHREAD_ENABLED
30 ////////////////////////////////////////
31 // Shared between all threading types //
32 ////////////////////////////////////////
34 // Locks a mutex for a duration of a block.
36 // Perform mythread_mutex_lock(&mutex) in the beginning of a block
37 // and mythread_mutex_unlock(&mutex) at the end of the block. "break"
38 // may be used to unlock the mutex and jump out of the block.
39 // mythread_sync blocks may be nested.
43 // mythread_sync(mutex) {
46 // break; // Skips bar()
50 // At least GCC optimizes the loops completely away so it doesn't slow
51 // things down at all compared to plain mythread_mutex_lock(&mutex)
52 // and mythread_mutex_unlock(&mutex) calls.
54 #define mythread_sync(mutex) mythread_sync_helper1(mutex, __LINE__)
55 #define mythread_sync_helper1(mutex, line) mythread_sync_helper2(mutex, line)
56 #define mythread_sync_helper2(mutex, line) \
57 for (unsigned int mythread_i_ ## line = 0; \
59 ? (mythread_mutex_unlock(&(mutex)), 0) \
60 : (mythread_mutex_lock(&(mutex)), 1); \
61 mythread_i_ ## line = 1) \
62 for (unsigned int mythread_j_ ## line = 0; \
63 !mythread_j_ ## line; \
64 mythread_j_ ## line = 1)
68 #if !defined(MYTHREAD_ENABLED)
74 // Calls the given function once. This isn't thread safe.
75 #define mythread_once(func) \
77 static bool once_ = false; \
85 #if !(defined(_WIN32) && !defined(__CYGWIN__))
86 // Use sigprocmask() to set the signal mask in single-threaded programs.
90 mythread_sigmask(int how, const sigset_t *restrict set,
91 sigset_t *restrict oset)
93 int ret = sigprocmask(how, set, oset);
100 #elif defined(MYTHREAD_POSIX)
106 #include <sys/time.h>
112 #define MYTHREAD_RET_TYPE void *
113 #define MYTHREAD_RET_VALUE NULL
115 typedef pthread_t mythread;
116 typedef pthread_mutex_t mythread_mutex;
120 #ifdef HAVE_CLOCK_GETTIME
121 // Clock ID (CLOCK_REALTIME or CLOCK_MONOTONIC) associated with
122 // the condition variable.
127 typedef struct timespec mythread_condtime;
130 // Calls the given function once in a thread-safe way.
131 #define mythread_once(func) \
133 static pthread_once_t once_ = PTHREAD_ONCE_INIT; \
134 pthread_once(&once_, &func); \
138 // Use pthread_sigmask() to set the signal mask in multi-threaded programs.
139 // Do nothing on OpenVMS since it lacks pthread_sigmask().
141 mythread_sigmask(int how, const sigset_t *restrict set,
142 sigset_t *restrict oset)
149 int ret = pthread_sigmask(how, set, oset);
156 // Creates a new thread with all signals blocked. Returns zero on success
157 // and non-zero on error.
159 mythread_create(mythread *thread, void *(*func)(void *arg), void *arg)
165 mythread_sigmask(SIG_SETMASK, &all, &old);
166 const int ret = pthread_create(thread, NULL, func, arg);
167 mythread_sigmask(SIG_SETMASK, &old, NULL);
172 // Joins a thread. Returns zero on success and non-zero on error.
174 mythread_join(mythread thread)
176 return pthread_join(thread, NULL);
180 // Initiatlizes a mutex. Returns zero on success and non-zero on error.
182 mythread_mutex_init(mythread_mutex *mutex)
184 return pthread_mutex_init(mutex, NULL);
188 mythread_mutex_destroy(mythread_mutex *mutex)
190 int ret = pthread_mutex_destroy(mutex);
196 mythread_mutex_lock(mythread_mutex *mutex)
198 int ret = pthread_mutex_lock(mutex);
204 mythread_mutex_unlock(mythread_mutex *mutex)
206 int ret = pthread_mutex_unlock(mutex);
212 // Initializes a condition variable.
214 // Using CLOCK_MONOTONIC instead of the default CLOCK_REALTIME makes the
215 // timeout in pthread_cond_timedwait() work correctly also if system time
216 // is suddenly changed. Unfortunately CLOCK_MONOTONIC isn't available
217 // everywhere while the default CLOCK_REALTIME is, so the default is
218 // used if CLOCK_MONOTONIC isn't available.
220 // If clock_gettime() isn't available at all, gettimeofday() will be used.
222 mythread_cond_init(mythread_cond *mycond)
224 #ifdef HAVE_CLOCK_GETTIME
225 // NOTE: HAVE_DECL_CLOCK_MONOTONIC is always defined to 0 or 1.
226 # if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && HAVE_DECL_CLOCK_MONOTONIC
228 pthread_condattr_t condattr;
230 // POSIX doesn't seem to *require* that pthread_condattr_setclock()
231 // will fail if given an unsupported clock ID. Test that
232 // CLOCK_MONOTONIC really is supported using clock_gettime().
233 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0
234 && pthread_condattr_init(&condattr) == 0) {
235 int ret = pthread_condattr_setclock(
236 &condattr, CLOCK_MONOTONIC);
238 ret = pthread_cond_init(&mycond->cond, &condattr);
240 pthread_condattr_destroy(&condattr);
243 mycond->clk_id = CLOCK_MONOTONIC;
248 // If anything above fails, fall back to the default CLOCK_REALTIME.
249 // POSIX requires that all implementations of clock_gettime() must
250 // support at least CLOCK_REALTIME.
253 mycond->clk_id = CLOCK_REALTIME;
256 return pthread_cond_init(&mycond->cond, NULL);
260 mythread_cond_destroy(mythread_cond *cond)
262 int ret = pthread_cond_destroy(&cond->cond);
268 mythread_cond_signal(mythread_cond *cond)
270 int ret = pthread_cond_signal(&cond->cond);
276 mythread_cond_wait(mythread_cond *cond, mythread_mutex *mutex)
278 int ret = pthread_cond_wait(&cond->cond, mutex);
283 // Waits on a condition or until a timeout expires. If the timeout expires,
284 // non-zero is returned, otherwise zero is returned.
286 mythread_cond_timedwait(mythread_cond *cond, mythread_mutex *mutex,
287 const mythread_condtime *condtime)
289 int ret = pthread_cond_timedwait(&cond->cond, mutex, condtime);
290 assert(ret == 0 || ret == ETIMEDOUT);
294 // Sets condtime to the absolute time that is timeout_ms milliseconds
295 // in the future. The type of the clock to use is taken from cond.
297 mythread_condtime_set(mythread_condtime *condtime, const mythread_cond *cond,
300 condtime->tv_sec = timeout_ms / 1000;
301 condtime->tv_nsec = (timeout_ms % 1000) * 1000000;
303 #ifdef HAVE_CLOCK_GETTIME
305 int ret = clock_gettime(cond->clk_id, &now);
309 condtime->tv_sec += now.tv_sec;
310 condtime->tv_nsec += now.tv_nsec;
315 gettimeofday(&now, NULL);
317 condtime->tv_sec += now.tv_sec;
318 condtime->tv_nsec += now.tv_usec * 1000L;
321 // tv_nsec must stay in the range [0, 999_999_999].
322 if (condtime->tv_nsec >= 1000000000L) {
323 condtime->tv_nsec -= 1000000000L;
329 #elif defined(MYTHREAD_WIN95) || defined(MYTHREAD_VISTA)
331 /////////////////////
332 // Windows threads //
333 /////////////////////
335 #define WIN32_LEAN_AND_MEAN
336 #ifdef MYTHREAD_VISTA
338 # define _WIN32_WINNT 0x0600
343 #define MYTHREAD_RET_TYPE unsigned int __stdcall
344 #define MYTHREAD_RET_VALUE 0
346 typedef HANDLE mythread;
347 typedef CRITICAL_SECTION mythread_mutex;
349 #ifdef MYTHREAD_WIN95
350 typedef HANDLE mythread_cond;
352 typedef CONDITION_VARIABLE mythread_cond;
356 // Tick count (milliseconds) in the beginning of the timeout.
357 // NOTE: This is 32 bits so it wraps around after 49.7 days.
358 // Multi-day timeouts may not work as expected.
361 // Length of the timeout in milliseconds. The timeout expires
362 // when the current tick count minus "start" is equal or greater
368 // mythread_once() is only available with Vista threads.
369 #ifdef MYTHREAD_VISTA
370 #define mythread_once(func) \
372 static INIT_ONCE once_ = INIT_ONCE_STATIC_INIT; \
374 if (!InitOnceBeginInitialize(&once_, 0, &pending_, NULL)) \
378 if (!InitOnceComplete(&once, 0, NULL)) \
384 // mythread_sigmask() isn't available on Windows. Even a dummy version would
385 // make no sense because the other POSIX signal functions are missing anyway.
389 mythread_create(mythread *thread,
390 unsigned int (__stdcall *func)(void *arg), void *arg)
392 uintptr_t ret = _beginthreadex(NULL, 0, func, arg, 0, NULL);
396 *thread = (HANDLE)ret;
401 mythread_join(mythread thread)
405 if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0)
408 if (!CloseHandle(thread))
416 mythread_mutex_init(mythread_mutex *mutex)
418 InitializeCriticalSection(mutex);
423 mythread_mutex_destroy(mythread_mutex *mutex)
425 DeleteCriticalSection(mutex);
429 mythread_mutex_lock(mythread_mutex *mutex)
431 EnterCriticalSection(mutex);
435 mythread_mutex_unlock(mythread_mutex *mutex)
437 LeaveCriticalSection(mutex);
442 mythread_cond_init(mythread_cond *cond)
444 #ifdef MYTHREAD_WIN95
445 *cond = CreateEvent(NULL, FALSE, FALSE, NULL);
446 return *cond == NULL ? -1 : 0;
448 InitializeConditionVariable(cond);
454 mythread_cond_destroy(mythread_cond *cond)
456 #ifdef MYTHREAD_WIN95
464 mythread_cond_signal(mythread_cond *cond)
466 #ifdef MYTHREAD_WIN95
469 WakeConditionVariable(cond);
474 mythread_cond_wait(mythread_cond *cond, mythread_mutex *mutex)
476 #ifdef MYTHREAD_WIN95
477 LeaveCriticalSection(mutex);
478 WaitForSingleObject(*cond, INFINITE);
479 EnterCriticalSection(mutex);
481 BOOL ret = SleepConditionVariableCS(cond, mutex, INFINITE);
488 mythread_cond_timedwait(mythread_cond *cond, mythread_mutex *mutex,
489 const mythread_condtime *condtime)
491 #ifdef MYTHREAD_WIN95
492 LeaveCriticalSection(mutex);
495 DWORD elapsed = GetTickCount() - condtime->start;
496 DWORD timeout = elapsed >= condtime->timeout
497 ? 0 : condtime->timeout - elapsed;
499 #ifdef MYTHREAD_WIN95
500 DWORD ret = WaitForSingleObject(*cond, timeout);
501 assert(ret == WAIT_OBJECT_0 || ret == WAIT_TIMEOUT);
503 EnterCriticalSection(mutex);
505 return ret == WAIT_TIMEOUT;
507 BOOL ret = SleepConditionVariableCS(cond, mutex, timeout);
508 assert(ret || GetLastError() == ERROR_TIMEOUT);
514 mythread_condtime_set(mythread_condtime *condtime, const mythread_cond *cond,
518 condtime->start = GetTickCount();
519 condtime->timeout = timeout;