summaryrefslogtreecommitdiffstats
path: root/Python/thread_pthread.h
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2021-10-01 07:55:28 (GMT)
committerGitHub <noreply@github.com>2021-10-01 07:55:28 (GMT)
commit1ee0f94d16f150356a4b9b0a39d44ba1d2d5b9fc (patch)
treee94381603c5b5f84731ace512dbc7fbf6bc01fc7 /Python/thread_pthread.h
parent3e1c5d989a884cfbeb427b6fc86012b03cb95f62 (diff)
downloadcpython-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.h39
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");