1 | /* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; -*- |
2 | Copyright (c) 2012 Marcus Geelnard |
3 | Copyright (c) 2013-2014 Evan Nemerson |
4 | |
5 | This software is provided 'as-is', without any express or implied |
6 | warranty. In no event will the authors be held liable for any damages |
7 | arising from the use of this software. |
8 | |
9 | Permission is granted to anyone to use this software for any purpose, |
10 | including commercial applications, and to alter it and redistribute it |
11 | freely, subject to the following restrictions: |
12 | |
13 | 1. The origin of this software must not be misrepresented; you must not |
14 | claim that you wrote the original software. If you use this software |
15 | in a product, an acknowledgment in the product documentation would be |
16 | appreciated but is not required. |
17 | |
18 | 2. Altered source versions must be plainly marked as such, and must not be |
19 | misrepresented as being the original software. |
20 | |
21 | 3. This notice may not be removed or altered from any source |
22 | distribution. |
23 | */ |
24 | |
25 | #ifndef _TINYCTHREAD_H_ |
26 | #define _TINYCTHREAD_H_ |
27 | |
28 | /* Include config to know if C11 threads are available */ |
29 | #ifdef _MSC_VER |
30 | #include "win32_config.h" |
31 | #else |
32 | #include "../config.h" |
33 | #endif |
34 | |
35 | #if WITH_C11THREADS |
36 | #include <threads.h> |
37 | #else |
38 | |
39 | #ifdef __cplusplus |
40 | extern "C" { |
41 | #endif |
42 | |
43 | /** |
44 | * @file |
45 | * @mainpage TinyCThread API Reference |
46 | * |
47 | * @section intro_sec Introduction |
48 | * TinyCThread is a minimal, portable implementation of basic threading |
49 | * classes for C. |
50 | * |
51 | * They closely mimic the functionality and naming of the C11 standard, and |
52 | * should be easily replaceable with the corresponding standard variants. |
53 | * |
54 | * @section port_sec Portability |
55 | * The Win32 variant uses the native Win32 API for implementing the thread |
56 | * classes, while for other systems, the POSIX threads API (pthread) is used. |
57 | * |
58 | * @section misc_sec Miscellaneous |
59 | * The following special keywords are available: #_Thread_local. |
60 | * |
61 | * For more detailed information, browse the different sections of this |
62 | * documentation. A good place to start is: |
63 | * tinycthread.h. |
64 | */ |
65 | |
66 | /* Which platform are we on? */ |
67 | #if !defined(_TTHREAD_PLATFORM_DEFINED_) |
68 | #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) |
69 | #define _TTHREAD_WIN32_ |
70 | #else |
71 | #define _TTHREAD_POSIX_ |
72 | #endif |
73 | #define _TTHREAD_PLATFORM_DEFINED_ |
74 | #endif |
75 | |
76 | /* Activate some POSIX functionality (e.g. clock_gettime and recursive mutexes) */ |
77 | #if defined(_TTHREAD_POSIX_) |
78 | #undef _FEATURES_H |
79 | #if !defined(_GNU_SOURCE) |
80 | #define _GNU_SOURCE |
81 | #endif |
82 | #if !defined(_POSIX_C_SOURCE) || ((_POSIX_C_SOURCE - 0) < 199309L) |
83 | #undef _POSIX_C_SOURCE |
84 | #define _POSIX_C_SOURCE 199309L |
85 | #endif |
86 | #if !defined(_XOPEN_SOURCE) || ((_XOPEN_SOURCE - 0) < 500) |
87 | #undef _XOPEN_SOURCE |
88 | #define _XOPEN_SOURCE 500 |
89 | #endif |
90 | #endif |
91 | |
92 | /* Generic includes */ |
93 | #include <time.h> |
94 | |
95 | /* Platform specific includes */ |
96 | #if defined(_TTHREAD_POSIX_) |
97 | #ifndef _GNU_SOURCE |
98 | #define _GNU_SOURCE /* for pthread_setname_np() */ |
99 | #endif |
100 | #include <pthread.h> |
101 | #elif defined(_TTHREAD_WIN32_) |
102 | #ifndef WIN32_LEAN_AND_MEAN |
103 | #define WIN32_LEAN_AND_MEAN |
104 | #define __UNDEF_LEAN_AND_MEAN |
105 | #endif |
106 | #include <windows.h> |
107 | #ifdef __UNDEF_LEAN_AND_MEAN |
108 | #undef WIN32_LEAN_AND_MEAN |
109 | #undef __UNDEF_LEAN_AND_MEAN |
110 | #endif |
111 | #endif |
112 | |
113 | /* Compiler-specific information */ |
114 | #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L |
115 | #define TTHREAD_NORETURN _Noreturn |
116 | #elif defined(__GNUC__) |
117 | #define TTHREAD_NORETURN __attribute__((__noreturn__)) |
118 | #else |
119 | #define TTHREAD_NORETURN |
120 | #endif |
121 | |
122 | /* If TIME_UTC is missing, provide it and provide a wrapper for |
123 | timespec_get. */ |
124 | #ifndef TIME_UTC |
125 | #define TIME_UTC 1 |
126 | #define _TTHREAD_EMULATE_TIMESPEC_GET_ |
127 | |
128 | #if defined(_TTHREAD_WIN32_) |
129 | struct _tthread_timespec { |
130 | time_t tv_sec; |
131 | long tv_nsec; |
132 | }; |
133 | #define timespec _tthread_timespec |
134 | #endif |
135 | |
136 | int _tthread_timespec_get(struct timespec *ts, int base); |
137 | #define timespec_get _tthread_timespec_get |
138 | #endif |
139 | |
140 | /** TinyCThread version (major number). */ |
141 | #define TINYCTHREAD_VERSION_MAJOR 1 |
142 | /** TinyCThread version (minor number). */ |
143 | #define TINYCTHREAD_VERSION_MINOR 2 |
144 | /** TinyCThread version (full version). */ |
145 | #define TINYCTHREAD_VERSION (TINYCTHREAD_VERSION_MAJOR * 100 + TINYCTHREAD_VERSION_MINOR) |
146 | |
147 | /** |
148 | * @def _Thread_local |
149 | * Thread local storage keyword. |
150 | * A variable that is declared with the @c _Thread_local keyword makes the |
151 | * value of the variable local to each thread (known as thread-local storage, |
152 | * or TLS). Example usage: |
153 | * @code |
154 | * // This variable is local to each thread. |
155 | * _Thread_local int variable; |
156 | * @endcode |
157 | * @note The @c _Thread_local keyword is a macro that maps to the corresponding |
158 | * compiler directive (e.g. @c __declspec(thread)). |
159 | * @note This directive is currently not supported on Mac OS X (it will give |
160 | * a compiler error), since compile-time TLS is not supported in the Mac OS X |
161 | * executable format. Also, some older versions of MinGW (before GCC 4.x) do |
162 | * not support this directive, nor does the Tiny C Compiler. |
163 | * @hideinitializer |
164 | */ |
165 | |
166 | #if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201102L)) && !defined(_Thread_local) |
167 | #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) |
168 | #define _Thread_local __thread |
169 | #else |
170 | #define _Thread_local __declspec(thread) |
171 | #endif |
172 | #elif defined(__GNUC__) && defined(__GNUC_MINOR__) && (((__GNUC__ << 8) | __GNUC_MINOR__) < ((4 << 8) | 9)) |
173 | #define _Thread_local __thread |
174 | #endif |
175 | |
176 | /* Macros */ |
177 | #if defined(_TTHREAD_WIN32_) |
178 | #define TSS_DTOR_ITERATIONS (4) |
179 | #else |
180 | #define TSS_DTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS |
181 | #endif |
182 | |
183 | /* Function return values */ |
184 | #define thrd_error 0 /**< The requested operation failed */ |
185 | #define thrd_success 1 /**< The requested operation succeeded */ |
186 | #define thrd_timedout 2 /**< The time specified in the call was reached without acquiring the requested resource */ |
187 | #define thrd_busy 3 /**< The requested operation failed because a tesource requested by a test and return function is already in use */ |
188 | #define thrd_nomem 4 /**< The requested operation failed because it was unable to allocate memory */ |
189 | |
190 | /* Mutex types */ |
191 | #define mtx_plain 0 |
192 | #define mtx_timed 1 |
193 | #define mtx_recursive 2 |
194 | |
195 | /* Mutex */ |
196 | #if defined(_TTHREAD_WIN32_) |
197 | typedef struct { |
198 | union { |
199 | CRITICAL_SECTION cs; /* Critical section handle (used for non-timed mutexes) */ |
200 | HANDLE mut; /* Mutex handle (used for timed mutex) */ |
201 | } mHandle; /* Mutex handle */ |
202 | int mAlreadyLocked; /* TRUE if the mutex is already locked */ |
203 | int mRecursive; /* TRUE if the mutex is recursive */ |
204 | int mTimed; /* TRUE if the mutex is timed */ |
205 | } mtx_t; |
206 | #else |
207 | typedef pthread_mutex_t mtx_t; |
208 | #endif |
209 | |
210 | /** Create a mutex object. |
211 | * @param mtx A mutex object. |
212 | * @param type Bit-mask that must have one of the following six values: |
213 | * @li @c mtx_plain for a simple non-recursive mutex |
214 | * @li @c mtx_timed for a non-recursive mutex that supports timeout |
215 | * @li @c mtx_plain | @c mtx_recursive (same as @c mtx_plain, but recursive) |
216 | * @li @c mtx_timed | @c mtx_recursive (same as @c mtx_timed, but recursive) |
217 | * @return @ref thrd_success on success, or @ref thrd_error if the request could |
218 | * not be honored. |
219 | */ |
220 | int mtx_init(mtx_t *mtx, int type); |
221 | |
222 | /** Release any resources used by the given mutex. |
223 | * @param mtx A mutex object. |
224 | */ |
225 | void mtx_destroy(mtx_t *mtx); |
226 | |
227 | /** Lock the given mutex. |
228 | * Blocks until the given mutex can be locked. If the mutex is non-recursive, and |
229 | * the calling thread already has a lock on the mutex, this call will block |
230 | * forever. |
231 | * @param mtx A mutex object. |
232 | * @return @ref thrd_success on success, or @ref thrd_error if the request could |
233 | * not be honored. |
234 | */ |
235 | int mtx_lock(mtx_t *mtx); |
236 | |
237 | /** NOT YET IMPLEMENTED. |
238 | */ |
239 | int mtx_timedlock(mtx_t *mtx, const struct timespec *ts); |
240 | |
241 | /** Try to lock the given mutex. |
242 | * The specified mutex shall support either test and return or timeout. If the |
243 | * mutex is already locked, the function returns without blocking. |
244 | * @param mtx A mutex object. |
245 | * @return @ref thrd_success on success, or @ref thrd_busy if the resource |
246 | * requested is already in use, or @ref thrd_error if the request could not be |
247 | * honored. |
248 | */ |
249 | int mtx_trylock(mtx_t *mtx); |
250 | |
251 | /** Unlock the given mutex. |
252 | * @param mtx A mutex object. |
253 | * @return @ref thrd_success on success, or @ref thrd_error if the request could |
254 | * not be honored. |
255 | */ |
256 | int mtx_unlock(mtx_t *mtx); |
257 | |
258 | /* Condition variable */ |
259 | #if defined(_TTHREAD_WIN32_) |
260 | typedef struct { |
261 | HANDLE mEvents[2]; /* Signal and broadcast event HANDLEs. */ |
262 | unsigned int mWaitersCount; /* Count of the number of waiters. */ |
263 | CRITICAL_SECTION mWaitersCountLock; /* Serialize access to mWaitersCount. */ |
264 | } cnd_t; |
265 | #else |
266 | typedef pthread_cond_t cnd_t; |
267 | #endif |
268 | |
269 | /** Create a condition variable object. |
270 | * @param cond A condition variable object. |
271 | * @return @ref thrd_success on success, or @ref thrd_error if the request could |
272 | * not be honored. |
273 | */ |
274 | int cnd_init(cnd_t *cond); |
275 | |
276 | /** Release any resources used by the given condition variable. |
277 | * @param cond A condition variable object. |
278 | */ |
279 | void cnd_destroy(cnd_t *cond); |
280 | |
281 | /** Signal a condition variable. |
282 | * Unblocks one of the threads that are blocked on the given condition variable |
283 | * at the time of the call. If no threads are blocked on the condition variable |
284 | * at the time of the call, the function does nothing and return success. |
285 | * @param cond A condition variable object. |
286 | * @return @ref thrd_success on success, or @ref thrd_error if the request could |
287 | * not be honored. |
288 | */ |
289 | int cnd_signal(cnd_t *cond); |
290 | |
291 | /** Broadcast a condition variable. |
292 | * Unblocks all of the threads that are blocked on the given condition variable |
293 | * at the time of the call. If no threads are blocked on the condition variable |
294 | * at the time of the call, the function does nothing and return success. |
295 | * @param cond A condition variable object. |
296 | * @return @ref thrd_success on success, or @ref thrd_error if the request could |
297 | * not be honored. |
298 | */ |
299 | int cnd_broadcast(cnd_t *cond); |
300 | |
301 | /** Wait for a condition variable to become signaled. |
302 | * The function atomically unlocks the given mutex and endeavors to block until |
303 | * the given condition variable is signaled by a call to cnd_signal or to |
304 | * cnd_broadcast. When the calling thread becomes unblocked it locks the mutex |
305 | * before it returns. |
306 | * @param cond A condition variable object. |
307 | * @param mtx A mutex object. |
308 | * @return @ref thrd_success on success, or @ref thrd_error if the request could |
309 | * not be honored. |
310 | */ |
311 | int cnd_wait(cnd_t *cond, mtx_t *mtx); |
312 | |
313 | /** Wait for a condition variable to become signaled. |
314 | * The function atomically unlocks the given mutex and endeavors to block until |
315 | * the given condition variable is signaled by a call to cnd_signal or to |
316 | * cnd_broadcast, or until after the specified time. When the calling thread |
317 | * becomes unblocked it locks the mutex before it returns. |
318 | * @param cond A condition variable object. |
319 | * @param mtx A mutex object. |
320 | * @param xt A point in time at which the request will time out (absolute time). |
321 | * @return @ref thrd_success upon success, or @ref thrd_timeout if the time |
322 | * specified in the call was reached without acquiring the requested resource, or |
323 | * @ref thrd_error if the request could not be honored. |
324 | */ |
325 | int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts); |
326 | |
327 | #if defined(_TTHREAD_WIN32_) |
328 | int _cnd_timedwait_win32(cnd_t *cond, mtx_t *mtx, DWORD timeout); |
329 | #endif |
330 | |
331 | /* Thread */ |
332 | #if defined(_TTHREAD_WIN32_) |
333 | typedef HANDLE thrd_t; |
334 | #else |
335 | typedef pthread_t thrd_t; |
336 | #endif |
337 | |
338 | /** Thread start function. |
339 | * Any thread that is started with the @ref thrd_create() function must be |
340 | * started through a function of this type. |
341 | * @param arg The thread argument (the @c arg argument of the corresponding |
342 | * @ref thrd_create() call). |
343 | * @return The thread return value, which can be obtained by another thread |
344 | * by using the @ref thrd_join() function. |
345 | */ |
346 | typedef int (*thrd_start_t)(void *arg); |
347 | |
348 | /** Create a new thread. |
349 | * @param thr Identifier of the newly created thread. |
350 | * @param func A function pointer to the function that will be executed in |
351 | * the new thread. |
352 | * @param arg An argument to the thread function. |
353 | * @return @ref thrd_success on success, or @ref thrd_nomem if no memory could |
354 | * be allocated for the thread requested, or @ref thrd_error if the request |
355 | * could not be honored. |
356 | * @note A thread’s identifier may be reused for a different thread once the |
357 | * original thread has exited and either been detached or joined to another |
358 | * thread. |
359 | */ |
360 | int thrd_create(thrd_t *thr, thrd_start_t func, void *arg); |
361 | |
362 | /** Identify the calling thread. |
363 | * @return The identifier of the calling thread. |
364 | */ |
365 | thrd_t thrd_current(void); |
366 | |
367 | |
368 | /** Dispose of any resources allocated to the thread when that thread exits. |
369 | * @return thrd_success, or thrd_error on error |
370 | */ |
371 | int thrd_detach(thrd_t thr); |
372 | |
373 | /** Compare two thread identifiers. |
374 | * The function determines if two thread identifiers refer to the same thread. |
375 | * @return Zero if the two thread identifiers refer to different threads. |
376 | * Otherwise a nonzero value is returned. |
377 | */ |
378 | int thrd_equal(thrd_t thr0, thrd_t thr1); |
379 | |
380 | /** Terminate execution of the calling thread. |
381 | * @param res Result code of the calling thread. |
382 | */ |
383 | TTHREAD_NORETURN void thrd_exit(int res); |
384 | |
385 | /** Wait for a thread to terminate. |
386 | * The function joins the given thread with the current thread by blocking |
387 | * until the other thread has terminated. |
388 | * @param thr The thread to join with. |
389 | * @param res If this pointer is not NULL, the function will store the result |
390 | * code of the given thread in the integer pointed to by @c res. |
391 | * @return @ref thrd_success on success, or @ref thrd_error if the request could |
392 | * not be honored. |
393 | */ |
394 | int thrd_join(thrd_t thr, int *res); |
395 | |
396 | /** Put the calling thread to sleep. |
397 | * Suspend execution of the calling thread. |
398 | * @param duration Interval to sleep for |
399 | * @param remaining If non-NULL, this parameter will hold the remaining |
400 | * time until time_point upon return. This will |
401 | * typically be zero, but if the thread was woken up |
402 | * by a signal that is not ignored before duration was |
403 | * reached @c remaining will hold a positive time. |
404 | * @return 0 (zero) on successful sleep, -1 if an interrupt occurred, |
405 | * or a negative value if the operation fails. |
406 | */ |
407 | int thrd_sleep(const struct timespec *duration, struct timespec *remaining); |
408 | |
409 | /** Yield execution to another thread. |
410 | * Permit other threads to run, even if the current thread would ordinarily |
411 | * continue to run. |
412 | */ |
413 | void thrd_yield(void); |
414 | |
415 | /* Thread local storage */ |
416 | #if defined(_TTHREAD_WIN32_) |
417 | typedef DWORD tss_t; |
418 | #else |
419 | typedef pthread_key_t tss_t; |
420 | #endif |
421 | |
422 | /** Destructor function for a thread-specific storage. |
423 | * @param val The value of the destructed thread-specific storage. |
424 | */ |
425 | typedef void (*tss_dtor_t)(void *val); |
426 | |
427 | /** Create a thread-specific storage. |
428 | * @param key The unique key identifier that will be set if the function is |
429 | * successful. |
430 | * @param dtor Destructor function. This can be NULL. |
431 | * @return @ref thrd_success on success, or @ref thrd_error if the request could |
432 | * not be honored. |
433 | * @note On Windows, the @c dtor will definitely be called when |
434 | * appropriate for threads created with @ref thrd_create. It will be |
435 | * called for other threads in most cases, the possible exception being |
436 | * for DLLs loaded with LoadLibraryEx. In order to be certain, you |
437 | * should use @ref thrd_create whenever possible. |
438 | */ |
439 | int tss_create(tss_t *key, tss_dtor_t dtor); |
440 | |
441 | /** Delete a thread-specific storage. |
442 | * The function releases any resources used by the given thread-specific |
443 | * storage. |
444 | * @param key The key that shall be deleted. |
445 | */ |
446 | void tss_delete(tss_t key); |
447 | |
448 | /** Get the value for a thread-specific storage. |
449 | * @param key The thread-specific storage identifier. |
450 | * @return The value for the current thread held in the given thread-specific |
451 | * storage. |
452 | */ |
453 | void *tss_get(tss_t key); |
454 | |
455 | /** Set the value for a thread-specific storage. |
456 | * @param key The thread-specific storage identifier. |
457 | * @param val The value of the thread-specific storage to set for the current |
458 | * thread. |
459 | * @return @ref thrd_success on success, or @ref thrd_error if the request could |
460 | * not be honored. |
461 | */ |
462 | int tss_set(tss_t key, void *val); |
463 | |
464 | #if defined(_TTHREAD_WIN32_) |
465 | typedef struct { |
466 | LONG volatile status; |
467 | CRITICAL_SECTION lock; |
468 | } once_flag; |
469 | #define ONCE_FLAG_INIT {0,} |
470 | #else |
471 | #define once_flag pthread_once_t |
472 | #define ONCE_FLAG_INIT PTHREAD_ONCE_INIT |
473 | #endif |
474 | |
475 | /** Invoke a callback exactly once |
476 | * @param flag Flag used to ensure the callback is invoked exactly |
477 | * once. |
478 | * @param func Callback to invoke. |
479 | */ |
480 | #if defined(_TTHREAD_WIN32_) |
481 | void call_once(once_flag *flag, void (*func)(void)); |
482 | #else |
483 | #define call_once(flag,func) pthread_once(flag,func) |
484 | #endif |
485 | |
486 | |
487 | |
488 | #ifdef __cplusplus |
489 | } |
490 | #endif |
491 | |
492 | #endif /* !WITH_C11THREADS */ |
493 | |
494 | /** |
495 | * @brief librdkafka extensions to c11threads |
496 | */ |
497 | #include "tinycthread_extra.h" |
498 | |
499 | #endif /* _TINYTHREAD_H_ */ |
500 | |