mirror of
https://github.com/python/cpython.git
synced 2025-07-07 19:35:27 +00:00
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.
This commit is contained in:
parent
3e1c5d989a
commit
1ee0f94d16
6 changed files with 216 additions and 128 deletions
|
@ -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");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue