diff options
author | Victor Stinner <vstinner@python.org> | 2021-10-01 11:29:25 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-01 11:29:25 (GMT) |
commit | 833fdf126c8fe77fd17e8a8ffbc5c571b3bf64bd (patch) | |
tree | 7e4ed574b7cfb30c0ebb7585061134fee1b1f8ae /Python | |
parent | 54957f16a63ecb6b15f77b01fa7c55ada892604a (diff) | |
download | cpython-833fdf126c8fe77fd17e8a8ffbc5c571b3bf64bd.zip cpython-833fdf126c8fe77fd17e8a8ffbc5c571b3bf64bd.tar.gz cpython-833fdf126c8fe77fd17e8a8ffbc5c571b3bf64bd.tar.bz2 |
bpo-41710: Add private _PyDeadline_Get() function (GH-28674)
Add a private C API for deadlines: add _PyDeadline_Init() and
_PyDeadline_Get() functions.
* Add _PyTime_Add() and _PyTime_Mul() functions which compute t1+t2
and t1*t2 and clamp the result on overflow.
* _PyTime_MulDiv() now uses _PyTime_Add() and _PyTime_Mul().
Diffstat (limited to 'Python')
-rw-r--r-- | Python/pytime.c | 85 | ||||
-rw-r--r-- | Python/thread_nt.h | 14 | ||||
-rw-r--r-- | Python/thread_pthread.h | 18 |
3 files changed, 77 insertions, 40 deletions
diff --git a/Python/pytime.c b/Python/pytime.c index 7fd03ea..8865638 100644 --- a/Python/pytime.c +++ b/Python/pytime.c @@ -73,30 +73,43 @@ pytime_as_nanoseconds(_PyTime_t t) } -// Compute t + t2. Clamp to [_PyTime_MIN; _PyTime_MAX] on overflow. +// Compute t1 + t2. Clamp to [_PyTime_MIN; _PyTime_MAX] on overflow. static inline int -pytime_add(_PyTime_t *t, _PyTime_t t2) +pytime_add(_PyTime_t *t1, _PyTime_t t2) { - if (t2 > 0 && *t > _PyTime_MAX - t2) { - *t = _PyTime_MAX; + if (t2 > 0 && *t1 > _PyTime_MAX - t2) { + *t1 = _PyTime_MAX; return -1; } - else if (t2 < 0 && *t < _PyTime_MIN - t2) { - *t = _PyTime_MIN; + else if (t2 < 0 && *t1 < _PyTime_MIN - t2) { + *t1 = _PyTime_MIN; return -1; } else { - *t += t2; + *t1 += t2; return 0; } } +_PyTime_t +_PyTime_Add(_PyTime_t t1, _PyTime_t t2) +{ + (void)pytime_add(&t1, t2); + return t1; +} + + static inline int -_PyTime_check_mul_overflow(_PyTime_t a, _PyTime_t b) +pytime_mul_check_overflow(_PyTime_t a, _PyTime_t b) { - assert(b > 0); - return ((a < _PyTime_MIN / b) || (_PyTime_MAX / b < a)); + if (b != 0) { + assert(b > 0); + return ((a < _PyTime_MIN / b) || (_PyTime_MAX / b < a)); + } + else { + return 0; + } } @@ -104,8 +117,8 @@ _PyTime_check_mul_overflow(_PyTime_t a, _PyTime_t b) static inline int pytime_mul(_PyTime_t *t, _PyTime_t k) { - assert(k > 0); - if (_PyTime_check_mul_overflow(*t, k)) { + assert(k >= 0); + if (pytime_mul_check_overflow(*t, k)) { *t = (*t >= 0) ? _PyTime_MAX : _PyTime_MIN; return -1; } @@ -116,21 +129,31 @@ pytime_mul(_PyTime_t *t, _PyTime_t k) } +// Compute t * k. Clamp to [_PyTime_MIN; _PyTime_MAX] on overflow. +static inline _PyTime_t +_PyTime_Mul(_PyTime_t t, _PyTime_t k) +{ + (void)pytime_mul(&t, k); + return t; +} + + + + _PyTime_t _PyTime_MulDiv(_PyTime_t ticks, _PyTime_t mul, _PyTime_t div) { - _PyTime_t intpart, remaining; - /* Compute (ticks * mul / div) in two parts to prevent integer overflow: - compute integer part, and then the remaining part. + /* Compute (ticks * mul / div) in two parts to reduce the risk of integer + overflow: compute the integer part, and then the remaining part. (ticks * mul) / div == (ticks / div) * mul + (ticks % div) * mul / div - - The caller must ensure that "(div - 1) * mul" cannot overflow. */ + */ + _PyTime_t intpart, remaining; intpart = ticks / div; ticks %= div; - remaining = ticks * mul; - remaining /= div; - return intpart * mul + remaining; + remaining = _PyTime_Mul(ticks, mul) / div; + // intpart * mul + remaining + return _PyTime_Add(_PyTime_Mul(intpart, mul), remaining); } @@ -505,7 +528,6 @@ pytime_from_object(_PyTime_t *tp, PyObject *obj, _PyTime_round_t round, return pytime_from_double(tp, d, round, unit_to_ns); } else { - Py_BUILD_ASSERT(sizeof(long long) <= sizeof(_PyTime_t)); long long sec = PyLong_AsLongLong(obj); if (sec == -1 && PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) { @@ -514,11 +536,12 @@ pytime_from_object(_PyTime_t *tp, PyObject *obj, _PyTime_round_t round, return -1; } - if (_PyTime_check_mul_overflow(sec, unit_to_ns)) { + Py_BUILD_ASSERT(sizeof(long long) <= sizeof(_PyTime_t)); + _PyTime_t ns = (_PyTime_t)sec; + if (pytime_mul(&ns, unit_to_ns) < 0) { pytime_overflow(); return -1; } - _PyTime_t ns = sec * unit_to_ns; *tp = pytime_from_nanoseconds(ns); return 0; @@ -1292,3 +1315,19 @@ _PyTime_gmtime(time_t t, struct tm *tm) return 0; #endif /* MS_WINDOWS */ } + + +_PyTime_t +_PyDeadline_Init(_PyTime_t timeout) +{ + _PyTime_t now = _PyTime_GetMonotonicClock(); + return _PyTime_Add(now, timeout); +} + + +_PyTime_t +_PyDeadline_Get(_PyTime_t deadline) +{ + _PyTime_t now = _PyTime_GetMonotonicClock(); + return deadline - now; +} diff --git a/Python/thread_nt.h b/Python/thread_nt.h index 26f054f..0dde1a0 100644 --- a/Python/thread_nt.h +++ b/Python/thread_nt.h @@ -75,20 +75,20 @@ EnterNonRecursiveMutex(PNRMUTEX mutex, DWORD milliseconds) } } } else if (milliseconds != 0) { - /* wait at least until the target */ - _PyTime_t now = _PyTime_GetPerfCounter(); + /* wait at least until the deadline */ _PyTime_t nanoseconds = _PyTime_FromNanoseconds((_PyTime_t)milliseconds * 1000000); - _PyTime_t target = now + nanoseconds; + _PyTime_t deadline = _PyTime_Add(_PyTime_GetPerfCounter(), nanoseconds); while (mutex->locked) { - _PyTime_t microseconds = _PyTime_AsMicroseconds(nanoseconds, _PyTime_ROUND_TIMEOUT); + _PyTime_t microseconds = _PyTime_AsMicroseconds(nanoseconds, + _PyTime_ROUND_TIMEOUT); if (PyCOND_TIMEDWAIT(&mutex->cv, &mutex->cs, microseconds) < 0) { result = WAIT_FAILED; break; } - now = _PyTime_GetPerfCounter(); - if (target <= now) + nanoseconds = deadline - _PyTime_GetPerfCounter(); + if (nanoseconds <= 0) { break; - nanoseconds = target - now; + } } } if (!mutex->locked) { diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h index 9b5e273..12dad7e 100644 --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -438,7 +438,7 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds, dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) called\n", lock, microseconds, intr_flag)); - _PyTime_t timeout; + _PyTime_t timeout; // relative timeout if (microseconds >= 0) { _PyTime_t ns; if (microseconds <= _PyTime_MAX / 1000) { @@ -465,16 +465,13 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds, struct timespec abs_timeout; // Local scope for deadline { - _PyTime_t deadline = _PyTime_GetMonotonicClock() + timeout; + _PyTime_t deadline = _PyTime_Add(_PyTime_GetMonotonicClock(), timeout); _PyTime_AsTimespec_clamp(deadline, &abs_timeout); } #else _PyTime_t deadline = 0; - if (timeout > 0 - && !intr_flag - ) - { - deadline = _PyTime_GetMonotonicClock() + timeout; + if (timeout > 0 && !intr_flag) { + deadline = _PyDeadline_Init(timeout); } #endif @@ -484,9 +481,10 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds, status = fix_status(sem_clockwait(thelock, CLOCK_MONOTONIC, &abs_timeout)); #else - _PyTime_t abs_timeout = _PyTime_GetSystemClock() + timeout; + _PyTime_t abs_time = _PyTime_Add(_PyTime_GetSystemClock(), + timeout); struct timespec ts; - _PyTime_AsTimespec_clamp(abs_timeout, &ts); + _PyTime_AsTimespec_clamp(abs_time, &ts); status = fix_status(sem_timedwait(thelock, &ts)); #endif } @@ -508,7 +506,7 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds, #ifndef HAVE_SEM_CLOCKWAIT if (timeout > 0) { /* wait interrupted by a signal (EINTR): recompute the timeout */ - _PyTime_t timeout = deadline - _PyTime_GetMonotonicClock(); + _PyTime_t timeout = _PyDeadline_Get(deadline); if (timeout < 0) { status = ETIMEDOUT; break; |