diff options
-rw-r--r-- | includes/rts/OSThreads.h | 12 | ||||
-rw-r--r-- | m4/fp_check_pthreads.m4 | 2 | ||||
-rw-r--r-- | rts/posix/OSThreads.c | 45 |
3 files changed, 46 insertions, 13 deletions
diff --git a/includes/rts/OSThreads.h b/includes/rts/OSThreads.h index 08d90de06e..d24a1313a6 100644 --- a/includes/rts/OSThreads.h +++ b/includes/rts/OSThreads.h @@ -27,7 +27,17 @@ #include <pthread.h> #include <errno.h> -typedef pthread_cond_t Condition; +typedef struct { + pthread_cond_t cond; + + // Which clock are pthread_cond_timedwait calls referenced against? + // N.B. Some older Darwin releases don't support clock_gettime. However, we + // do want to reference to CLOCK_MONOTONIC whenever possible as it is more + // robust against system time changes and is likely cheaper to query. +#if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) + clockid_t timeout_clk; +#endif +} Condition; typedef pthread_mutex_t Mutex; typedef pthread_t OSThreadId; typedef pthread_key_t ThreadLocalKey; diff --git a/m4/fp_check_pthreads.m4 b/m4/fp_check_pthreads.m4 index 8160f76d4b..ee5b364e93 100644 --- a/m4/fp_check_pthreads.m4 +++ b/m4/fp_check_pthreads.m4 @@ -115,4 +115,6 @@ AC_DEFUN([FP_CHECK_PTHREADS], ], AC_MSG_RESULT(no) ) + + AC_CHECK_FUNCS_ONCE([pthread_condattr_setclock]) ]) diff --git a/rts/posix/OSThreads.c b/rts/posix/OSThreads.c index 647b4840d3..980080731f 100644 --- a/rts/posix/OSThreads.c +++ b/rts/posix/OSThreads.c @@ -91,6 +91,9 @@ #include <numa.h> #endif +// For gettimeofday() +#include <sys/time.h> + // TODO does this need configure magic? #include <time.h> @@ -104,44 +107,62 @@ void initCondition( Condition* pCond ) { - CHECK(pthread_cond_init(pCond, NULL) == 0); + pthread_condattr_t attr; + CHECK(pthread_condattr_init(&attr) == 0); +#if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) + pCond->timeout_clk = CLOCK_REALTIME; + if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC) == 0) { + pCond->timeout_clk = CLOCK_MONOTONIC; + } +#endif + CHECK(pthread_cond_init(&pCond->cond, &attr) == 0); + CHECK(pthread_condattr_destroy(&attr) == 0); } void closeCondition( Condition* pCond ) { - CHECK(pthread_cond_destroy(pCond) == 0); + CHECK(pthread_cond_destroy(&pCond->cond) == 0); } void broadcastCondition ( Condition* pCond ) { - CHECK(pthread_cond_broadcast(pCond) == 0); + CHECK(pthread_cond_broadcast(&pCond->cond) == 0); } void signalCondition ( Condition* pCond ) { - CHECK(pthread_cond_signal(pCond) == 0); + CHECK(pthread_cond_signal(&pCond->cond) == 0); } void waitCondition ( Condition* pCond, Mutex* pMut ) { - CHECK(pthread_cond_wait(pCond,pMut) == 0); + CHECK(pthread_cond_wait(&pCond->cond, pMut) == 0); } bool timedWaitCondition ( Condition* pCond, Mutex* pMut, Time timeout) { - timeout += getMonotonicNSec(); - uint64_t secs = TimeToSeconds(timeout); + struct timespec ts; + +#if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) + CHECK(clock_gettime(pCond->timeout_clk, &ts) == 0); +#else + struct timeval tv; + CHECK(gettimeofday(&tv, NULL) == 0); + ts.tv_sec = tv.tv_sec; + ts.tv_nsec = 1000 * tv.tv_usec; +#endif - const struct timespec t = (struct timespec) { - .tv_sec = secs, - .tv_nsec = TimeToNS(timeout - SecondsToTime(secs)) - }; + uint64_t sec = TimeToSeconds(timeout); + ts.tv_sec += sec; + ts.tv_nsec += TimeToNS(timeout - SecondsToTime(sec)); + ts.tv_sec += ts.tv_nsec / 1000000000; + ts.tv_nsec %= 1000000000; - int ret = pthread_cond_timedwait(pCond,pMut, &t); + int ret = pthread_cond_timedwait(&pCond->cond, pMut, &ts); switch (ret) { case ETIMEDOUT: return false; |