92
92
* mutexes and condition variables:
93
93
*/
94
94
#if (defined(_POSIX_SEMAPHORES ) && !defined(HAVE_BROKEN_POSIX_SEMAPHORES ) && \
95
- defined(HAVE_SEM_TIMEDWAIT ))
95
+ ( defined(HAVE_SEM_TIMEDWAIT ) || defined( HAVE_SEM_CLOCKWAIT ) ))
96
96
# define USE_SEMAPHORES
97
97
#else
98
98
# undef USE_SEMAPHORES
99
99
#endif
100
100
101
+ #if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK ) && defined(HAVE_CLOCK_GETTIME ) && defined(CLOCK_MONOTONIC )
102
+ // monotonic is supported statically. It doesn't mean it works on runtime.
103
+ #define CONDATTR_MONOTONIC
104
+ #endif
105
+
101
106
102
107
/* On platforms that don't use standard POSIX threads pthread_sigmask()
103
108
* isn't present. DEC threads uses sigprocmask() instead as do most
@@ -123,16 +128,23 @@ do { \
123
128
ts.tv_nsec = tv.tv_usec * 1000; \
124
129
} while(0)
125
130
131
+ #if defined(CONDATTR_MONOTONIC ) || defined(HAVE_SEM_CLOCKWAIT )
132
+ static void
133
+ monotonic_abs_timeout (long long us , struct timespec * abs )
134
+ {
135
+ clock_gettime (CLOCK_MONOTONIC , abs );
136
+ abs -> tv_sec += us / 1000000 ;
137
+ abs -> tv_nsec += (us % 1000000 ) * 1000 ;
138
+ abs -> tv_sec += abs -> tv_nsec / 1000000000 ;
139
+ abs -> tv_nsec %= 1000000000 ;
140
+ }
141
+ #endif
142
+
126
143
127
144
/*
128
145
* pthread_cond support
129
146
*/
130
147
131
- #if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK ) && defined(HAVE_CLOCK_GETTIME ) && defined(CLOCK_MONOTONIC )
132
- // monotonic is supported statically. It doesn't mean it works on runtime.
133
- #define CONDATTR_MONOTONIC
134
- #endif
135
-
136
148
// NULL when pthread_condattr_setclock(CLOCK_MONOTONIC) is not supported.
137
149
static pthread_condattr_t * condattr_monotonic = NULL ;
138
150
@@ -154,16 +166,13 @@ _PyThread_cond_init(PyCOND_T *cond)
154
166
return pthread_cond_init (cond , condattr_monotonic );
155
167
}
156
168
169
+
157
170
void
158
171
_PyThread_cond_after (long long us , struct timespec * abs )
159
172
{
160
173
#ifdef CONDATTR_MONOTONIC
161
174
if (condattr_monotonic ) {
162
- clock_gettime (CLOCK_MONOTONIC , abs );
163
- abs -> tv_sec += us / 1000000 ;
164
- abs -> tv_nsec += (us % 1000000 ) * 1000 ;
165
- abs -> tv_sec += abs -> tv_nsec / 1000000000 ;
166
- abs -> tv_nsec %= 1000000000 ;
175
+ monotonic_abs_timeout (us , abs );
167
176
return ;
168
177
}
169
178
#endif
@@ -434,7 +443,9 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
434
443
sem_t * thelock = (sem_t * )lock ;
435
444
int status , error = 0 ;
436
445
struct timespec ts ;
446
+ #ifndef HAVE_SEM_CLOCKWAIT
437
447
_PyTime_t deadline = 0 ;
448
+ #endif
438
449
439
450
(void ) error ; /* silence unused-but-set-variable warning */
440
451
dprintf (("PyThread_acquire_lock_timed(%p, %lld, %d) called\n" ,
@@ -445,6 +456,9 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
445
456
}
446
457
447
458
if (microseconds > 0 ) {
459
+ #ifdef HAVE_SEM_CLOCKWAIT
460
+ monotonic_abs_timeout (microseconds , & ts );
461
+ #else
448
462
MICROSECONDS_TO_TIMESPEC (microseconds , ts );
449
463
450
464
if (!intr_flag ) {
@@ -453,11 +467,17 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
453
467
_PyTime_t timeout = _PyTime_FromNanoseconds (microseconds * 1000 );
454
468
deadline = _PyTime_GetMonotonicClock () + timeout ;
455
469
}
470
+ #endif
456
471
}
457
472
458
473
while (1 ) {
459
474
if (microseconds > 0 ) {
475
+ #ifdef HAVE_SEM_CLOCKWAIT
476
+ status = fix_status (sem_clockwait (thelock , CLOCK_MONOTONIC ,
477
+ & ts ));
478
+ #else
460
479
status = fix_status (sem_timedwait (thelock , & ts ));
480
+ #endif
461
481
}
462
482
else if (microseconds == 0 ) {
463
483
status = fix_status (sem_trywait (thelock ));
@@ -472,6 +492,9 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
472
492
break ;
473
493
}
474
494
495
+ // sem_clockwait() uses an absolute timeout, there is no need
496
+ // to recompute the relative timeout.
497
+ #ifndef HAVE_SEM_CLOCKWAIT
475
498
if (microseconds > 0 ) {
476
499
/* wait interrupted by a signal (EINTR): recompute the timeout */
477
500
_PyTime_t dt = deadline - _PyTime_GetMonotonicClock ();
@@ -493,13 +516,19 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
493
516
microseconds = 0 ;
494
517
}
495
518
}
519
+ #endif
496
520
}
497
521
498
522
/* Don't check the status if we're stopping because of an interrupt. */
499
523
if (!(intr_flag && status == EINTR )) {
500
524
if (microseconds > 0 ) {
501
- if (status != ETIMEDOUT )
525
+ if (status != ETIMEDOUT ) {
526
+ #ifdef HAVE_SEM_CLOCKWAIT
527
+ CHECK_STATUS ("sem_clockwait" );
528
+ #else
502
529
CHECK_STATUS ("sem_timedwait" );
530
+ #endif
531
+ }
503
532
}
504
533
else if (microseconds == 0 ) {
505
534
if (status != EAGAIN )
0 commit comments