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 ///////////////////////////////////////////////////////////////////////////////
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
25 #ifdef MYTHREAD_ENABLED
27 ////////////////////////////////////////
28 // Shared between all threading types //
29 ////////////////////////////////////////
31 // Locks a mutex for a duration of a block.
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.
40 // mythread_sync(mutex) {
43 // break; // Skips bar()
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.
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; \
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)
65 #if !defined(MYTHREAD_ENABLED)
71 // Calls the given function once. This isn't thread safe.
72 #define mythread_once(func) \
74 static bool once_ = false; \
82 #if !(defined(_WIN32) && !defined(__CYGWIN__))
83 // Use sigprocmask() to set the signal mask in single-threaded programs.
87 mythread_sigmask(int how
, const sigset_t
*restrict set
,
88 sigset_t
*restrict oset
)
90 int ret
= sigprocmask(how
, set
, oset
);
97 #elif defined(MYTHREAD_POSIX)
108 // If clock_gettime() isn't available, use gettimeofday() from <sys/time.h>
109 // as a fallback. gettimeofday() is in SUSv2 and thus is supported on all
110 // relevant POSIX systems.
111 #ifndef HAVE_CLOCK_GETTIME
112 # include <sys/time.h>
115 #define MYTHREAD_RET_TYPE void *
116 #define MYTHREAD_RET_VALUE NULL
118 typedef pthread_t mythread
;
119 typedef pthread_mutex_t mythread_mutex
;
123 #ifdef HAVE_CLOCK_GETTIME
124 // Clock ID (CLOCK_REALTIME or CLOCK_MONOTONIC) associated with
125 // the condition variable.
130 typedef struct timespec mythread_condtime
;
133 // Calls the given function once in a thread-safe way.
134 #define mythread_once(func) \
136 static pthread_once_t once_ = PTHREAD_ONCE_INIT; \
137 pthread_once(&once_, &func); \
141 // Use pthread_sigmask() to set the signal mask in multi-threaded programs.
142 // Do nothing on OpenVMS since it lacks pthread_sigmask().
144 mythread_sigmask(int how
, const sigset_t
*restrict set
,
145 sigset_t
*restrict oset
)
152 int ret
= pthread_sigmask(how
, set
, oset
);
159 // Creates a new thread with all signals blocked. Returns zero on success
160 // and non-zero on error.
162 mythread_create(mythread
*thread
, void *(*func
)(void *arg
), void *arg
)
168 mythread_sigmask(SIG_SETMASK
, &all
, &old
);
169 const int ret
= pthread_create(thread
, NULL
, func
, arg
);
170 mythread_sigmask(SIG_SETMASK
, &old
, NULL
);
175 // Joins a thread. Returns zero on success and non-zero on error.
177 mythread_join(mythread thread
)
179 return pthread_join(thread
, NULL
);
183 // Initiatlizes a mutex. Returns zero on success and non-zero on error.
185 mythread_mutex_init(mythread_mutex
*mutex
)
187 return pthread_mutex_init(mutex
, NULL
);
191 mythread_mutex_destroy(mythread_mutex
*mutex
)
193 int ret
= pthread_mutex_destroy(mutex
);
199 mythread_mutex_lock(mythread_mutex
*mutex
)
201 int ret
= pthread_mutex_lock(mutex
);
207 mythread_mutex_unlock(mythread_mutex
*mutex
)
209 int ret
= pthread_mutex_unlock(mutex
);
215 // Initializes a condition variable.
217 // Using CLOCK_MONOTONIC instead of the default CLOCK_REALTIME makes the
218 // timeout in pthread_cond_timedwait() work correctly also if system time
219 // is suddenly changed. Unfortunately CLOCK_MONOTONIC isn't available
220 // everywhere while the default CLOCK_REALTIME is, so the default is
221 // used if CLOCK_MONOTONIC isn't available.
223 // If clock_gettime() isn't available at all, gettimeofday() will be used.
225 mythread_cond_init(mythread_cond
*mycond
)
227 #ifdef HAVE_CLOCK_GETTIME
228 # if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && \
229 defined(HAVE_CLOCK_MONOTONIC)
231 pthread_condattr_t condattr
;
233 // POSIX doesn't seem to *require* that pthread_condattr_setclock()
234 // will fail if given an unsupported clock ID. Test that
235 // CLOCK_MONOTONIC really is supported using clock_gettime().
236 if (clock_gettime(CLOCK_MONOTONIC
, &ts
) == 0
237 && pthread_condattr_init(&condattr
) == 0) {
238 int ret
= pthread_condattr_setclock(
239 &condattr
, CLOCK_MONOTONIC
);
241 ret
= pthread_cond_init(&mycond
->cond
, &condattr
);
243 pthread_condattr_destroy(&condattr
);
246 mycond
->clk_id
= CLOCK_MONOTONIC
;
251 // If anything above fails, fall back to the default CLOCK_REALTIME.
252 // POSIX requires that all implementations of clock_gettime() must
253 // support at least CLOCK_REALTIME.
256 mycond
->clk_id
= CLOCK_REALTIME
;
259 return pthread_cond_init(&mycond
->cond
, NULL
);
263 mythread_cond_destroy(mythread_cond
*cond
)
265 int ret
= pthread_cond_destroy(&cond
->cond
);
271 mythread_cond_signal(mythread_cond
*cond
)
273 int ret
= pthread_cond_signal(&cond
->cond
);
279 mythread_cond_wait(mythread_cond
*cond
, mythread_mutex
*mutex
)
281 int ret
= pthread_cond_wait(&cond
->cond
, mutex
);
286 // Waits on a condition or until a timeout expires. If the timeout expires,
287 // non-zero is returned, otherwise zero is returned.
289 mythread_cond_timedwait(mythread_cond
*cond
, mythread_mutex
*mutex
,
290 const mythread_condtime
*condtime
)
292 int ret
= pthread_cond_timedwait(&cond
->cond
, mutex
, condtime
);
293 assert(ret
== 0 || ret
== ETIMEDOUT
);
297 // Sets condtime to the absolute time that is timeout_ms milliseconds
298 // in the future. The type of the clock to use is taken from cond.
300 mythread_condtime_set(mythread_condtime
*condtime
, const mythread_cond
*cond
,
303 condtime
->tv_sec
= (time_t)(timeout_ms
/ 1000);
304 condtime
->tv_nsec
= (long)((timeout_ms
% 1000) * 1000000);
306 #ifdef HAVE_CLOCK_GETTIME
308 int ret
= clock_gettime(cond
->clk_id
, &now
);
312 condtime
->tv_sec
+= now
.tv_sec
;
313 condtime
->tv_nsec
+= now
.tv_nsec
;
318 gettimeofday(&now
, NULL
);
320 condtime
->tv_sec
+= now
.tv_sec
;
321 condtime
->tv_nsec
+= now
.tv_usec
* 1000L;
324 // tv_nsec must stay in the range [0, 999_999_999].
325 if (condtime
->tv_nsec
>= 1000000000L) {
326 condtime
->tv_nsec
-= 1000000000L;
332 #elif defined(MYTHREAD_WIN95) || defined(MYTHREAD_VISTA)
334 /////////////////////
335 // Windows threads //
336 /////////////////////
338 #define WIN32_LEAN_AND_MEAN
339 #ifdef MYTHREAD_VISTA
341 # define _WIN32_WINNT 0x0600
346 #define MYTHREAD_RET_TYPE unsigned int __stdcall
347 #define MYTHREAD_RET_VALUE 0
349 typedef HANDLE mythread
;
350 typedef CRITICAL_SECTION mythread_mutex
;
352 #ifdef MYTHREAD_WIN95
353 typedef HANDLE mythread_cond
;
355 typedef CONDITION_VARIABLE mythread_cond
;
359 // Tick count (milliseconds) in the beginning of the timeout.
360 // NOTE: This is 32 bits so it wraps around after 49.7 days.
361 // Multi-day timeouts may not work as expected.
364 // Length of the timeout in milliseconds. The timeout expires
365 // when the current tick count minus "start" is equal or greater
371 // mythread_once() is only available with Vista threads.
372 #ifdef MYTHREAD_VISTA
373 #define mythread_once(func) \
375 static INIT_ONCE once_ = INIT_ONCE_STATIC_INIT; \
377 if (!InitOnceBeginInitialize(&once_, 0, &pending_, NULL)) \
381 if (!InitOnceComplete(&once, 0, NULL)) \
388 // mythread_sigmask() isn't available on Windows. Even a dummy version would
389 // make no sense because the other POSIX signal functions are missing anyway.
393 mythread_create(mythread
*thread
,
394 unsigned int (__stdcall
*func
)(void *arg
), void *arg
)
396 uintptr_t ret
= _beginthreadex(NULL
, 0, func
, arg
, 0, NULL
);
400 *thread
= (HANDLE
)ret
;
405 mythread_join(mythread thread
)
409 if (WaitForSingleObject(thread
, INFINITE
) != WAIT_OBJECT_0
)
412 if (!CloseHandle(thread
))
420 mythread_mutex_init(mythread_mutex
*mutex
)
422 InitializeCriticalSection(mutex
);
427 mythread_mutex_destroy(mythread_mutex
*mutex
)
429 DeleteCriticalSection(mutex
);
433 mythread_mutex_lock(mythread_mutex
*mutex
)
435 EnterCriticalSection(mutex
);
439 mythread_mutex_unlock(mythread_mutex
*mutex
)
441 LeaveCriticalSection(mutex
);
446 mythread_cond_init(mythread_cond
*cond
)
448 #ifdef MYTHREAD_WIN95
449 *cond
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
450 return *cond
== NULL
? -1 : 0;
452 InitializeConditionVariable(cond
);
458 mythread_cond_destroy(mythread_cond
*cond
)
460 #ifdef MYTHREAD_WIN95
468 mythread_cond_signal(mythread_cond
*cond
)
470 #ifdef MYTHREAD_WIN95
473 WakeConditionVariable(cond
);
478 mythread_cond_wait(mythread_cond
*cond
, mythread_mutex
*mutex
)
480 #ifdef MYTHREAD_WIN95
481 LeaveCriticalSection(mutex
);
482 WaitForSingleObject(*cond
, INFINITE
);
483 EnterCriticalSection(mutex
);
485 BOOL ret
= SleepConditionVariableCS(cond
, mutex
, INFINITE
);
492 mythread_cond_timedwait(mythread_cond
*cond
, mythread_mutex
*mutex
,
493 const mythread_condtime
*condtime
)
495 #ifdef MYTHREAD_WIN95
496 LeaveCriticalSection(mutex
);
499 DWORD elapsed
= GetTickCount() - condtime
->start
;
500 DWORD timeout
= elapsed
>= condtime
->timeout
501 ? 0 : condtime
->timeout
- elapsed
;
503 #ifdef MYTHREAD_WIN95
504 DWORD ret
= WaitForSingleObject(*cond
, timeout
);
505 assert(ret
== WAIT_OBJECT_0
|| ret
== WAIT_TIMEOUT
);
507 EnterCriticalSection(mutex
);
509 return ret
== WAIT_TIMEOUT
;
511 BOOL ret
= SleepConditionVariableCS(cond
, mutex
, timeout
);
512 assert(ret
|| GetLastError() == ERROR_TIMEOUT
);
518 mythread_condtime_set(mythread_condtime
*condtime
, const mythread_cond
*cond
,
522 condtime
->start
= GetTickCount();
523 condtime
->timeout
= timeout
;