summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--includes/rts/OSThreads.h12
-rw-r--r--m4/fp_check_pthreads.m42
-rw-r--r--rts/posix/OSThreads.c45
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 04375006d2..b5eda78648 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;