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.

134146

static pthread_condattr_t *condattr_monotonic = NULL;

135147

@@ -151,16 +163,13 @@ _PyThread_cond_init(PyCOND_T *cond)

151163

return pthread_cond_init(cond, condattr_monotonic);

152164

}

153165166+154167

void

155168

_PyThread_cond_after(long long us, struct timespec *abs)

156169

{

157170

#ifdef CONDATTR_MONOTONIC

158171

if (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);

164173

return;

165174

}

166175

#endif

@@ -431,7 +440,9 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,

431440

sem_t *thelock = (sem_t *)lock;

432441

int status, error = 0;

433442

struct timespec ts;

443+

#ifndef HAVE_SEM_CLOCKWAIT

434444

_PyTime_t deadline = 0;

445+

#endif

435446436447

(void) error; /* silence unused-but-set-variable warning */

437448

dprintf(("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

}

443454444455

if (microseconds > 0) {

456+

#ifdef HAVE_SEM_CLOCKWAIT

457+

monotonic_abs_timeout(microseconds, &ts);

458+

#else

445459

MICROSECONDS_TO_TIMESPEC(microseconds, ts);

446460447461

if (!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);

451465

deadline = _PyTime_GetMonotonicClock() + timeout;

452466

}

467+

#endif

453468

}

454469455470

while (1) {

456471

if (microseconds > 0) {

472+

#ifdef HAVE_SEM_CLOCKWAIT

473+

status = fix_status(sem_clockwait(thelock, CLOCK_MONOTONIC,

474+

&ts));

475+

#else

457476

status = fix_status(sem_timedwait(thelock, &ts));

477+

#endif

458478

}

459479

else if (microseconds == 0) {

460480

status = fix_status(sem_trywait(thelock));

@@ -469,6 +489,9 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,

469489

break;

470490

}

471491492+

// sem_clockwait() uses an absolute timeout, there is no need

493+

// to recompute the relative timeout.

494+

#ifndef HAVE_SEM_CLOCKWAIT

472495

if (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,

490513

microseconds = 0;

491514

}

492515

}

516+

#endif

493517

}

494518495519

/* Don't check the status if we're stopping because of an interrupt. */

496520

if (!(intr_flag && status == EINTR)) {

497521

if (microseconds > 0) {

498-

if (status != ETIMEDOUT)

522+

if (status != ETIMEDOUT) {

523+

#ifdef HAVE_SEM_CLOCKWAIT

524+

CHECK_STATUS("sem_clockwait");

525+

#else

499526

CHECK_STATUS("sem_timedwait");

527+

#endif

528+

}

500529

}

501530

else if (microseconds == 0) {

502531

if (status != EAGAIN)