From 1ab5a8a5954117d07fd7b64e52619dfca2719e17 Mon Sep 17 00:00:00 2001 From: mattprodani Date: Fri, 1 Dec 2023 21:01:19 -0500 Subject: [PATCH] Use monotonic clock when supported in semaphore waiting in parking_lot.c Updates parking_lot.c to prefer functions that support CLOCK_MONOTONIC for semaphore and pthread_cond_t based implementations of _PySemaphore_PlatformWait. --- Python/parking_lot.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/Python/parking_lot.c b/Python/parking_lot.c index 664e622cc17474..089d4949c4e6f8 100644 --- a/Python/parking_lot.c +++ b/Python/parking_lot.c @@ -49,6 +49,20 @@ static Bucket buckets[NUM_BUCKETS] = { BUCKET_INIT(buckets, 256), }; +// macOS supports CLOCK_MONOTONIC, but not pthread_condattr_setclock +#if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && defined(CLOCK_MONOTONIC) \ + && !defined(_Py_USE_SEMAPHORES) + #define CONDATTR_MONOTONIC +#endif + +// Condattr for monotonic clock types +static pthread_condattr_t *condattr; +// NULL if monotonic clock is not supported +#if defined(CONDATTR_MONOTONIC) + pthread_condattr_init(condattr); + pthread_condattr_setclock(condattr, CLOCK_MONOTONIC); +#endif + void _PySemaphore_Init(_PySemaphore *sema) { @@ -70,7 +84,7 @@ _PySemaphore_Init(_PySemaphore *sema) if (pthread_mutex_init(&sema->mutex, NULL) != 0) { Py_FatalError("parking_lot: pthread_mutex_init failed"); } - if (pthread_cond_init(&sema->cond, NULL)) { + if (pthread_cond_init(&sema->cond, condattr)) { Py_FatalError("parking_lot: pthread_cond_init failed"); } sema->counter = 0; @@ -118,10 +132,18 @@ _PySemaphore_PlatformWait(_PySemaphore *sema, _PyTime_t timeout) if (timeout >= 0) { struct timespec ts; + #if defined(CLOCK_MONOTONIC) + _PyTime_t deadline = _PyTime_Add(_PyTime_GetMonotonicClock(), timeout); + _PyTime_AsTimespec_clamp(deadline, &ts); + + err = sem_clockwait(&sema->platform_sem, CLOCK_MONOTONIC, &ts); + #else + // does not support CLOCK_MONOTONIC, use system clock _PyTime_t deadline = _PyTime_Add(_PyTime_GetSystemClock(), timeout); - _PyTime_AsTimespec(deadline, &ts); + _PyTime_AsTimespec_clamp(deadline, &ts); err = sem_timedwait(&sema->platform_sem, &ts); + #endif } else { err = sem_wait(&sema->platform_sem); @@ -150,8 +172,13 @@ _PySemaphore_PlatformWait(_PySemaphore *sema, _PyTime_t timeout) if (timeout >= 0) { struct timespec ts; + #if defined(CONDATTR_MONOTONIC) + _PyTime_t deadline = _PyTime_Add(_PyTime_GetMonotonicClock(), timeout); + _PyTime_AsTimespec_clamp(deadline, &ts); + #else _PyTime_t deadline = _PyTime_Add(_PyTime_GetSystemClock(), timeout); - _PyTime_AsTimespec(deadline, &ts); + _PyTime_AsTimespec_clamp(deadline, &ts); + #endif err = pthread_cond_timedwait(&sema->cond, &sema->mutex, &ts); }