1/* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; -*-
2Copyright (c) 2012 Marcus Geelnard
3Copyright (c) 2013-2014 Evan Nemerson
4
5This software is provided 'as-is', without any express or implied
6warranty. In no event will the authors be held liable for any damages
7arising from the use of this software.
8
9Permission is granted to anyone to use this software for any purpose,
10including commercial applications, and to alter it and redistribute it
11freely, 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
40extern "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_)
129struct _tthread_timespec {
130 time_t tv_sec;
131 long tv_nsec;
132};
133#define timespec _tthread_timespec
134#endif
135
136int _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_)
197typedef 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
207typedef 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*/
220int mtx_init(mtx_t *mtx, int type);
221
222/** Release any resources used by the given mutex.
223* @param mtx A mutex object.
224*/
225void 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*/
235int mtx_lock(mtx_t *mtx);
236
237/** NOT YET IMPLEMENTED.
238*/
239int 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*/
249int 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*/
256int mtx_unlock(mtx_t *mtx);
257
258/* Condition variable */
259#if defined(_TTHREAD_WIN32_)
260typedef 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
266typedef 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*/
274int cnd_init(cnd_t *cond);
275
276/** Release any resources used by the given condition variable.
277* @param cond A condition variable object.
278*/
279void 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*/
289int 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*/
299int 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*/
311int 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*/
325int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts);
326
327#if defined(_TTHREAD_WIN32_)
328int _cnd_timedwait_win32(cnd_t *cond, mtx_t *mtx, DWORD timeout);
329#endif
330
331/* Thread */
332#if defined(_TTHREAD_WIN32_)
333typedef HANDLE thrd_t;
334#else
335typedef 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*/
346typedef 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*/
360int 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*/
365thrd_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*/
371int 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*/
378int 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*/
383TTHREAD_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*/
394int 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*/
407int 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*/
413void thrd_yield(void);
414
415/* Thread local storage */
416#if defined(_TTHREAD_WIN32_)
417typedef DWORD tss_t;
418#else
419typedef 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*/
425typedef 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*/
439int 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*/
446void 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*/
453void *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*/
462int 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