1 /* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; -*-
2 Copyright (c) 2012 Marcus Geelnard
3 Copyright (c) 2013-2016 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 #ifdef __cplusplus
29 extern "C" {
30 #endif
31 
32 #include "badthreads.h"
33 
34 // jcheng 2017-11-03: _XOPEN_SOURCE 600 is necessary to prevent Solaris headers
35 // from complaining about the combination of C99 and _XOPEN_SOURCE <= 500. The
36 // error message starts with:
37 // "Compiler or options invalid for pre-UNIX 03 X/Open applications"
38 #if defined(sun) && (__STDC_VERSION__ - 0 >= 199901L) && (!defined(_XOPEN_SOURCE) || ((_XOPEN_SOURCE - 0) < 600))
39   #undef _XOPEN_SOURCE
40   #define _XOPEN_SOURCE 600
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   #define _XPG6
91 #endif
92 
93 /* Generic includes */
94 #include <time.h>
95 
96 /* Platform specific includes */
97 #if defined(_TTHREAD_POSIX_)
98   #include <pthread.h>
99 #elif defined(_TTHREAD_WIN32_)
100   #ifndef WIN32_LEAN_AND_MEAN
101     #define WIN32_LEAN_AND_MEAN
102     #define __UNDEF_LEAN_AND_MEAN
103   #endif
104   #include <windows.h>
105   #ifdef __UNDEF_LEAN_AND_MEAN
106     #undef WIN32_LEAN_AND_MEAN
107     #undef __UNDEF_LEAN_AND_MEAN
108   #endif
109 #endif
110 
111 /* Compiler-specific information */
112 #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
113   #define TTHREAD_NORETURN _Noreturn
114 #elif defined(__GNUC__)
115   #define TTHREAD_NORETURN __attribute__((__noreturn__))
116 #else
117   #define TTHREAD_NORETURN
118 #endif
119 
120 /* If TIME_UTC is missing, provide it and provide a wrapper for
121    timespec_get. */
122 #ifndef TIME_UTC
123 #define TIME_UTC 1
124 #define _TTHREAD_EMULATE_TIMESPEC_GET_
125 
126 #if defined(_TTHREAD_WIN32_)
127 struct _tthread_timespec {
128   time_t tv_sec;
129   long   tv_nsec;
130 };
131 #define timespec _tthread_timespec
132 #endif
133 
134 int _tthread_timespec_get(struct timespec *ts, int base);
135 #define timespec_get _tthread_timespec_get
136 #endif
137 
138 /** TinyCThread version (major number). */
139 #define TINYCTHREAD_VERSION_MAJOR 1
140 /** TinyCThread version (minor number). */
141 #define TINYCTHREAD_VERSION_MINOR 2
142 /** TinyCThread version (full version). */
143 #define TINYCTHREAD_VERSION (TINYCTHREAD_VERSION_MAJOR * 100 + TINYCTHREAD_VERSION_MINOR)
144 
145 /**
146 * @def _Thread_local
147 * Thread local storage keyword.
148 * A variable that is declared with the @c _Thread_local keyword makes the
149 * value of the variable local to each thread (known as thread-local storage,
150 * or TLS). Example usage:
151 * @code
152 * // This variable is local to each thread.
153 * _Thread_local int variable;
154 * @endcode
155 * @note The @c _Thread_local keyword is a macro that maps to the corresponding
156 * compiler directive (e.g. @c __declspec(thread)).
157 * @note This directive is currently not supported on Mac OS X (it will give
158 * a compiler error), since compile-time TLS is not supported in the Mac OS X
159 * executable format. Also, some older versions of MinGW (before GCC 4.x) do
160 * not support this directive, nor does the Tiny C Compiler.
161 * @hideinitializer
162 */
163 
164 #if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201102L)) && !defined(_Thread_local)
165  #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__)
166   #define _Thread_local __thread
167  #else
168   #define _Thread_local __declspec(thread)
169  #endif
170 #elif defined(__GNUC__) && defined(__GNUC_MINOR__) && (((__GNUC__ << 8) | __GNUC_MINOR__) < ((4 << 8) | 9))
171  #define _Thread_local __thread
172 #endif
173 
174 /* Macros */
175 #if defined(_TTHREAD_WIN32_)
176 #define TCT_TSS_DTOR_ITERATIONS (4)
177 #else
178 #define TCT_TSS_DTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS
179 #endif
180 
181 /* Function return values */
182 #define tct_thrd_error    0 /**< The requested operation failed */
183 #define tct_thrd_success  1 /**< The requested operation succeeded */
184 #define tct_thrd_timedout 2 /**< The time specified in the call was reached without acquiring the requested resource */
185 #define tct_thrd_busy     3 /**< The requested operation failed because a tesource requested by a test and return function is already in use */
186 #define tct_thrd_nomem    4 /**< The requested operation failed because it was unable to allocate memory */
187 
188 /* Mutex types */
189 #define tct_mtx_plain     0
190 #define tct_mtx_timed     1
191 #define tct_mtx_recursive 2
192 
193 /* Mutex */
194 #if defined(_TTHREAD_WIN32_)
195 typedef struct {
196   union {
197     CRITICAL_SECTION cs;      /* Critical section handle (used for non-timed mutexes) */
198     HANDLE mut;               /* Mutex handle (used for timed mutex) */
199   } mHandle;                  /* Mutex handle */
200   int mAlreadyLocked;         /* TRUE if the mutex is already locked */
201   int mRecursive;             /* TRUE if the mutex is recursive */
202   int mTimed;                 /* TRUE if the mutex is timed */
203 } tct_mtx_t;
204 #else
205 typedef pthread_mutex_t tct_mtx_t;
206 #endif
207 
208 /** Create a mutex object.
209 * @param mtx A mutex object.
210 * @param type Bit-mask that must have one of the following six values:
211 *   @li @c mtx_plain for a simple non-recursive mutex
212 *   @li @c mtx_timed for a non-recursive mutex that supports timeout
213 *   @li @c mtx_plain | @c mtx_recursive (same as @c mtx_plain, but recursive)
214 *   @li @c mtx_timed | @c mtx_recursive (same as @c mtx_timed, but recursive)
215 * @return @ref thrd_success on success, or @ref thrd_error if the request could
216 * not be honored.
217 */
218 int tct_mtx_init(tct_mtx_t *mtx, int type);
219 
220 /** Release any resources used by the given mutex.
221 * @param mtx A mutex object.
222 */
223 void tct_mtx_destroy(tct_mtx_t *mtx);
224 
225 /** Lock the given mutex.
226 * Blocks until the given mutex can be locked. If the mutex is non-recursive, and
227 * the calling thread already has a lock on the mutex, this call will block
228 * forever.
229 * @param mtx A mutex object.
230 * @return @ref thrd_success on success, or @ref thrd_error if the request could
231 * not be honored.
232 */
233 int tct_mtx_lock(tct_mtx_t *mtx);
234 
235 /** Lock the given mutex, or block until a specific point in time.
236 * Blocks until either the given mutex can be locked, or the specified TIME_UTC
237 * based time.
238 * @param mtx A mutex object.
239 * @param ts A UTC based calendar time
240 * @return @ref The mtx_timedlock function returns thrd_success on success, or
241 * thrd_timedout if the time specified was reached without acquiring the
242 * requested resource, or thrd_error if the request could not be honored.
243 */
244 int tct_mtx_timedlock(tct_mtx_t *mtx, const struct timespec *ts);
245 
246 /** Try to lock the given mutex.
247 * The specified mutex shall support either test and return or timeout. If the
248 * mutex is already locked, the function returns without blocking.
249 * @param mtx A mutex object.
250 * @return @ref thrd_success on success, or @ref thrd_busy if the resource
251 * requested is already in use, or @ref thrd_error if the request could not be
252 * honored.
253 */
254 int tct_mtx_trylock(tct_mtx_t *mtx);
255 
256 /** Unlock the given mutex.
257 * @param mtx A mutex object.
258 * @return @ref thrd_success on success, or @ref thrd_error if the request could
259 * not be honored.
260 */
261 int tct_mtx_unlock(tct_mtx_t *mtx);
262 
263 /* Condition variable */
264 #if defined(_TTHREAD_WIN32_)
265 typedef struct {
266   HANDLE mEvents[2];                  /* Signal and broadcast event HANDLEs. */
267   unsigned int mWaitersCount;         /* Count of the number of waiters. */
268   CRITICAL_SECTION mWaitersCountLock; /* Serialize access to mWaitersCount. */
269 } tct_cnd_t;
270 #else
271 typedef pthread_cond_t tct_cnd_t;
272 #endif
273 
274 /** Create a condition variable object.
275 * @param cond A condition variable object.
276 * @return @ref thrd_success on success, or @ref thrd_error if the request could
277 * not be honored.
278 */
279 int tct_cnd_init(tct_cnd_t *cond);
280 
281 /** Release any resources used by the given condition variable.
282 * @param cond A condition variable object.
283 */
284 void tct_cnd_destroy(tct_cnd_t *cond);
285 
286 /** Signal a condition variable.
287 * Unblocks one of the threads that are blocked on the given condition variable
288 * at the time of the call. If no threads are blocked on the condition variable
289 * at the time of the call, the function does nothing and return success.
290 * @param cond A condition variable object.
291 * @return @ref thrd_success on success, or @ref thrd_error if the request could
292 * not be honored.
293 */
294 int tct_cnd_signal(tct_cnd_t *cond);
295 
296 /** Broadcast a condition variable.
297 * Unblocks all of the threads that are blocked on the given condition variable
298 * at the time of the call. If no threads are blocked on the condition variable
299 * at the time of the call, the function does nothing and return success.
300 * @param cond A condition variable object.
301 * @return @ref thrd_success on success, or @ref thrd_error if the request could
302 * not be honored.
303 */
304 int tct_cnd_broadcast(tct_cnd_t *cond);
305 
306 /** Wait for a condition variable to become signaled.
307 * The function atomically unlocks the given mutex and endeavors to block until
308 * the given condition variable is signaled by a call to cnd_signal or to
309 * cnd_broadcast. When the calling thread becomes unblocked it locks the mutex
310 * before it returns.
311 * @param cond A condition variable object.
312 * @param mtx A mutex object.
313 * @return @ref thrd_success on success, or @ref thrd_error if the request could
314 * not be honored.
315 */
316 int tct_cnd_wait(tct_cnd_t *cond, tct_mtx_t *mtx);
317 
318 /** Wait for a condition variable to become signaled.
319 * The function atomically unlocks the given mutex and endeavors to block until
320 * the given condition variable is signaled by a call to cnd_signal or to
321 * cnd_broadcast, or until after the specified time. When the calling thread
322 * becomes unblocked it locks the mutex before it returns.
323 * @param cond A condition variable object.
324 * @param mtx A mutex object.
325 * @param xt A point in time at which the request will time out (absolute time).
326 * @return @ref thrd_success upon success, or @ref thrd_timeout if the time
327 * specified in the call was reached without acquiring the requested resource, or
328 * @ref thrd_error if the request could not be honored.
329 */
330 int tct_cnd_timedwait(tct_cnd_t *cond, tct_mtx_t *mtx, const struct timespec *ts);
331 
332 /* Thread */
333 #if defined(_TTHREAD_WIN32_)
334 typedef HANDLE tct_thrd_t;
335 #else
336 typedef pthread_t tct_thrd_t;
337 #endif
338 
339 /** Thread start function.
340 * Any thread that is started with the @ref thrd_create() function must be
341 * started through a function of this type.
342 * @param arg The thread argument (the @c arg argument of the corresponding
343 *        @ref thrd_create() call).
344 * @return The thread return value, which can be obtained by another thread
345 * by using the @ref thrd_join() function.
346 */
347 typedef int (*tct_thrd_start_t)(void *arg);
348 
349 /** Create a new thread.
350 * @param thr Identifier of the newly created thread.
351 * @param func A function pointer to the function that will be executed in
352 *        the new thread.
353 * @param arg An argument to the thread function.
354 * @return @ref thrd_success on success, or @ref thrd_nomem if no memory could
355 * be allocated for the thread requested, or @ref thrd_error if the request
356 * could not be honored.
357 * @note A thread’s identifier may be reused for a different thread once the
358 * original thread has exited and either been detached or joined to another
359 * thread.
360 */
361 int tct_thrd_create(tct_thrd_t *thr, tct_thrd_start_t func, void *arg);
362 
363 /** Identify the calling thread.
364 * @return The identifier of the calling thread.
365 */
366 tct_thrd_t tct_thrd_current(void);
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 tct_thrd_detach(tct_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 tct_thrd_equal(tct_thrd_t thr0, tct_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 tct_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 tct_thrd_join(tct_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 tct_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 tct_thrd_yield(void);
414 
415 /* Thread local storage */
416 #if defined(_TTHREAD_WIN32_)
417 typedef DWORD tct_tss_t;
418 #else
419 typedef pthread_key_t tct_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 (*tct_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 tct_tss_create(tct_tss_t *key, tct_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 tct_tss_delete(tct_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 *tct_tss_get(tct_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 tct_tss_set(tct_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 tct_call_once(once_flag *flag, void (*func)(void));
482 #else
483   #define tct_call_once(flag,func) pthread_once(flag,func)
484 #endif
485 
486 #ifdef __cplusplus
487 }
488 #endif
489 
490 #endif /* _TINYTHREAD_H_ */
491