bpo-41710: PyThread_acquire_lock_timed() uses sem_clockwait() (GH-286… · python/cpython@0e1aeab
@@ -89,12 +89,17 @@
8989 * mutexes and condition variables:
9090 */
9191#if (defined(_POSIX_SEMAPHORES) && !defined(HAVE_BROKEN_POSIX_SEMAPHORES) && \
92- defined(HAVE_SEM_TIMEDWAIT))
92+(defined(HAVE_SEM_TIMEDWAIT) || defined(HAVE_SEM_CLOCKWAIT)))
9393# define USE_SEMAPHORES
9494#else
9595# undef USE_SEMAPHORES
9696#endif
979798+#if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
99+// monotonic is supported statically. It doesn't mean it works on runtime.
100+#define CONDATTR_MONOTONIC
101+#endif
102+9810399104/* On platforms that don't use standard POSIX threads pthread_sigmask()
100105 * isn't present. DEC threads uses sigprocmask() instead as do most
@@ -120,16 +125,23 @@ do { \
120125 ts.tv_nsec = tv.tv_usec * 1000; \
121126} while(0)
122127128+#if defined(CONDATTR_MONOTONIC) || defined(HAVE_SEM_CLOCKWAIT)
129+static void
130+monotonic_abs_timeout(long long us, struct timespec *abs)
131+{
132+clock_gettime(CLOCK_MONOTONIC, abs);
133+abs->tv_sec += us / 1000000;
134+abs->tv_nsec += (us % 1000000) * 1000;
135+abs->tv_sec += abs->tv_nsec / 1000000000;
136+abs->tv_nsec %= 1000000000;
137+}
138+#endif
139+123140124141/*
125142 * pthread_cond support
126143 */
127144128-#if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
129-// monotonic is supported statically. It doesn't mean it works on runtime.
130-#define CONDATTR_MONOTONIC
131-#endif
132-133145// NULL when pthread_condattr_setclock(CLOCK_MONOTONIC) is not supported.
134146static pthread_condattr_t *condattr_monotonic = NULL;
135147@@ -151,16 +163,13 @@ _PyThread_cond_init(PyCOND_T *cond)
151163return pthread_cond_init(cond, condattr_monotonic);
152164}
153165166+154167void
155168_PyThread_cond_after(long long us, struct timespec *abs)
156169{
157170#ifdef CONDATTR_MONOTONIC
158171if (condattr_monotonic) {
159-clock_gettime(CLOCK_MONOTONIC, abs);
160-abs->tv_sec += us / 1000000;
161-abs->tv_nsec += (us % 1000000) * 1000;
162-abs->tv_sec += abs->tv_nsec / 1000000000;
163-abs->tv_nsec %= 1000000000;
172+monotonic_abs_timeout(us, abs);
164173return;
165174 }
166175#endif
@@ -431,7 +440,9 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
431440sem_t *thelock = (sem_t *)lock;
432441int status, error = 0;
433442struct timespec ts;
443+#ifndef HAVE_SEM_CLOCKWAIT
434444_PyTime_t deadline = 0;
445+#endif
435446436447 (void) error; /* silence unused-but-set-variable warning */
437448dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) called\n",
@@ -442,6 +453,9 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
442453 }
443454444455if (microseconds > 0) {
456+#ifdef HAVE_SEM_CLOCKWAIT
457+monotonic_abs_timeout(microseconds, &ts);
458+#else
445459MICROSECONDS_TO_TIMESPEC(microseconds, ts);
446460447461if (!intr_flag) {
@@ -450,11 +464,17 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
450464_PyTime_t timeout = _PyTime_FromNanoseconds(microseconds * 1000);
451465deadline = _PyTime_GetMonotonicClock() + timeout;
452466 }
467+#endif
453468 }
454469455470while (1) {
456471if (microseconds > 0) {
472+#ifdef HAVE_SEM_CLOCKWAIT
473+status = fix_status(sem_clockwait(thelock, CLOCK_MONOTONIC,
474+&ts));
475+#else
457476status = fix_status(sem_timedwait(thelock, &ts));
477+#endif
458478 }
459479else if (microseconds == 0) {
460480status = fix_status(sem_trywait(thelock));
@@ -469,6 +489,9 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
469489break;
470490 }
471491492+// sem_clockwait() uses an absolute timeout, there is no need
493+// to recompute the relative timeout.
494+#ifndef HAVE_SEM_CLOCKWAIT
472495if (microseconds > 0) {
473496/* wait interrupted by a signal (EINTR): recompute the timeout */
474497_PyTime_t dt = deadline - _PyTime_GetMonotonicClock();
@@ -490,13 +513,19 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
490513microseconds = 0;
491514 }
492515 }
516+#endif
493517 }
494518495519/* Don't check the status if we're stopping because of an interrupt. */
496520if (!(intr_flag && status == EINTR)) {
497521if (microseconds > 0) {
498-if (status != ETIMEDOUT)
522+if (status != ETIMEDOUT) {
523+#ifdef HAVE_SEM_CLOCKWAIT
524+CHECK_STATUS("sem_clockwait");
525+#else
499526CHECK_STATUS("sem_timedwait");
527+#endif
528+ }
500529 }
501530else if (microseconds == 0) {
502531if (status != EAGAIN)