summaryrefslogtreecommitdiff
path: root/Python
diff options
context:
space:
mode:
Diffstat (limited to 'Python')
-rw-r--r--Python/thread_nt.h9
-rw-r--r--Python/thread_pthread.h55
2 files changed, 54 insertions, 10 deletions
diff --git a/Python/thread_nt.h b/Python/thread_nt.h
index bae8bcc356..46df346692 100644
--- a/Python/thread_nt.h
+++ b/Python/thread_nt.h
@@ -283,12 +283,13 @@ PyThread_acquire_lock_timed(PyThread_type_lock aLock,
milliseconds = microseconds / 1000;
if (microseconds % 1000 > 0)
++milliseconds;
- if ((DWORD) milliseconds != milliseconds)
- Py_FatalError("Timeout too large for a DWORD, "
- "please check PY_TIMEOUT_MAX");
+ if (milliseconds > PY_DWORD_MAX) {
+ Py_FatalError("Timeout larger than PY_TIMEOUT_MAX");
+ }
}
- else
+ else {
milliseconds = INFINITE;
+ }
dprintf(("%lu: PyThread_acquire_lock_timed(%p, %lld) called\n",
PyThread_get_thread_ident(), aLock, microseconds));
diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h
index c5b7f3256f..13cffa3bf3 100644
--- a/Python/thread_pthread.h
+++ b/Python/thread_pthread.h
@@ -318,23 +318,66 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
sem_t *thelock = (sem_t *)lock;
int status, error = 0;
struct timespec ts;
+ _PyTime_t deadline = 0;
(void) error; /* silence unused-but-set-variable warning */
dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) called\n",
lock, microseconds, intr_flag));
- if (microseconds > 0)
+ if (microseconds > PY_TIMEOUT_MAX) {
+ Py_FatalError("Timeout larger than PY_TIMEOUT_MAX");
+ }
+
+ if (microseconds > 0) {
MICROSECONDS_TO_TIMESPEC(microseconds, ts);
- do {
- if (microseconds > 0)
+
+ if (!intr_flag) {
+ /* cannot overflow thanks to (microseconds > PY_TIMEOUT_MAX)
+ check done above */
+ _PyTime_t timeout = _PyTime_FromNanoseconds(microseconds * 1000);
+ deadline = _PyTime_GetMonotonicClock() + timeout;
+ }
+ }
+
+ while (1) {
+ if (microseconds > 0) {
status = fix_status(sem_timedwait(thelock, &ts));
- else if (microseconds == 0)
+ }
+ else if (microseconds == 0) {
status = fix_status(sem_trywait(thelock));
- else
+ }
+ else {
status = fix_status(sem_wait(thelock));
+ }
+
/* Retry if interrupted by a signal, unless the caller wants to be
notified. */
- } while (!intr_flag && status == EINTR);
+ if (intr_flag || status != EINTR) {
+ break;
+ }
+
+ if (microseconds > 0) {
+ /* wait interrupted by a signal (EINTR): recompute the timeout */
+ _PyTime_t dt = deadline - _PyTime_GetMonotonicClock();
+ if (dt < 0) {
+ status = ETIMEDOUT;
+ break;
+ }
+ else if (dt > 0) {
+ _PyTime_t realtime_deadline = _PyTime_GetSystemClock() + dt;
+ if (_PyTime_AsTimespec(realtime_deadline, &ts) < 0) {
+ /* Cannot occur thanks to (microseconds > PY_TIMEOUT_MAX)
+ check done above */
+ Py_UNREACHABLE();
+ }
+ /* no need to update microseconds value, the code only care
+ if (microseconds > 0 or (microseconds == 0). */
+ }
+ else {
+ microseconds = 0;
+ }
+ }
+ }
/* Don't check the status if we're stopping because of an interrupt. */
if (!(intr_flag && status == EINTR)) {