Parolin 0.7.9 6796
Console (soon DLLs) to do a tar like job
Loading...
Searching...
No Matches
mythread.h
Go to the documentation of this file.
1
2//
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) \
73do { \
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
86static inline void
87mythread_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 <pthread.h>
104#include <signal.h>
105#include <time.h>
106#include <errno.h>
107
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>
113#endif
114
115#define MYTHREAD_RET_TYPE void *
116#define MYTHREAD_RET_VALUE NULL
117
118typedef pthread_t mythread;
119typedef pthread_mutex_t mythread_mutex;
120
121typedef struct {
122 pthread_cond_t cond;
123#ifdef HAVE_CLOCK_GETTIME
124 // Clock ID (CLOCK_REALTIME or CLOCK_MONOTONIC) associated with
125 // the condition variable.
126 clockid_t clk_id;
127#endif
128} mythread_cond;
129
130typedef struct timespec mythread_condtime;
131
132
133// Calls the given function once in a thread-safe way.
134#define mythread_once(func) \
135 do { \
136 static pthread_once_t once_ = PTHREAD_ONCE_INIT; \
137 pthread_once(&once_, &func); \
138 } while (0)
139
140
141// Use pthread_sigmask() to set the signal mask in multi-threaded programs.
142// Do nothing on OpenVMS since it lacks pthread_sigmask().
143static inline void
144mythread_sigmask(int how, const sigset_t *restrict set,
145 sigset_t *restrict oset)
146{
147#ifdef __VMS
148 (void)how;
149 (void)set;
150 (void)oset;
151#else
152 int ret = pthread_sigmask(how, set, oset);
153 assert(ret == 0);
154 (void)ret;
155#endif
156}
157
158
159// Creates a new thread with all signals blocked. Returns zero on success
160// and non-zero on error.
161static inline int
162mythread_create(mythread *thread, void *(*func)(void *arg), void *arg)
163{
164 sigset_t old;
165 sigset_t all;
166 sigfillset(&all);
167
168 mythread_sigmask(SIG_SETMASK, &all, &old);
169 const int ret = pthread_create(thread, NULL, func, arg);
170 mythread_sigmask(SIG_SETMASK, &old, NULL);
171
172 return ret;
173}
174
175// Joins a thread. Returns zero on success and non-zero on error.
176static inline int
177mythread_join(mythread thread)
178{
179 return pthread_join(thread, NULL);
180}
181
182
183// Initiatlizes a mutex. Returns zero on success and non-zero on error.
184static inline int
185mythread_mutex_init(mythread_mutex *mutex)
186{
187 return pthread_mutex_init(mutex, NULL);
188}
189
190static inline void
191mythread_mutex_destroy(mythread_mutex *mutex)
192{
193 int ret = pthread_mutex_destroy(mutex);
194 assert(ret == 0);
195 (void)ret;
196}
197
198static inline void
199mythread_mutex_lock(mythread_mutex *mutex)
200{
201 int ret = pthread_mutex_lock(mutex);
202 assert(ret == 0);
203 (void)ret;
204}
205
206static inline void
207mythread_mutex_unlock(mythread_mutex *mutex)
208{
209 int ret = pthread_mutex_unlock(mutex);
210 assert(ret == 0);
211 (void)ret;
212}
213
214
215// Initializes a condition variable.
216//
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.
222//
223// If clock_gettime() isn't available at all, gettimeofday() will be used.
224static inline int
225mythread_cond_init(mythread_cond *mycond)
226{
227#ifdef HAVE_CLOCK_GETTIME
228# if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && \
229 defined(HAVE_CLOCK_MONOTONIC)
230 struct timespec ts;
231 pthread_condattr_t condattr;
232
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);
240 if (ret == 0)
241 ret = pthread_cond_init(&mycond->cond, &condattr);
242
243 pthread_condattr_destroy(&condattr);
244
245 if (ret == 0) {
246 mycond->clk_id = CLOCK_MONOTONIC;
247 return 0;
248 }
249 }
250
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.
254# endif
255
256 mycond->clk_id = CLOCK_REALTIME;
257#endif
258
259 return pthread_cond_init(&mycond->cond, NULL);
260}
261
262static inline void
263mythread_cond_destroy(mythread_cond *cond)
264{
265 int ret = pthread_cond_destroy(&cond->cond);
266 assert(ret == 0);
267 (void)ret;
268}
269
270static inline void
271mythread_cond_signal(mythread_cond *cond)
272{
273 int ret = pthread_cond_signal(&cond->cond);
274 assert(ret == 0);
275 (void)ret;
276}
277
278static inline void
279mythread_cond_wait(mythread_cond *cond, mythread_mutex *mutex)
280{
281 int ret = pthread_cond_wait(&cond->cond, mutex);
282 assert(ret == 0);
283 (void)ret;
284}
285
286// Waits on a condition or until a timeout expires. If the timeout expires,
287// non-zero is returned, otherwise zero is returned.
288static inline int
289mythread_cond_timedwait(mythread_cond *cond, mythread_mutex *mutex,
290 const mythread_condtime *condtime)
291{
292 int ret = pthread_cond_timedwait(&cond->cond, mutex, condtime);
293 assert(ret == 0 || ret == ETIMEDOUT);
294 return ret;
295}
296
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.
299static inline void
300mythread_condtime_set(mythread_condtime *condtime, const mythread_cond *cond,
301 uint32_t timeout_ms)
302{
303 condtime->tv_sec = timeout_ms / 1000;
304 condtime->tv_nsec = (timeout_ms % 1000) * 1000000;
305
306#ifdef HAVE_CLOCK_GETTIME
307 struct timespec now;
308 int ret = clock_gettime(cond->clk_id, &now);
309 assert(ret == 0);
310 (void)ret;
311
312 condtime->tv_sec += now.tv_sec;
313 condtime->tv_nsec += now.tv_nsec;
314#else
315 (void)cond;
316
317 struct timeval now;
318 gettimeofday(&now, NULL);
319
320 condtime->tv_sec += now.tv_sec;
321 condtime->tv_nsec += now.tv_usec * 1000L;
322#endif
323
324 // tv_nsec must stay in the range [0, 999_999_999].
325 if (condtime->tv_nsec >= 1000000000L) {
326 condtime->tv_nsec -= 1000000000L;
327 ++condtime->tv_sec;
328 }
329}
330
331
332#elif defined(MYTHREAD_WIN95) || defined(MYTHREAD_VISTA)
333
335// Windows threads //
337
338#define WIN32_LEAN_AND_MEAN
339#ifdef MYTHREAD_VISTA
340# undef _WIN32_WINNT
341# define _WIN32_WINNT 0x0600
342#endif
343#include <windows.h>
344#include <process.h>
345
346#define MYTHREAD_RET_TYPE unsigned int __stdcall
347#define MYTHREAD_RET_VALUE 0
348
349typedef HANDLE mythread;
350typedef CRITICAL_SECTION mythread_mutex;
351
352#ifdef MYTHREAD_WIN95
353typedef HANDLE mythread_cond;
354#else
355typedef CONDITION_VARIABLE mythread_cond;
356#endif
357
358typedef struct {
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.
362 DWORD start;
363
364 // Length of the timeout in milliseconds. The timeout expires
365 // when the current tick count minus "start" is equal or greater
366 // than "timeout".
368} mythread_condtime;
369
370
371// mythread_once() is only available with Vista threads.
372#ifdef MYTHREAD_VISTA
373#define mythread_once(func) \
374 do { \
375 static INIT_ONCE once_ = INIT_ONCE_STATIC_INIT; \
376 BOOL pending_; \
377 if (!InitOnceBeginInitialize(&once_, 0, &pending_, NULL)) \
378 abort(); \
379 if (pending_) { \
380 func(); \
381 if (!InitOnceComplete(&once, 0, NULL)) \
382 abort(); \
383 } \
384 } while (0)
385#endif
386
387
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.
390
391
392static inline int
393mythread_create(mythread *thread,
394 unsigned int (__stdcall *func)(void *arg), void *arg)
395{
396 uintptr_t ret = _beginthreadex(NULL, 0, func, arg, 0, NULL);
397 if (ret == 0)
398 return -1;
399
400 *thread = (HANDLE)ret;
401 return 0;
402}
403
404static inline int
405mythread_join(mythread thread)
406{
407 int ret = 0;
408
409 if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0)
410 ret = -1;
411
412 if (!CloseHandle(thread))
413 ret = -1;
414
415 return ret;
416}
417
418
419static inline int
420mythread_mutex_init(mythread_mutex *mutex)
421{
422 InitializeCriticalSection(mutex);
423 return 0;
424}
425
426static inline void
427mythread_mutex_destroy(mythread_mutex *mutex)
428{
429 DeleteCriticalSection(mutex);
430}
431
432static inline void
433mythread_mutex_lock(mythread_mutex *mutex)
434{
435 EnterCriticalSection(mutex);
436}
437
438static inline void
439mythread_mutex_unlock(mythread_mutex *mutex)
440{
441 LeaveCriticalSection(mutex);
442}
443
444
445static inline int
446mythread_cond_init(mythread_cond *cond)
447{
448#ifdef MYTHREAD_WIN95
449 *cond = CreateEvent(NULL, FALSE, FALSE, NULL);
450 return *cond == NULL ? -1 : 0;
451#else
452 InitializeConditionVariable(cond);
453 return 0;
454#endif
455}
456
457static inline void
458mythread_cond_destroy(mythread_cond *cond)
459{
460#ifdef MYTHREAD_WIN95
461 CloseHandle(*cond);
462#else
463 (void)cond;
464#endif
465}
466
467static inline void
468mythread_cond_signal(mythread_cond *cond)
469{
470#ifdef MYTHREAD_WIN95
471 SetEvent(*cond);
472#else
473 WakeConditionVariable(cond);
474#endif
475}
476
477static inline void
478mythread_cond_wait(mythread_cond *cond, mythread_mutex *mutex)
479{
480#ifdef MYTHREAD_WIN95
481 LeaveCriticalSection(mutex);
482 WaitForSingleObject(*cond, INFINITE);
483 EnterCriticalSection(mutex);
484#else
485 BOOL ret = SleepConditionVariableCS(cond, mutex, INFINITE);
486 assert(ret);
487 (void)ret;
488#endif
489}
490
491static inline int
492mythread_cond_timedwait(mythread_cond *cond, mythread_mutex *mutex,
493 const mythread_condtime *condtime)
494{
495#ifdef MYTHREAD_WIN95
496 LeaveCriticalSection(mutex);
497#endif
498
499 DWORD elapsed = GetTickCount() - condtime->start;
500 DWORD timeout = elapsed >= condtime->timeout
501 ? 0 : condtime->timeout - elapsed;
502
503#ifdef MYTHREAD_WIN95
504 DWORD ret = WaitForSingleObject(*cond, timeout);
505 assert(ret == WAIT_OBJECT_0 || ret == WAIT_TIMEOUT);
506
507 EnterCriticalSection(mutex);
508
509 return ret == WAIT_TIMEOUT;
510#else
511 BOOL ret = SleepConditionVariableCS(cond, mutex, timeout);
512 assert(ret || GetLastError() == ERROR_TIMEOUT);
513 return !ret;
514#endif
515}
516
517static inline void
518mythread_condtime_set(mythread_condtime *condtime, const mythread_cond *cond,
519 uint32_t timeout)
520{
521 (void)cond;
522 condtime->start = GetTickCount();
523 condtime->timeout = timeout;
524}
525
526#endif
527
528#endif
UINT32 DWORD
Definition 7zTypes.h:194
int BOOL
Definition 7zMain.c:321
int start()
#define assert(condition)
Definition lz4.c:273
now
Definition rateLimiter.py:31
timeout
Definition run.py:691
size_t uintptr_t
Definition fuzzer.c:71
#define NULL
Definition getopt1.c:37
Common includes, definitions, system-specific things etc.
ret
Definition zlib_interface.c:30