summaryrefslogtreecommitdiff
path: root/rts/posix
diff options
context:
space:
mode:
authorBen Gamari <ben@smart-cactus.org>2021-07-26 11:01:11 -0700
committerMarge Bot <ben+marge-bot@smart-cactus.org>2021-08-02 04:14:25 -0400
commitf454c0ea2e7de32786635a987885706fcd7cb01a (patch)
treeefa5034ef77674b767b8d33401f5373e908421f5 /rts/posix
parent2e0f4ca128d17a7161fa41ee9e82315a1cddffb7 (diff)
downloadhaskell-f454c0ea2e7de32786635a987885706fcd7cb01a.tar.gz
rts/OSThreads: Fix reference clock of timedWaitCondition
Previously `timedWaitCondition` assumed that timeouts were referenced against `CLOCK_MONOTONIC`. This is wrong; by default `pthread_cond_timedwait` references against `CLOCK_REALTIME`, although this can be overridden using `pthread_condattr_setclock`. Fix this and add support for using `CLOCK_MONOTONIC` whenever possible as it is more robust against system time changes and is likely cheaper to query. Unfortunately, this is complicated by the fact that older versions of Darwin did not provide `clock_gettime`, which means we also need to introduce a fallback path using `gettimeofday`. Fixes #20144.
Diffstat (limited to 'rts/posix')
-rw-r--r--rts/posix/OSThreads.c45
1 files changed, 33 insertions, 12 deletions
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;