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 <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
112typedef pthread_t mythread;
113typedef pthread_mutex_t mythread_mutex;
114
115typedef 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
124typedef 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().
137static inline void
138mythread_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.
155static inline int
156mythread_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.
170static inline int
171mythread_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.
178static inline int
179mythread_mutex_init(mythread_mutex *mutex)
180{
181 return pthread_mutex_init(mutex, NULL);
182}
183
184static inline void
185mythread_mutex_destroy(mythread_mutex *mutex)
186{
187 int ret = pthread_mutex_destroy(mutex);
188 assert(ret == 0);
189 (void)ret;
190}
191
192static inline void
193mythread_mutex_lock(mythread_mutex *mutex)
194{
195 int ret = pthread_mutex_lock(mutex);
196 assert(ret == 0);
197 (void)ret;
198}
199
200static inline void
201mythread_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.
218static inline int
219mythread_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
256static inline void
257mythread_cond_destroy(mythread_cond *cond)
258{
259 int ret = pthread_cond_destroy(&cond->cond);
260 assert(ret == 0);
261 (void)ret;
262}
263
264static inline void
265mythread_cond_signal(mythread_cond *cond)
266{
267 int ret = pthread_cond_signal(&cond->cond);
268 assert(ret == 0);
269 (void)ret;
270}
271
272static inline void
273mythread_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.
282static inline int
283mythread_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.
293static inline void
294mythread_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
343typedef HANDLE mythread;
344typedef CRITICAL_SECTION mythread_mutex;
345
346#ifdef MYTHREAD_WIN95
347typedef HANDLE mythread_cond;
348#else
349typedef CONDITION_VARIABLE mythread_cond;
350#endif
351
352typedef 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".
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 } \
378 } while (0)
379#endif
380
381
382// mythread_sigmask() isn't available on Windows. Even a dummy version would
383// make no sense because the other POSIX signal functions are missing anyway.
384
385
386static inline int
387mythread_create(mythread *thread,
388 unsigned int (__stdcall *func)(void *arg), void *arg)
389{
390 uintptr_t ret = _beginthreadex(NULL, 0, func, arg, 0, NULL);
391 if (ret == 0)
392 return -1;
393
394 *thread = (HANDLE)ret;
395 return 0;
396}
397
398static inline int
399mythread_join(mythread thread)
400{
401 int ret = 0;
402
403 if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0)
404 ret = -1;
405
406 if (!CloseHandle(thread))
407 ret = -1;
408
409 return ret;
410}
411
412
413static inline int
414mythread_mutex_init(mythread_mutex *mutex)
415{
416 InitializeCriticalSection(mutex);
417 return 0;
418}
419
420static inline void
421mythread_mutex_destroy(mythread_mutex *mutex)
422{
423 DeleteCriticalSection(mutex);
424}
425
426static inline void
427mythread_mutex_lock(mythread_mutex *mutex)
428{
429 EnterCriticalSection(mutex);
430}
431
432static inline void
433mythread_mutex_unlock(mythread_mutex *mutex)
434{
435 LeaveCriticalSection(mutex);
436}
437
438
439static inline int
440mythread_cond_init(mythread_cond *cond)
441{
442#ifdef MYTHREAD_WIN95
443 *cond = CreateEvent(NULL, FALSE, FALSE, NULL);
444 return *cond == NULL ? -1 : 0;
445#else
446 InitializeConditionVariable(cond);
447 return 0;
448#endif
449}
450
451static inline void
452mythread_cond_destroy(mythread_cond *cond)
453{
454#ifdef MYTHREAD_WIN95
455 CloseHandle(*cond);
456#else
457 (void)cond;
458#endif
459}
460
461static inline void
462mythread_cond_signal(mythread_cond *cond)
463{
464#ifdef MYTHREAD_WIN95
465 SetEvent(*cond);
466#else
467 WakeConditionVariable(cond);
468#endif
469}
470
471static inline void
472mythread_cond_wait(mythread_cond *cond, mythread_mutex *mutex)
473{
474#ifdef MYTHREAD_WIN95
475 LeaveCriticalSection(mutex);
476 WaitForSingleObject(*cond, INFINITE);
477 EnterCriticalSection(mutex);
478#else
479 BOOL ret = SleepConditionVariableCS(cond, mutex, INFINITE);
480 assert(ret);
481 (void)ret;
482#endif
483}
484
485static inline int
486mythread_cond_timedwait(mythread_cond *cond, mythread_mutex *mutex,
487 const mythread_condtime *condtime)
488{
489#ifdef MYTHREAD_WIN95
490 LeaveCriticalSection(mutex);
491#endif
492
493 DWORD elapsed = GetTickCount() - condtime->start;
494 DWORD timeout = elapsed >= condtime->timeout
495 ? 0 : condtime->timeout - elapsed;
496
497#ifdef MYTHREAD_WIN95
498 DWORD ret = WaitForSingleObject(*cond, timeout);
499 assert(ret == WAIT_OBJECT_0 || ret == WAIT_TIMEOUT);
500
501 EnterCriticalSection(mutex);
502
503 return ret == WAIT_TIMEOUT;
504#else
505 BOOL ret = SleepConditionVariableCS(cond, mutex, timeout);
506 assert(ret || GetLastError() == ERROR_TIMEOUT);
507 return !ret;
508#endif
509}
510
511static inline void
512mythread_condtime_set(mythread_condtime *condtime, const mythread_cond *cond,
513 uint32_t timeout)
514{
515 (void)cond;
516 condtime->start = GetTickCount();
517 condtime->timeout = timeout;
518}
519
520#endif
521
522#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