aboutsummaryrefslogtreecommitdiff
path: root/Python
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2021-10-01 13:29:25 +0200
committerGitHub <noreply@github.com>2021-10-01 13:29:25 +0200
commit833fdf126c8fe77fd17e8a8ffbc5c571b3bf64bd (patch)
tree7e4ed574b7cfb30c0ebb7585061134fee1b1f8ae /Python
parent54957f16a63ecb6b15f77b01fa7c55ada892604a (diff)
downloadcpython3-833fdf126c8fe77fd17e8a8ffbc5c571b3bf64bd.tar.gz
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.c85
-rw-r--r--Python/thread_nt.h14
-rw-r--r--Python/thread_pthread.h18
3 files changed, 77 insertions, 40 deletions
diff --git a/Python/pytime.c b/Python/pytime.c
index 7fd03ea576..8865638e91 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 26f054ff0c..0dde1a0409 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 9b5e273f1a..12dad7e9e4 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;