diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-10-21-18-00-00.gh-issue-160368.sem-clockwait.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-10-21-18-00-00.gh-issue-160368.sem-clockwait.rst new file mode 100644 index 00000000000000..11d7467b38413a --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-10-21-18-00-00.gh-issue-160368.sem-clockwait.rst @@ -0,0 +1,3 @@ +On Linux, allow timed semaphore waits to use the monotonic clock when +``sem_clockwait`` is available at runtime, even if Python was built with +older libc headers. diff --git a/Python/parking_lot.c b/Python/parking_lot.c index 8823d77719cb9a..8431b9bb24ec44 100644 --- a/Python/parking_lot.c +++ b/Python/parking_lot.c @@ -10,6 +10,18 @@ #include +#if defined(_Py_USE_SEMAPHORES) && defined(CLOCK_MONOTONIC) && !defined(_Py_THREAD_SANITIZER) +# ifdef HAVE_SEM_CLOCKWAIT +# define _Py_SEM_CLOCKWAIT_AVAILABLE 1 +# elif defined(__linux__) && (defined(__GNUC__) || defined(__clang__)) +/* Older glibc headers do not declare sem_clockwait. A weak reference allows + such builds to use monotonic waits on newer runtimes. */ +extern int sem_clockwait(sem_t *, clockid_t, const struct timespec *) + __attribute__((weak)); +# define _Py_SEM_CLOCKWAIT_AVAILABLE (sem_clockwait != NULL) +# endif +#endif + typedef struct { // The mutex protects the waiter queue and the num_waiters counter. @@ -151,24 +163,27 @@ _PySemaphore_Wait(_PySemaphore *sema, PyTime_t timeout) if (timeout >= 0) { struct timespec ts; -#if defined(CLOCK_MONOTONIC) && defined(HAVE_SEM_CLOCKWAIT) && !defined(_Py_THREAD_SANITIZER) - PyTime_t now; - // silently ignore error: cannot report error to the caller - (void)PyTime_MonotonicRaw(&now); - PyTime_t deadline = _PyTime_Add(now, timeout); - _PyTime_AsTimespec_clamp(deadline, &ts); - - err = sem_clockwait(&sema->platform_sem, CLOCK_MONOTONIC, &ts); -#else - PyTime_t now; - // silently ignore error: cannot report error to the caller - (void)PyTime_TimeRaw(&now); - PyTime_t deadline = _PyTime_Add(now, timeout); - - _PyTime_AsTimespec_clamp(deadline, &ts); +#ifdef _Py_SEM_CLOCKWAIT_AVAILABLE + if (_Py_SEM_CLOCKWAIT_AVAILABLE) { + PyTime_t now; + // Silently ignore error: cannot report error to the caller. + (void)PyTime_MonotonicRaw(&now); + PyTime_t deadline = _PyTime_Add(now, timeout); + _PyTime_AsTimespec_clamp(deadline, &ts); - err = sem_timedwait(&sema->platform_sem, &ts); + err = sem_clockwait(&sema->platform_sem, CLOCK_MONOTONIC, &ts); + } + else #endif + { + PyTime_t now; + // Silently ignore error: cannot report error to the caller. + (void)PyTime_TimeRaw(&now); + PyTime_t deadline = _PyTime_Add(now, timeout); + _PyTime_AsTimespec_clamp(deadline, &ts); + + err = sem_timedwait(&sema->platform_sem, &ts); + } } else { err = sem_wait(&sema->platform_sem);