123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444 |
- /* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; -*-
- Copyright (c) 2012 Marcus Geelnard
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source
- distribution.
- */
- #ifndef _TINYCTHREAD_H_
- #define _TINYCTHREAD_H_
- /**
- * @file
- * @mainpage TinyCThread API Reference
- *
- * @section intro_sec Introduction
- * TinyCThread is a minimal, portable implementation of basic threading
- * classes for C.
- *
- * They closely mimic the functionality and naming of the C11 standard, and
- * should be easily replaceable with the corresponding standard variants.
- *
- * @section port_sec Portability
- * The Win32 variant uses the native Win32 API for implementing the thread
- * classes, while for other systems, the POSIX threads API (pthread) is used.
- *
- * @section misc_sec Miscellaneous
- * The following special keywords are available: #_Thread_local.
- *
- * For more detailed information, browse the different sections of this
- * documentation. A good place to start is:
- * tinycthread.h.
- */
- /* Which platform are we on? */
- #if !defined(_TTHREAD_PLATFORM_DEFINED_)
- #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__)
- #define _TTHREAD_WIN32_
- #else
- #define _TTHREAD_POSIX_
- #endif
- #define _TTHREAD_PLATFORM_DEFINED_
- #endif
- /* Activate some POSIX functionality (e.g. clock_gettime and recursive mutexes) */
- #if defined(_TTHREAD_POSIX_)
- #undef _FEATURES_H
- #if !defined(_GNU_SOURCE)
- #define _GNU_SOURCE
- #endif
- #if !defined(_POSIX_C_SOURCE) || ((_POSIX_C_SOURCE - 0) < 199309L)
- #undef _POSIX_C_SOURCE
- #define _POSIX_C_SOURCE 199309L
- #endif
- #if !defined(_XOPEN_SOURCE) || ((_XOPEN_SOURCE - 0) < 500)
- #undef _XOPEN_SOURCE
- #define _XOPEN_SOURCE 500
- #endif
- #endif
- /* Generic includes */
- #include <time.h>
- /* Platform specific includes */
- #if defined(_TTHREAD_POSIX_)
- #include <sys/time.h>
- #include <pthread.h>
- #elif defined(_TTHREAD_WIN32_)
- #ifndef WIN32_LEAN_AND_MEAN
- #define WIN32_LEAN_AND_MEAN
- #define __UNDEF_LEAN_AND_MEAN
- #endif
- #include <windows.h>
- #ifdef __UNDEF_LEAN_AND_MEAN
- #undef WIN32_LEAN_AND_MEAN
- #undef __UNDEF_LEAN_AND_MEAN
- #endif
- #endif
- /* Workaround for missing TIME_UTC: If time.h doesn't provide TIME_UTC,
- it's quite likely that libc does not support it either. Hence, fall back to
- the only other supported time specifier: CLOCK_REALTIME (and if that fails,
- we're probably emulating clock_gettime anyway, so anything goes). */
- #ifndef TIME_UTC
- #ifdef CLOCK_REALTIME
- #define TIME_UTC CLOCK_REALTIME
- #else
- #define TIME_UTC 0
- #endif
- #endif
- /* Workaround for missing clock_gettime (most Windows compilers, afaik) */
- #if defined(_TTHREAD_WIN32_) || defined(__APPLE_CC__)
- #define _TTHREAD_EMULATE_CLOCK_GETTIME_
- /* Emulate struct timespec */
- #if defined(_TTHREAD_WIN32_)
- struct _ttherad_timespec {
- time_t tv_sec;
- long tv_nsec;
- };
- #define timespec _ttherad_timespec
- #endif
- /* Emulate clockid_t */
- typedef int _tthread_clockid_t;
- #define clockid_t _tthread_clockid_t
- /* Emulate clock_gettime */
- int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts);
- #define clock_gettime _tthread_clock_gettime
- #ifndef CLOCK_REALTIME
- #define CLOCK_REALTIME 0
- #endif
- #endif
- /** TinyCThread version (major number). */
- #define TINYCTHREAD_VERSION_MAJOR 1
- /** TinyCThread version (minor number). */
- #define TINYCTHREAD_VERSION_MINOR 1
- /** TinyCThread version (full version). */
- #define TINYCTHREAD_VERSION (TINYCTHREAD_VERSION_MAJOR * 100 + TINYCTHREAD_VERSION_MINOR)
- /**
- * @def _Thread_local
- * Thread local storage keyword.
- * A variable that is declared with the @c _Thread_local keyword makes the
- * value of the variable local to each thread (known as thread-local storage,
- * or TLS). Example usage:
- * @code
- * // This variable is local to each thread.
- * _Thread_local int variable;
- * @endcode
- * @note The @c _Thread_local keyword is a macro that maps to the corresponding
- * compiler directive (e.g. @c __declspec(thread)).
- * @note This directive is currently not supported on Mac OS X (it will give
- * a compiler error), since compile-time TLS is not supported in the Mac OS X
- * executable format. Also, some older versions of MinGW (before GCC 4.x) do
- * not support this directive.
- * @hideinitializer
- */
- /* FIXME: Check for a PROPER value of __STDC_VERSION__ to know if we have C11 */
- #if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201102L)) && !defined(_Thread_local)
- #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__)
- #define _Thread_local __thread
- #else
- #define _Thread_local __declspec(thread)
- #endif
- #endif
- /* Macros */
- #define TSS_DTOR_ITERATIONS 0
- /* Function return values */
- #define thrd_error 0 /**< The requested operation failed */
- #define thrd_success 1 /**< The requested operation succeeded */
- #define thrd_timeout 2 /**< The time specified in the call was reached without acquiring the requested resource */
- #define thrd_busy 3 /**< The requested operation failed because a tesource requested by a test and return function is already in use */
- #define thrd_nomem 4 /**< The requested operation failed because it was unable to allocate memory */
- /* Mutex types */
- #define mtx_plain 1
- #define mtx_timed 2
- #define mtx_try 4
- #define mtx_recursive 8
- /* Mutex */
- #if defined(_TTHREAD_WIN32_)
- typedef struct {
- CRITICAL_SECTION mHandle; /* Critical section handle */
- int mAlreadyLocked; /* TRUE if the mutex is already locked */
- int mRecursive; /* TRUE if the mutex is recursive */
- } mtx_t;
- #else
- typedef pthread_mutex_t mtx_t;
- #endif
- /** Create a mutex object.
- * @param mtx A mutex object.
- * @param type Bit-mask that must have one of the following six values:
- * @li @c mtx_plain for a simple non-recursive mutex
- * @li @c mtx_timed for a non-recursive mutex that supports timeout
- * @li @c mtx_try for a non-recursive mutex that supports test and return
- * @li @c mtx_plain | @c mtx_recursive (same as @c mtx_plain, but recursive)
- * @li @c mtx_timed | @c mtx_recursive (same as @c mtx_timed, but recursive)
- * @li @c mtx_try | @c mtx_recursive (same as @c mtx_try, but recursive)
- * @return @ref thrd_success on success, or @ref thrd_error if the request could
- * not be honored.
- */
- int mtx_init(mtx_t *mtx, int type);
- /** Release any resources used by the given mutex.
- * @param mtx A mutex object.
- */
- void mtx_destroy(mtx_t *mtx);
- /** Lock the given mutex.
- * Blocks until the given mutex can be locked. If the mutex is non-recursive, and
- * the calling thread already has a lock on the mutex, this call will block
- * forever.
- * @param mtx A mutex object.
- * @return @ref thrd_success on success, or @ref thrd_error if the request could
- * not be honored.
- */
- int mtx_lock(mtx_t *mtx);
- /** NOT YET IMPLEMENTED.
- */
- int mtx_timedlock(mtx_t *mtx, const struct timespec *ts);
- /** Try to lock the given mutex.
- * The specified mutex shall support either test and return or timeout. If the
- * mutex is already locked, the function returns without blocking.
- * @param mtx A mutex object.
- * @return @ref thrd_success on success, or @ref thrd_busy if the resource
- * requested is already in use, or @ref thrd_error if the request could not be
- * honored.
- */
- int mtx_trylock(mtx_t *mtx);
- /** Unlock the given mutex.
- * @param mtx A mutex object.
- * @return @ref thrd_success on success, or @ref thrd_error if the request could
- * not be honored.
- */
- int mtx_unlock(mtx_t *mtx);
- /* Condition variable */
- #if defined(_TTHREAD_WIN32_)
- typedef struct {
- HANDLE mEvents[2]; /* Signal and broadcast event HANDLEs. */
- unsigned int mWaitersCount; /* Count of the number of waiters. */
- CRITICAL_SECTION mWaitersCountLock; /* Serialize access to mWaitersCount. */
- } cnd_t;
- #else
- typedef pthread_cond_t cnd_t;
- #endif
- /** Create a condition variable object.
- * @param cond A condition variable object.
- * @return @ref thrd_success on success, or @ref thrd_error if the request could
- * not be honored.
- */
- int cnd_init(cnd_t *cond);
- /** Release any resources used by the given condition variable.
- * @param cond A condition variable object.
- */
- void cnd_destroy(cnd_t *cond);
- /** Signal a condition variable.
- * Unblocks one of the threads that are blocked on the given condition variable
- * at the time of the call. If no threads are blocked on the condition variable
- * at the time of the call, the function does nothing and return success.
- * @param cond A condition variable object.
- * @return @ref thrd_success on success, or @ref thrd_error if the request could
- * not be honored.
- */
- int cnd_signal(cnd_t *cond);
- /** Broadcast a condition variable.
- * Unblocks all of the threads that are blocked on the given condition variable
- * at the time of the call. If no threads are blocked on the condition variable
- * at the time of the call, the function does nothing and return success.
- * @param cond A condition variable object.
- * @return @ref thrd_success on success, or @ref thrd_error if the request could
- * not be honored.
- */
- int cnd_broadcast(cnd_t *cond);
- /** Wait for a condition variable to become signaled.
- * The function atomically unlocks the given mutex and endeavors to block until
- * the given condition variable is signaled by a call to cnd_signal or to
- * cnd_broadcast. When the calling thread becomes unblocked it locks the mutex
- * before it returns.
- * @param cond A condition variable object.
- * @param mtx A mutex object.
- * @return @ref thrd_success on success, or @ref thrd_error if the request could
- * not be honored.
- */
- int cnd_wait(cnd_t *cond, mtx_t *mtx);
- /** Wait for a condition variable to become signaled.
- * The function atomically unlocks the given mutex and endeavors to block until
- * the given condition variable is signaled by a call to cnd_signal or to
- * cnd_broadcast, or until after the specified time. When the calling thread
- * becomes unblocked it locks the mutex before it returns.
- * @param cond A condition variable object.
- * @param mtx A mutex object.
- * @param xt A point in time at which the request will time out (absolute time).
- * @return @ref thrd_success upon success, or @ref thrd_timeout if the time
- * specified in the call was reached without acquiring the requested resource, or
- * @ref thrd_error if the request could not be honored.
- */
- int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts);
- /* Thread */
- #if defined(_TTHREAD_WIN32_)
- typedef HANDLE thrd_t;
- #else
- typedef pthread_t thrd_t;
- #endif
- /** Thread start function.
- * Any thread that is started with the @ref thrd_create() function must be
- * started through a function of this type.
- * @param arg The thread argument (the @c arg argument of the corresponding
- * @ref thrd_create() call).
- * @return The thread return value, which can be obtained by another thread
- * by using the @ref thrd_join() function.
- */
- typedef int (*thrd_start_t)(void *arg);
- /** Create a new thread.
- * @param thr Identifier of the newly created thread.
- * @param func A function pointer to the function that will be executed in
- * the new thread.
- * @param arg An argument to the thread function.
- * @return @ref thrd_success on success, or @ref thrd_nomem if no memory could
- * be allocated for the thread requested, or @ref thrd_error if the request
- * could not be honored.
- * @note A thread’s identifier may be reused for a different thread once the
- * original thread has exited and either been detached or joined to another
- * thread.
- */
- int thrd_create(thrd_t *thr, thrd_start_t func, void *arg);
- /** Identify the calling thread.
- * @return The identifier of the calling thread.
- */
- thrd_t thrd_current(void);
- /** NOT YET IMPLEMENTED.
- */
- int thrd_detach(thrd_t thr);
- /** Compare two thread identifiers.
- * The function determines if two thread identifiers refer to the same thread.
- * @return Zero if the two thread identifiers refer to different threads.
- * Otherwise a nonzero value is returned.
- */
- int thrd_equal(thrd_t thr0, thrd_t thr1);
- /** Terminate execution of the calling thread.
- * @param res Result code of the calling thread.
- */
- void thrd_exit(int res);
- /** Wait for a thread to terminate.
- * The function joins the given thread with the current thread by blocking
- * until the other thread has terminated.
- * @param thr The thread to join with.
- * @param res If this pointer is not NULL, the function will store the result
- * code of the given thread in the integer pointed to by @c res.
- * @return @ref thrd_success on success, or @ref thrd_error if the request could
- * not be honored.
- */
- int thrd_join(thrd_t thr, int *res);
- /** Put the calling thread to sleep.
- * Suspend execution of the calling thread.
- * @param time_point A point in time at which the thread will resume (absolute time).
- * @param remaining If non-NULL, this parameter will hold the remaining time until
- * time_point upon return. This will typically be zero, but if
- * the thread was woken up by a signal that is not ignored before
- * time_point was reached @c remaining will hold a positive
- * time.
- * @return 0 (zero) on successful sleep, or -1 if an interrupt occurred.
- */
- int thrd_sleep(const struct timespec *time_point, struct timespec *remaining);
- /** Yield execution to another thread.
- * Permit other threads to run, even if the current thread would ordinarily
- * continue to run.
- */
- void thrd_yield(void);
- /* Thread local storage */
- #if defined(_TTHREAD_WIN32_)
- typedef DWORD tss_t;
- #else
- typedef pthread_key_t tss_t;
- #endif
- /** Destructor function for a thread-specific storage.
- * @param val The value of the destructed thread-specific storage.
- */
- typedef void (*tss_dtor_t)(void *val);
- /** Create a thread-specific storage.
- * @param key The unique key identifier that will be set if the function is
- * successful.
- * @param dtor Destructor function. This can be NULL.
- * @return @ref thrd_success on success, or @ref thrd_error if the request could
- * not be honored.
- * @note The destructor function is not supported under Windows. If @c dtor is
- * not NULL when calling this function under Windows, the function will fail
- * and return @ref thrd_error.
- */
- int tss_create(tss_t *key, tss_dtor_t dtor);
- /** Delete a thread-specific storage.
- * The function releases any resources used by the given thread-specific
- * storage.
- * @param key The key that shall be deleted.
- */
- void tss_delete(tss_t key);
- /** Get the value for a thread-specific storage.
- * @param key The thread-specific storage identifier.
- * @return The value for the current thread held in the given thread-specific
- * storage.
- */
- void *tss_get(tss_t key);
- /** Set the value for a thread-specific storage.
- * @param key The thread-specific storage identifier.
- * @param val The value of the thread-specific storage to set for the current
- * thread.
- * @return @ref thrd_success on success, or @ref thrd_error if the request could
- * not be honored.
- */
- int tss_set(tss_t key, void *val);
- #endif /* _TINYTHREAD_H_ */
|