From 5e075ee8672530de5e41fb2d9896d43dac63722c Mon Sep 17 00:00:00 2001 From: Winston Chang Date: Thu, 3 Jan 2019 13:35:44 -0600 Subject: [PATCH] Use tinycthread on all platforms This also changes the function names in tinycthread so that they don't conflict with (and inadverantly link to) functions with the same name from C11-style threads.h. --- .gitignore | 1 - cleanup | 3 - configure | 45 ------- src/{Makevars.in => Makevars} | 6 +- src/Makevars.win | 7 - src/badthreads.h | 58 +++++++++ src/c11threads.h | 16 --- src/callback_registry.cpp | 2 +- src/debug.h | 2 +- src/later_posix.cpp | 2 +- src/threadutils.h | 38 +++--- src/timeconv.h | 2 +- src/{tinycthread => }/tinycthread.c | 195 ++++++++++++++-------------- src/{tinycthread => }/tinycthread.h | 90 ++++++------- 14 files changed, 227 insertions(+), 240 deletions(-) delete mode 100755 cleanup delete mode 100755 configure rename src/{Makevars.in => Makevars} (50%) delete mode 100644 src/Makevars.win create mode 100644 src/badthreads.h delete mode 100644 src/c11threads.h rename src/{tinycthread => }/tinycthread.c (81%) rename src/{tinycthread => }/tinycthread.h (87%) diff --git a/.gitignore b/.gitignore index 60daf7e2..29e3fd68 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,3 @@ *.so *.dll inst/doc -src/Makevars diff --git a/cleanup b/cleanup deleted file mode 100755 index 62aa98a8..00000000 --- a/cleanup +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -rm -f src/Makevars -rm -f src/tinycthread/tinycthread.o diff --git a/configure b/configure deleted file mode 100755 index 28a593b9..00000000 --- a/configure +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/sh - -echo "Running configure script" - -# Find compiler -CC=`${R_HOME}/bin/R CMD config CC` -CFLAGS=`${R_HOME}/bin/R CMD config CFLAGS` -CPPFLAGS=`${R_HOME}/bin/R CMD config CPPFLAGS` - -# Same as from src/Makevars -LATER_PKG_LIBS=-pthread - -# For debugging -echo "Using CC=$CC" -echo "Using CFLAGS=$CFLAGS" -echo "Using CPPFLAGS=$CPPFLAGS" - - -# Detect support for C11-style threads.h. This checks for both the presence of -# the header file, and the availability of threading functions when linked -# using -pthread. Some C11 implementations don't have threads.h; on some platforms, -# compiling with an earlier C standard (like -std=c99) will work with threads.h -# and -pthread. -echo "#include -int main() { - mtx_t mutex; - mtx_init(&mutex, mtx_plain); - return 0; -}" | ${CC} ${CPPFLAGS} ${CFLAGS} ${LATER_PKG_LIBS} -x c - -o /dev/null > /dev/null 2>&1 - -if [ $? -eq 0 ]; then - echo "C11-style threads.h support detected." - PKG_CPPFLAGS=-DTHREADS_H_SUPPORT=1 -else - echo "C11-style threads.h support not detected. Using tinycthread library." - PKG_CPPFLAGS=-DTHREADS_H_SUPPORT=-1 - PKG_LIBS=./tinycthread/tinycthread.o -fi - - -# Write to Makevars -sed -e "s|@cppflags@|$PKG_CPPFLAGS|" -e "s|@libs@|$PKG_LIBS|" src/Makevars.in > src/Makevars - -# Success -exit 0 diff --git a/src/Makevars.in b/src/Makevars similarity index 50% rename from src/Makevars.in rename to src/Makevars index aa7e48b8..21798bca 100644 --- a/src/Makevars.in +++ b/src/Makevars @@ -1,7 +1,5 @@ -PKG_CPPFLAGS = -pthread @cppflags@ -PKG_LIBS = -pthread @libs@ +PKG_CPPFLAGS = -pthread +PKG_LIBS = -pthread # Uncomment to enable thread assertions # PKG_CPPFLAGS += -DDEBUG_THREAD -UNDEBUG - -$(SHLIB): @libs@ diff --git a/src/Makevars.win b/src/Makevars.win deleted file mode 100644 index ab9c4db1..00000000 --- a/src/Makevars.win +++ /dev/null @@ -1,7 +0,0 @@ -PKG_CPPFLAGS += -DTHREADS_H_SUPPORT=-1 -PKG_LIBS += ./tinycthread/tinycthread.o - -# Uncomment to enable thread assertions -# PKG_CPPFLAGS += -DDEBUG_THREAD -UNDEBUG - -$(SHLIB): ./tinycthread/tinycthread.o diff --git a/src/badthreads.h b/src/badthreads.h new file mode 100644 index 00000000..fb985e28 --- /dev/null +++ b/src/badthreads.h @@ -0,0 +1,58 @@ +#ifndef _BADTHREADS_H_ +#define _BADTHREADS_H_ + +/* + * This file contains functions and symbols that are defined in C11 threads.h. + * If any of these symbols are used in a file that includes badthreads.h, it + * should throw an error at compile time. + * + * The purpose of this file is to make sure that code does not accidentally + * use symbols from threads.h. If this happens, and the system C library has + * C11-style thread support, then the resulting object could link to the + * system's functions that have the same name, instead of the local functions. +*/ + +#define thrd_t THREADS_H_ERROR +#define thrd_create THREADS_H_ERROR +#define thrd_equal THREADS_H_ERROR +#define thrd_current THREADS_H_ERROR +#define thrd_sleep THREADS_H_ERROR +#define thrd_yield THREADS_H_ERROR +#define thrd_exit THREADS_H_ERROR +#define thrd_detach THREADS_H_ERROR +#define thrd_join THREADS_H_ERROR +#define thrd_success THREADS_H_ERROR +#define thrd_timedout THREADS_H_ERROR +#define thrd_busy THREADS_H_ERROR +#define thrd_nomem THREADS_H_ERROR +#define thrd_error THREADS_H_ERROR +#define thrd_start_t THREADS_H_ERROR +#define mtx_t THREADS_H_ERROR +#define mtx_init THREADS_H_ERROR +#define mtx_lock THREADS_H_ERROR +#define mtx_timedlock THREADS_H_ERROR +#define mtx_trylock THREADS_H_ERROR +#define mtx_unlock THREADS_H_ERROR +#define mtx_destroy THREADS_H_ERROR +#define mtx_plain THREADS_H_ERROR +#define mtx_recursive THREADS_H_ERROR +#define mtx_timed THREADS_H_ERROR +#define call_once THREADS_H_ERROR +#define cnd_t THREADS_H_ERROR +#define cnd_init THREADS_H_ERROR +#define cnd_signal THREADS_H_ERROR +#define cnd_broadcast THREADS_H_ERROR +#define cnd_wait THREADS_H_ERROR +#define cnd_timedwait THREADS_H_ERROR +#define cnd_destroy THREADS_H_ERROR +#define thread_local THREADS_H_ERROR +#define tss_t THREADS_H_ERROR +#define TSS_DTOR_ITERATIONS THREADS_H_ERROR +#define tss_dtor_t THREADS_H_ERROR +#define tss_create THREADS_H_ERROR +#define tss_get THREADS_H_ERROR +#define tss_set THREADS_H_ERROR +#define tss_delete THREADS_H_ERROR + + +#endif diff --git a/src/c11threads.h b/src/c11threads.h deleted file mode 100644 index d83f70fa..00000000 --- a/src/c11threads.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _C11_THREADS_H_ -#define _C11_THREADS_H_ - - -/* If there's C11 support, use it; otherwise use tinycthread.h, - * which has a compatible API. */ -#if THREADS_H_SUPPORT==1 - #include -#elif THREADS_H_SUPPORT==-1 - #include "tinycthread/tinycthread.h" -#else - #error THREADS_H_SUPPORT must be set to 1 or -1. -#endif - - -#endif diff --git a/src/callback_registry.cpp b/src/callback_registry.cpp index caccc934..c2263cdf 100644 --- a/src/callback_registry.cpp +++ b/src/callback_registry.cpp @@ -41,7 +41,7 @@ void testCallbackOrdering() { } } -CallbackRegistry::CallbackRegistry() : mutex(mtx_recursive), condvar(mutex) { +CallbackRegistry::CallbackRegistry() : mutex(tct_mtx_recursive), condvar(mutex) { } void CallbackRegistry::add(Rcpp::Function func, double secs) { diff --git a/src/debug.h b/src/debug.h index 41779d17..374f6f3b 100644 --- a/src/debug.h +++ b/src/debug.h @@ -4,7 +4,7 @@ // See the Makevars file to see how to compile with various debugging settings. #if defined(DEBUG_THREAD) -#include "c11threads.h" +#include "tinycthread.h" extern thrd_t __main_thread__; extern thrd_t __background_thread__; diff --git a/src/later_posix.cpp b/src/later_posix.cpp index c9a44ab2..1137c8c3 100644 --- a/src/later_posix.cpp +++ b/src/later_posix.cpp @@ -38,7 +38,7 @@ int dummy_pipe_in, dummy_pipe_out; bool hot = false; // This mutex protects reading/writing of `hot` and of reading from/writing to // the pipe. -Mutex m(mtx_plain); +Mutex m(tct_mtx_plain); // The buffer we're using for the pipe. This doesn't have to be large, // in theory it only ever holds zero or one byte. diff --git a/src/threadutils.h b/src/threadutils.h index 935015e0..895fbe38 100644 --- a/src/threadutils.h +++ b/src/threadutils.h @@ -7,14 +7,14 @@ #include #include -#include "c11threads.h" +#include "tinycthread.h" #include "timeconv.h" class ConditionVariable; class Mutex : boost::noncopyable { friend class ConditionVariable; - mtx_t _m; + tct_mtx_t _m; public: // type must be one of: @@ -28,26 +28,26 @@ class Mutex : boost::noncopyable { // // (although mtx_timed seems not to be actually implemented) Mutex(int type) { - if (mtx_init(&_m, type) != thrd_success) { + if (tct_mtx_init(&_m, type) != tct_thrd_success) { throw std::runtime_error("Mutex creation failed"); } } virtual ~Mutex() { - mtx_destroy(&_m); + tct_mtx_destroy(&_m); } void lock() { - if (mtx_lock(&_m) != thrd_success) { + if (tct_mtx_lock(&_m) != tct_thrd_success) { throw std::runtime_error("Mutex failed to lock"); } } bool tryLock() { - int res = mtx_trylock(&_m); - if (res == thrd_success) { + int res = tct_mtx_trylock(&_m); + if (res == tct_thrd_success) { return true; - } else if (res == thrd_busy) { + } else if (res == tct_thrd_busy) { return false; } else { throw std::runtime_error("Mutex failed to trylock"); @@ -55,7 +55,7 @@ class Mutex : boost::noncopyable { } void unlock() { - if (mtx_unlock(&_m) != thrd_success) { + if (tct_mtx_unlock(&_m) != tct_thrd_success) { throw std::runtime_error("Mutex failed to unlock"); } } @@ -75,8 +75,8 @@ class Guard : boost::noncopyable { }; class ConditionVariable : boost::noncopyable { - mtx_t* _m; - cnd_t _c; + tct_mtx_t* _m; + tct_cnd_t _c; public: ConditionVariable(Mutex& mutex) : _m(&mutex._m) { @@ -89,28 +89,28 @@ class ConditionVariable : boost::noncopyable { if (!boost::is_signed::value) throw std::runtime_error("Signed time_t type expected"); - if (cnd_init(&_c) != thrd_success) + if (tct_cnd_init(&_c) != tct_thrd_success) throw std::runtime_error("Condition variable failed to initialize"); } virtual ~ConditionVariable() { - cnd_destroy(&_c); + tct_cnd_destroy(&_c); } // Unblocks one thread (if any are waiting) void signal() { - if (cnd_signal(&_c) != thrd_success) + if (tct_cnd_signal(&_c) != tct_thrd_success) throw std::runtime_error("Condition variable failed to signal"); } // Unblocks all waiting threads void broadcast() { - if (cnd_broadcast(&_c) != thrd_success) + if (tct_cnd_broadcast(&_c) != tct_thrd_success) throw std::runtime_error("Condition variable failed to broadcast"); } void wait() { - if (cnd_wait(&_c, _m) != thrd_success) + if (tct_cnd_wait(&_c, _m) != tct_thrd_success) throw std::runtime_error("Condition variable failed to wait"); } @@ -122,10 +122,10 @@ class ConditionVariable : boost::noncopyable { ts = addSeconds(ts, timeoutSecs); - int res = cnd_timedwait(&_c, _m, &ts); - if (res == thrd_success) { + int res = tct_cnd_timedwait(&_c, _m, &ts); + if (res == tct_thrd_success) { return true; - } else if (res == thrd_timedout) { + } else if (res == tct_thrd_timedout) { return false; } else { throw std::runtime_error("Condition variable failed to timedwait"); diff --git a/src/timeconv.h b/src/timeconv.h index fa479908..01103aee 100644 --- a/src/timeconv.h +++ b/src/timeconv.h @@ -3,7 +3,7 @@ // tinycthread.h to provide timespec. Whether tinycthread // defines timespec or not, we want it to be consistent for // anyone who uses these functions. -#include "c11threads.h" +#include "tinycthread.h" inline timespec timevalToTimespec(const timeval& tv) { timespec ts; diff --git a/src/tinycthread/tinycthread.c b/src/tinycthread.c similarity index 81% rename from src/tinycthread/tinycthread.c rename to src/tinycthread.c index 195e413f..f4657c16 100644 --- a/src/tinycthread/tinycthread.c +++ b/src/tinycthread.c @@ -23,6 +23,7 @@ freely, subject to the following restrictions: */ #include "tinycthread.h" +#include "badthreads.h" #include /* Platform specific includes */ @@ -53,12 +54,12 @@ extern "C" { #endif -int mtx_init(mtx_t *mtx, int type) +int tct_mtx_init(tct_mtx_t *mtx, int type) { #if defined(_TTHREAD_WIN32_) mtx->mAlreadyLocked = FALSE; - mtx->mRecursive = type & mtx_recursive; - mtx->mTimed = type & mtx_timed; + mtx->mRecursive = type & tct_mtx_recursive; + mtx->mTimed = type & tct_mtx_timed; if (!mtx->mTimed) { InitializeCriticalSection(&(mtx->mHandle.cs)); @@ -68,25 +69,25 @@ int mtx_init(mtx_t *mtx, int type) mtx->mHandle.mut = CreateMutex(NULL, FALSE, NULL); if (mtx->mHandle.mut == NULL) { - return thrd_error; + return tct_thrd_error; } } - return thrd_success; + return tct_thrd_success; #else int ret; pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); - if (type & mtx_recursive) + if (type & tct_mtx_recursive) { pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); } ret = pthread_mutex_init(mtx, &attr); pthread_mutexattr_destroy(&attr); - return ret == 0 ? thrd_success : thrd_error; + return ret == 0 ? tct_thrd_success : tct_thrd_error; #endif } -void mtx_destroy(mtx_t *mtx) +void tct_mtx_destroy(tct_mtx_t *mtx) { #if defined(_TTHREAD_WIN32_) if (!mtx->mTimed) @@ -102,7 +103,7 @@ void mtx_destroy(mtx_t *mtx) #endif } -int mtx_lock(mtx_t *mtx) +int tct_mtx_lock(tct_mtx_t *mtx) { #if defined(_TTHREAD_WIN32_) if (!mtx->mTimed) @@ -117,7 +118,7 @@ int mtx_lock(mtx_t *mtx) break; case WAIT_ABANDONED: default: - return thrd_error; + return tct_thrd_error; } } @@ -126,13 +127,13 @@ int mtx_lock(mtx_t *mtx) while(mtx->mAlreadyLocked) Sleep(1); /* Simulate deadlock... */ mtx->mAlreadyLocked = TRUE; } - return thrd_success; + return tct_thrd_success; #else - return pthread_mutex_lock(mtx) == 0 ? thrd_success : thrd_error; + return pthread_mutex_lock(mtx) == 0 ? tct_thrd_success : tct_thrd_error; #endif } -int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) +int tct_mtx_timedlock(tct_mtx_t *mtx, const struct timespec *ts) { #if defined(_TTHREAD_WIN32_) struct timespec current_ts; @@ -140,7 +141,7 @@ int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) if (!mtx->mTimed) { - return thrd_error; + return tct_thrd_error; } timespec_get(¤t_ts, TIME_UTC); @@ -163,10 +164,10 @@ int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) case WAIT_OBJECT_0: break; case WAIT_TIMEOUT: - return thrd_timedout; + return tct_thrd_timedout; case WAIT_ABANDONED: default: - return thrd_error; + return tct_thrd_error; } if (!mtx->mRecursive) @@ -175,15 +176,15 @@ int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) mtx->mAlreadyLocked = TRUE; } - return thrd_success; + return tct_thrd_success; #elif defined(_POSIX_TIMEOUTS) && (_POSIX_TIMEOUTS >= 200112L) && defined(_POSIX_THREADS) && (_POSIX_THREADS >= 200112L) switch (pthread_mutex_timedlock(mtx, ts)) { case 0: - return thrd_success; + return tct_thrd_success; case ETIMEDOUT: - return thrd_timedout; + return tct_thrd_timedout; default: - return thrd_error; + return tct_thrd_error; } #else int rc; @@ -217,36 +218,36 @@ int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) switch (rc) { case 0: - return thrd_success; + return tct_thrd_success; case ETIMEDOUT: case EBUSY: - return thrd_timedout; + return tct_thrd_timedout; default: - return thrd_error; + return tct_thrd_error; } #endif } -int mtx_trylock(mtx_t *mtx) +int tct_mtx_trylock(tct_mtx_t *mtx) { #if defined(_TTHREAD_WIN32_) int ret; if (!mtx->mTimed) { - ret = TryEnterCriticalSection(&(mtx->mHandle.cs)) ? thrd_success : thrd_busy; + ret = TryEnterCriticalSection(&(mtx->mHandle.cs)) ? tct_thrd_success : tct_thrd_busy; } else { - ret = (WaitForSingleObject(mtx->mHandle.mut, 0) == WAIT_OBJECT_0) ? thrd_success : thrd_busy; + ret = (WaitForSingleObject(mtx->mHandle.mut, 0) == WAIT_OBJECT_0) ? tct_thrd_success : tct_thrd_busy; } - if ((!mtx->mRecursive) && (ret == thrd_success)) + if ((!mtx->mRecursive) && (ret == tct_thrd_success)) { if (mtx->mAlreadyLocked) { LeaveCriticalSection(&(mtx->mHandle.cs)); - ret = thrd_busy; + ret = tct_thrd_busy; } else { @@ -255,11 +256,11 @@ int mtx_trylock(mtx_t *mtx) } return ret; #else - return (pthread_mutex_trylock(mtx) == 0) ? thrd_success : thrd_busy; + return (pthread_mutex_trylock(mtx) == 0) ? tct_thrd_success : tct_thrd_busy; #endif } -int mtx_unlock(mtx_t *mtx) +int tct_mtx_unlock(tct_mtx_t *mtx) { #if defined(_TTHREAD_WIN32_) mtx->mAlreadyLocked = FALSE; @@ -271,12 +272,12 @@ int mtx_unlock(mtx_t *mtx) { if (!ReleaseMutex(mtx->mHandle.mut)) { - return thrd_error; + return tct_thrd_error; } } - return thrd_success; + return tct_thrd_success; #else - return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error;; + return pthread_mutex_unlock(mtx) == 0 ? tct_thrd_success : tct_thrd_error;; #endif } @@ -285,7 +286,7 @@ int mtx_unlock(mtx_t *mtx) #define _CONDITION_EVENT_ALL 1 #endif -int cnd_init(cnd_t *cond) +int tct_cnd_init(tct_cnd_t *cond) { #if defined(_TTHREAD_WIN32_) cond->mWaitersCount = 0; @@ -298,23 +299,23 @@ int cnd_init(cnd_t *cond) if (cond->mEvents[_CONDITION_EVENT_ONE] == NULL) { cond->mEvents[_CONDITION_EVENT_ALL] = NULL; - return thrd_error; + return tct_thrd_error; } cond->mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL); if (cond->mEvents[_CONDITION_EVENT_ALL] == NULL) { CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]); cond->mEvents[_CONDITION_EVENT_ONE] = NULL; - return thrd_error; + return tct_thrd_error; } - return thrd_success; + return tct_thrd_success; #else - return pthread_cond_init(cond, NULL) == 0 ? thrd_success : thrd_error; + return pthread_cond_init(cond, NULL) == 0 ? tct_thrd_success : tct_thrd_error; #endif } -void cnd_destroy(cnd_t *cond) +void tct_cnd_destroy(tct_cnd_t *cond) { #if defined(_TTHREAD_WIN32_) if (cond->mEvents[_CONDITION_EVENT_ONE] != NULL) @@ -331,7 +332,7 @@ void cnd_destroy(cnd_t *cond) #endif } -int cnd_signal(cnd_t *cond) +int tct_cnd_signal(tct_cnd_t *cond) { #if defined(_TTHREAD_WIN32_) int haveWaiters; @@ -346,17 +347,17 @@ int cnd_signal(cnd_t *cond) { if (SetEvent(cond->mEvents[_CONDITION_EVENT_ONE]) == 0) { - return thrd_error; + return tct_thrd_error; } } - return thrd_success; + return tct_thrd_success; #else - return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; + return pthread_cond_signal(cond) == 0 ? tct_thrd_success : tct_thrd_error; #endif } -int cnd_broadcast(cnd_t *cond) +int tct_cnd_broadcast(tct_cnd_t *cond) { #if defined(_TTHREAD_WIN32_) int haveWaiters; @@ -371,18 +372,18 @@ int cnd_broadcast(cnd_t *cond) { if (SetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0) { - return thrd_error; + return tct_thrd_error; } } - return thrd_success; + return tct_thrd_success; #else - return pthread_cond_broadcast(cond) == 0 ? thrd_success : thrd_error; + return pthread_cond_broadcast(cond) == 0 ? tct_thrd_success : tct_thrd_error; #endif } #if defined(_TTHREAD_WIN32_) -static int _cnd_timedwait_win32(cnd_t *cond, mtx_t *mtx, DWORD timeout) +static int _cnd_timedwait_win32(tct_cnd_t *cond, tct_mtx_t *mtx, DWORD timeout) { DWORD result; int lastWaiter; @@ -394,7 +395,7 @@ static int _cnd_timedwait_win32(cnd_t *cond, mtx_t *mtx, DWORD timeout) /* Release the mutex while waiting for the condition (will decrease the number of waiters when done)... */ - mtx_unlock(mtx); + tct_mtx_unlock(mtx); /* Wait for either event to become signaled due to cnd_signal() or cnd_broadcast() being called */ @@ -402,14 +403,14 @@ static int _cnd_timedwait_win32(cnd_t *cond, mtx_t *mtx, DWORD timeout) if (result == WAIT_TIMEOUT) { /* The mutex is locked again before the function returns, even if an error occurred */ - mtx_lock(mtx); - return thrd_timedout; + tct_mtx_lock(mtx); + return tct_thrd_timedout; } else if (result == WAIT_FAILED) { /* The mutex is locked again before the function returns, even if an error occurred */ - mtx_lock(mtx); - return thrd_error; + tct_mtx_lock(mtx); + return tct_thrd_error; } /* Check if we are the last waiter */ @@ -425,28 +426,28 @@ static int _cnd_timedwait_win32(cnd_t *cond, mtx_t *mtx, DWORD timeout) if (ResetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0) { /* The mutex is locked again before the function returns, even if an error occurred */ - mtx_lock(mtx); - return thrd_error; + tct_mtx_lock(mtx); + return tct_thrd_error; } } /* Re-acquire the mutex */ - mtx_lock(mtx); + tct_mtx_lock(mtx); - return thrd_success; + return tct_thrd_success; } #endif -int cnd_wait(cnd_t *cond, mtx_t *mtx) +int tct_cnd_wait(tct_cnd_t *cond, tct_mtx_t *mtx) { #if defined(_TTHREAD_WIN32_) return _cnd_timedwait_win32(cond, mtx, INFINITE); #else - return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error; + return pthread_cond_wait(cond, mtx) == 0 ? tct_thrd_success : tct_thrd_error; #endif } -int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts) +int tct_cnd_timedwait(tct_cnd_t *cond, tct_mtx_t *mtx, const struct timespec *ts) { #if defined(_TTHREAD_WIN32_) struct timespec now; @@ -459,26 +460,26 @@ int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts) return _cnd_timedwait_win32(cond, mtx, delta); } else - return thrd_error; + return tct_thrd_error; #else int ret; ret = pthread_cond_timedwait(cond, mtx, ts); if (ret == ETIMEDOUT) { - return thrd_timedout; + return tct_thrd_timedout; } - return ret == 0 ? thrd_success : thrd_error; + return ret == 0 ? tct_thrd_success : tct_thrd_error; #endif } #if defined(_TTHREAD_WIN32_) struct TinyCThreadTSSData { void* value; - tss_t key; + tct_tss_t key; struct TinyCThreadTSSData* next; }; -static tss_dtor_t _tinycthread_tss_dtors[1088] = { NULL, }; +static tct_tss_dtor_t _tinycthread_tss_dtors[1088] = { NULL, }; static _Thread_local struct TinyCThreadTSSData* _tinycthread_tss_head = NULL; static _Thread_local struct TinyCThreadTSSData* _tinycthread_tss_tail = NULL; @@ -491,7 +492,7 @@ static void _tinycthread_tss_cleanup (void) { unsigned int again = 1; void* value; - for (iteration = 0 ; iteration < TSS_DTOR_ITERATIONS && again > 0 ; iteration++) + for (iteration = 0 ; iteration < TCT_TSS_DTOR_ITERATIONS && again > 0 ; iteration++) { again = 0; for (data = _tinycthread_tss_head ; data != NULL ; data = data->next) @@ -550,7 +551,7 @@ static void NTAPI _tinycthread_tss_callback(PVOID h, DWORD dwReason, PVOID pv) /** Information to pass to the new thread (what to run). */ typedef struct { - thrd_start_t mFunction; /**< Pointer to the function to be executed. */ + tct_thrd_start_t mFunction; /**< Pointer to the function to be executed. */ void * mArg; /**< Function argument for the thread function. */ } _thread_start_info; @@ -561,7 +562,7 @@ static DWORD WINAPI _thrd_wrapper_function(LPVOID aArg) static void * _thrd_wrapper_function(void * aArg) #endif { - thrd_start_t fun; + tct_thrd_start_t fun; void *arg; int res; @@ -588,14 +589,14 @@ static void * _thrd_wrapper_function(void * aArg) #endif } -int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) +int tct_thrd_create(thrd_t *thr, tct_thrd_start_t func, void *arg) { /* Fill out the thread startup information (passed to the thread wrapper, which will eventually free it) */ _thread_start_info* ti = (_thread_start_info*)malloc(sizeof(_thread_start_info)); if (ti == NULL) { - return thrd_nomem; + return tct_thrd_nomem; } ti->mFunction = func; ti->mArg = arg; @@ -614,13 +615,13 @@ int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) if(!*thr) { free(ti); - return thrd_error; + return tct_thrd_error; } - return thrd_success; + return tct_thrd_success; } -thrd_t thrd_current(void) +thrd_t tct_thrd_current(void) { #if defined(_TTHREAD_WIN32_) return GetCurrentThread(); @@ -629,17 +630,17 @@ thrd_t thrd_current(void) #endif } -int thrd_detach(thrd_t thr) +int tct_thrd_detach(thrd_t thr) { #if defined(_TTHREAD_WIN32_) /* https://stackoverflow.com/questions/12744324/how-to-detach-a-thread-on-windows-c#answer-12746081 */ - return CloseHandle(thr) != 0 ? thrd_success : thrd_error; + return CloseHandle(thr) != 0 ? tct_thrd_success : tct_thrd_error; #else - return pthread_detach(thr) == 0 ? thrd_success : thrd_error; + return pthread_detach(thr) == 0 ? tct_thrd_success : tct_thrd_error; #endif } -int thrd_equal(thrd_t thr0, thrd_t thr1) +int tct_thrd_equal(thrd_t thr0, thrd_t thr1) { #if defined(_TTHREAD_WIN32_) return GetThreadId(thr0) == GetThreadId(thr1); @@ -648,7 +649,7 @@ int thrd_equal(thrd_t thr0, thrd_t thr1) #endif } -void thrd_exit(int res) +void tct_thrd_exit(int res) { #if defined(_TTHREAD_WIN32_) if (_tinycthread_tss_head != NULL) @@ -662,14 +663,14 @@ void thrd_exit(int res) #endif } -int thrd_join(thrd_t thr, int *res) +int tct_thrd_join(thrd_t thr, int *res) { #if defined(_TTHREAD_WIN32_) DWORD dwRes; if (WaitForSingleObject(thr, INFINITE) == WAIT_FAILED) { - return thrd_error; + return tct_thrd_error; } if (res != NULL) { @@ -679,7 +680,7 @@ int thrd_join(thrd_t thr, int *res) } else { - return thrd_error; + return tct_thrd_error; } } CloseHandle(thr); @@ -687,17 +688,17 @@ int thrd_join(thrd_t thr, int *res) void *pres; if (pthread_join(thr, &pres) != 0) { - return thrd_error; + return tct_thrd_error; } if (res != NULL) { *res = (int)(intptr_t)pres; } #endif - return thrd_success; + return tct_thrd_success; } -int thrd_sleep(const struct timespec *duration, struct timespec *remaining) +int tct_thrd_sleep(const struct timespec *duration, struct timespec *remaining) { #if !defined(_TTHREAD_WIN32_) int res = nanosleep(duration, remaining); @@ -738,7 +739,7 @@ int thrd_sleep(const struct timespec *duration, struct timespec *remaining) #endif } -void thrd_yield(void) +void tct_thrd_yield(void) { #if defined(_TTHREAD_WIN32_) Sleep(0); @@ -747,25 +748,25 @@ void thrd_yield(void) #endif } -int tss_create(tss_t *key, tss_dtor_t dtor) +int tct_tss_create(tct_tss_t *key, tct_tss_dtor_t dtor) { #if defined(_TTHREAD_WIN32_) *key = TlsAlloc(); if (*key == TLS_OUT_OF_INDEXES) { - return thrd_error; + return tct_thrd_error; } _tinycthread_tss_dtors[*key] = dtor; #else if (pthread_key_create(key, dtor) != 0) { - return thrd_error; + return tct_thrd_error; } #endif - return thrd_success; + return tct_thrd_success; } -void tss_delete(tss_t key) +void tct_tss_delete(tct_tss_t key) { #if defined(_TTHREAD_WIN32_) struct TinyCThreadTSSData* data = (struct TinyCThreadTSSData*) TlsGetValue (key); @@ -802,7 +803,7 @@ void tss_delete(tss_t key) #endif } -void *tss_get(tss_t key) +void *tct_tss_get(tct_tss_t key) { #if defined(_TTHREAD_WIN32_) struct TinyCThreadTSSData* data = (struct TinyCThreadTSSData*)TlsGetValue(key); @@ -816,7 +817,7 @@ void *tss_get(tss_t key) #endif } -int tss_set(tss_t key, void *val) +int tct_tss_set(tct_tss_t key, void *val) { #if defined(_TTHREAD_WIN32_) struct TinyCThreadTSSData* data = (struct TinyCThreadTSSData*)TlsGetValue(key); @@ -825,7 +826,7 @@ int tss_set(tss_t key, void *val) data = (struct TinyCThreadTSSData*)malloc(sizeof(struct TinyCThreadTSSData)); if (data == NULL) { - return thrd_error; + return tct_thrd_error; } data->value = NULL; @@ -849,17 +850,17 @@ int tss_set(tss_t key, void *val) if (!TlsSetValue(key, data)) { free (data); - return thrd_error; + return tct_thrd_error; } } data->value = val; #else if (pthread_setspecific(key, val) != 0) { - return thrd_error; + return tct_thrd_error; } #endif - return thrd_success; + return tct_thrd_success; } #if defined(_TTHREAD_EMULATE_TIMESPEC_GET_) @@ -893,7 +894,7 @@ int _tthread_timespec_get(struct timespec *ts, int base) #endif /* _TTHREAD_EMULATE_TIMESPEC_GET_ */ #if defined(_TTHREAD_WIN32_) -void call_once(once_flag *flag, void (*func)(void)) +void tct_call_once(once_flag *flag, void (*func)(void)) { /* The idea here is that we use a spin lock (via the InterlockedCompareExchange function) to restrict access to the diff --git a/src/tinycthread/tinycthread.h b/src/tinycthread.h similarity index 87% rename from src/tinycthread/tinycthread.h rename to src/tinycthread.h index 1dd62145..3d7ffe8d 100644 --- a/src/tinycthread/tinycthread.h +++ b/src/tinycthread.h @@ -29,6 +29,8 @@ freely, subject to the following restrictions: extern "C" { #endif +#include "badthreads.h" + // jcheng 2017-11-03: _XOPEN_SOURCE 600 is necessary to prevent Solaris headers // from complaining about the combination of C99 and _XOPEN_SOURCE <= 500. The // error message starts with: @@ -171,22 +173,22 @@ int _tthread_timespec_get(struct timespec *ts, int base); /* Macros */ #if defined(_TTHREAD_WIN32_) -#define TSS_DTOR_ITERATIONS (4) +#define TCT_TSS_DTOR_ITERATIONS (4) #else -#define TSS_DTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS +#define TCT_TSS_DTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS #endif /* Function return values */ -#define thrd_error 0 /**< The requested operation failed */ -#define thrd_success 1 /**< The requested operation succeeded */ -#define thrd_timedout 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 */ +#define tct_thrd_error 0 /**< The requested operation failed */ +#define tct_thrd_success 1 /**< The requested operation succeeded */ +#define tct_thrd_timedout 2 /**< The time specified in the call was reached without acquiring the requested resource */ +#define tct_thrd_busy 3 /**< The requested operation failed because a tesource requested by a test and return function is already in use */ +#define tct_thrd_nomem 4 /**< The requested operation failed because it was unable to allocate memory */ /* Mutex types */ -#define mtx_plain 0 -#define mtx_timed 1 -#define mtx_recursive 2 +#define tct_mtx_plain 0 +#define tct_mtx_timed 1 +#define tct_mtx_recursive 2 /* Mutex */ #if defined(_TTHREAD_WIN32_) @@ -198,9 +200,9 @@ typedef struct { int mAlreadyLocked; /* TRUE if the mutex is already locked */ int mRecursive; /* TRUE if the mutex is recursive */ int mTimed; /* TRUE if the mutex is timed */ -} mtx_t; +} tct_mtx_t; #else -typedef pthread_mutex_t mtx_t; +typedef pthread_mutex_t tct_mtx_t; #endif /** Create a mutex object. @@ -213,12 +215,12 @@ typedef pthread_mutex_t mtx_t; * @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); +int tct_mtx_init(tct_mtx_t *mtx, int type); /** Release any resources used by the given mutex. * @param mtx A mutex object. */ -void mtx_destroy(mtx_t *mtx); +void tct_mtx_destroy(tct_mtx_t *mtx); /** Lock the given mutex. * Blocks until the given mutex can be locked. If the mutex is non-recursive, and @@ -228,7 +230,7 @@ void mtx_destroy(mtx_t *mtx); * @return @ref thrd_success on success, or @ref thrd_error if the request could * not be honored. */ -int mtx_lock(mtx_t *mtx); +int tct_mtx_lock(tct_mtx_t *mtx); /** Lock the given mutex, or block until a specific point in time. * Blocks until either the given mutex can be locked, or the specified TIME_UTC @@ -239,7 +241,7 @@ int mtx_lock(mtx_t *mtx); * thrd_timedout if the time specified was reached without acquiring the * requested resource, or thrd_error if the request could not be honored. */ -int mtx_timedlock(mtx_t *mtx, const struct timespec *ts); +int tct_mtx_timedlock(tct_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 @@ -249,14 +251,14 @@ int mtx_timedlock(mtx_t *mtx, const struct timespec *ts); * requested is already in use, or @ref thrd_error if the request could not be * honored. */ -int mtx_trylock(mtx_t *mtx); +int tct_mtx_trylock(tct_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); +int tct_mtx_unlock(tct_mtx_t *mtx); /* Condition variable */ #if defined(_TTHREAD_WIN32_) @@ -264,9 +266,9 @@ 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; +} tct_cnd_t; #else -typedef pthread_cond_t cnd_t; +typedef pthread_cond_t tct_cnd_t; #endif /** Create a condition variable object. @@ -274,12 +276,12 @@ typedef pthread_cond_t cnd_t; * @return @ref thrd_success on success, or @ref thrd_error if the request could * not be honored. */ -int cnd_init(cnd_t *cond); +int tct_cnd_init(tct_cnd_t *cond); /** Release any resources used by the given condition variable. * @param cond A condition variable object. */ -void cnd_destroy(cnd_t *cond); +void tct_cnd_destroy(tct_cnd_t *cond); /** Signal a condition variable. * Unblocks one of the threads that are blocked on the given condition variable @@ -289,7 +291,7 @@ void cnd_destroy(cnd_t *cond); * @return @ref thrd_success on success, or @ref thrd_error if the request could * not be honored. */ -int cnd_signal(cnd_t *cond); +int tct_cnd_signal(tct_cnd_t *cond); /** Broadcast a condition variable. * Unblocks all of the threads that are blocked on the given condition variable @@ -299,7 +301,7 @@ int cnd_signal(cnd_t *cond); * @return @ref thrd_success on success, or @ref thrd_error if the request could * not be honored. */ -int cnd_broadcast(cnd_t *cond); +int tct_cnd_broadcast(tct_cnd_t *cond); /** Wait for a condition variable to become signaled. * The function atomically unlocks the given mutex and endeavors to block until @@ -311,7 +313,7 @@ int cnd_broadcast(cnd_t *cond); * @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); +int tct_cnd_wait(tct_cnd_t *cond, tct_mtx_t *mtx); /** Wait for a condition variable to become signaled. * The function atomically unlocks the given mutex and endeavors to block until @@ -325,7 +327,7 @@ int cnd_wait(cnd_t *cond, mtx_t *mtx); * 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); +int tct_cnd_timedwait(tct_cnd_t *cond, tct_mtx_t *mtx, const struct timespec *ts); /* Thread */ #if defined(_TTHREAD_WIN32_) @@ -342,7 +344,7 @@ typedef pthread_t thrd_t; * @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); +typedef int (*tct_thrd_start_t)(void *arg); /** Create a new thread. * @param thr Identifier of the newly created thread. @@ -356,29 +358,29 @@ typedef int (*thrd_start_t)(void *arg); * 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); +int tct_thrd_create(thrd_t *thr, tct_thrd_start_t func, void *arg); /** Identify the calling thread. * @return The identifier of the calling thread. */ -thrd_t thrd_current(void); +thrd_t tct_thrd_current(void); /** Dispose of any resources allocated to the thread when that thread exits. * @return thrd_success, or thrd_error on error */ -int thrd_detach(thrd_t thr); +int tct_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); +int tct_thrd_equal(thrd_t thr0, thrd_t thr1); /** Terminate execution of the calling thread. * @param res Result code of the calling thread. */ -TTHREAD_NORETURN void thrd_exit(int res); +TTHREAD_NORETURN void tct_thrd_exit(int res); /** Wait for a thread to terminate. * The function joins the given thread with the current thread by blocking @@ -389,7 +391,7 @@ TTHREAD_NORETURN void thrd_exit(int 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); +int tct_thrd_join(thrd_t thr, int *res); /** Put the calling thread to sleep. * Suspend execution of the calling thread. @@ -402,25 +404,25 @@ int thrd_join(thrd_t thr, int *res); * @return 0 (zero) on successful sleep, -1 if an interrupt occurred, * or a negative value if the operation fails. */ -int thrd_sleep(const struct timespec *duration, struct timespec *remaining); +int tct_thrd_sleep(const struct timespec *duration, 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); +void tct_thrd_yield(void); /* Thread local storage */ #if defined(_TTHREAD_WIN32_) -typedef DWORD tss_t; +typedef DWORD tct_tss_t; #else -typedef pthread_key_t tss_t; +typedef pthread_key_t tct_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); +typedef void (*tct_tss_dtor_t)(void *val); /** Create a thread-specific storage. * @param key The unique key identifier that will be set if the function is @@ -434,21 +436,21 @@ typedef void (*tss_dtor_t)(void *val); * for DLLs loaded with LoadLibraryEx. In order to be certain, you * should use @ref thrd_create whenever possible. */ -int tss_create(tss_t *key, tss_dtor_t dtor); +int tct_tss_create(tct_tss_t *key, tct_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); +void tct_tss_delete(tct_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); +void *tct_tss_get(tct_tss_t key); /** Set the value for a thread-specific storage. * @param key The thread-specific storage identifier. @@ -457,7 +459,7 @@ void *tss_get(tss_t key); * @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); +int tct_tss_set(tct_tss_t key, void *val); #if defined(_TTHREAD_WIN32_) typedef struct { @@ -476,9 +478,9 @@ int tss_set(tss_t key, void *val); * @param func Callback to invoke. */ #if defined(_TTHREAD_WIN32_) - void call_once(once_flag *flag, void (*func)(void)); + void tct_call_once(once_flag *flag, void (*func)(void)); #else - #define call_once(flag,func) pthread_once(flag,func) + #define tct_call_once(flag,func) pthread_once(flag,func) #endif #ifdef __cplusplus