diff options
author | Victor Stinner <vstinner@python.org> | 2021-10-01 07:55:28 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-01 07:55:28 (GMT) |
commit | 1ee0f94d16f150356a4b9b0a39d44ba1d2d5b9fc (patch) | |
tree | e94381603c5b5f84731ace512dbc7fbf6bc01fc7 /Python/thread_pthread.h | |
parent | 3e1c5d989a884cfbeb427b6fc86012b03cb95f62 (diff) | |
download | cpython-1ee0f94d16f150356a4b9b0a39d44ba1d2d5b9fc.zip cpython-1ee0f94d16f150356a4b9b0a39d44ba1d2d5b9fc.tar.gz cpython-1ee0f94d16f150356a4b9b0a39d44ba1d2d5b9fc.tar.bz2 |
bpo-41710: PyThread_acquire_lock_timed() uses sem_clockwait() (GH-28662)
On Unix, if the sem_clockwait() function is available in the C
library (glibc 2.30 and newer), the threading.Lock.acquire() method
now uses the monotonic clock (time.CLOCK_MONOTONIC) for the timeout,
rather than using the system clock (time.CLOCK_REALTIME), to not be
affected by system clock changes.
configure now checks if the sem_clockwait() function is available.
Diffstat (limited to 'Python/thread_pthread.h')
-rw-r--r-- | Python/thread_pthread.h | 39 |
1 files changed, 33 insertions, 6 deletions
diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h index 3815ffa..9b5e273 100644 --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -92,7 +92,7 @@ * mutexes and condition variables: */ #if (defined(_POSIX_SEMAPHORES) && !defined(HAVE_BROKEN_POSIX_SEMAPHORES) && \ - defined(HAVE_SEM_TIMEDWAIT)) + (defined(HAVE_SEM_TIMEDWAIT) || defined(HAVE_SEM_CLOCKWAIT))) # define USE_SEMAPHORES #else # undef USE_SEMAPHORES @@ -461,17 +461,34 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds, timeout = _PyTime_FromNanoseconds(-1); } +#ifdef HAVE_SEM_CLOCKWAIT + struct timespec abs_timeout; + // Local scope for deadline + { + _PyTime_t deadline = _PyTime_GetMonotonicClock() + timeout; + _PyTime_AsTimespec_clamp(deadline, &abs_timeout); + } +#else _PyTime_t deadline = 0; - if (timeout > 0 && !intr_flag) { + if (timeout > 0 + && !intr_flag + ) + { deadline = _PyTime_GetMonotonicClock() + timeout; } +#endif while (1) { if (timeout > 0) { - _PyTime_t t = _PyTime_GetSystemClock() + timeout; +#ifdef HAVE_SEM_CLOCKWAIT + status = fix_status(sem_clockwait(thelock, CLOCK_MONOTONIC, + &abs_timeout)); +#else + _PyTime_t abs_timeout = _PyTime_GetSystemClock() + timeout; struct timespec ts; - _PyTime_AsTimespec_clamp(t, &ts); + _PyTime_AsTimespec_clamp(abs_timeout, &ts); status = fix_status(sem_timedwait(thelock, &ts)); +#endif } else if (timeout == 0) { status = fix_status(sem_trywait(thelock)); @@ -486,6 +503,9 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds, break; } + // sem_clockwait() uses an absolute timeout, there is no need + // to recompute the relative timeout. +#ifndef HAVE_SEM_CLOCKWAIT if (timeout > 0) { /* wait interrupted by a signal (EINTR): recompute the timeout */ _PyTime_t timeout = deadline - _PyTime_GetMonotonicClock(); @@ -494,17 +514,24 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds, break; } } +#endif } /* Don't check the status if we're stopping because of an interrupt. */ if (!(intr_flag && status == EINTR)) { if (timeout > 0) { - if (status != ETIMEDOUT) + if (status != ETIMEDOUT) { +#ifdef HAVE_SEM_CLOCKWAIT + CHECK_STATUS("sem_clockwait"); +#else CHECK_STATUS("sem_timedwait"); +#endif + } } else if (timeout == 0) { - if (status != EAGAIN) + if (status != EAGAIN) { CHECK_STATUS("sem_trywait"); + } } else { CHECK_STATUS("sem_wait"); |