//
// Some functions clamp the result in the range [_PyTime_MIN; _PyTime_MAX], so
// the caller doesn't have to handle errors and doesn't need to hold the GIL.
+// For example, _PyTime_Add(t1, t2) computes t1+t2 and clamp the result on
+// overflow.
//
// Clocks:
//
PyAPI_FUNC(void) _PyTime_AsTimespec_clamp(_PyTime_t t, struct timespec *ts);
#endif
+
+// Compute t1 + t2. Clamp to [_PyTime_MIN; _PyTime_MAX] on overflow.
+PyAPI_FUNC(_PyTime_t) _PyTime_Add(_PyTime_t t1, _PyTime_t t2);
+
/* Compute ticks * mul / div.
+ Clamp to [_PyTime_MIN; _PyTime_MAX] on overflow.
The caller must ensure that ((div - 1) * mul) cannot overflow. */
PyAPI_FUNC(_PyTime_t) _PyTime_MulDiv(_PyTime_t ticks,
_PyTime_t mul,
_PyTime_t *t,
_Py_clock_info_t *info);
+
+// Create a deadline.
+// Pseudo code: _PyTime_GetMonotonicClock() + timeout.
+PyAPI_FUNC(_PyTime_t) _PyDeadline_Init(_PyTime_t timeout);
+
+// Get remaining time from a deadline.
+// Pseudo code: deadline - _PyTime_GetMonotonicClock().
+PyAPI_FUNC(_PyTime_t) _PyDeadline_Get(_PyTime_t deadline);
+
#ifdef __cplusplus
}
#endif
cls: defining_class
/
block: bool = True
- timeout: object = None
+ timeout as timeout_obj: object = None
Remove and return an item from the queue.
static PyObject *
_queue_SimpleQueue_get_impl(simplequeueobject *self, PyTypeObject *cls,
- int block, PyObject *timeout)
-/*[clinic end generated code: output=1969aefa7db63666 input=5fc4d56b9a54757e]*/
+ int block, PyObject *timeout_obj)
+/*[clinic end generated code: output=5c2cca914cd1e55b input=5b4047bfbc645ec1]*/
{
_PyTime_t endtime = 0;
- _PyTime_t timeout_val;
+ _PyTime_t timeout;
PyObject *item;
PyLockStatus r;
PY_TIMEOUT_T microseconds;
/* Non-blocking */
microseconds = 0;
}
- else if (timeout != Py_None) {
+ else if (timeout_obj != Py_None) {
/* With timeout */
- if (_PyTime_FromSecondsObject(&timeout_val,
- timeout, _PyTime_ROUND_CEILING) < 0)
+ if (_PyTime_FromSecondsObject(&timeout,
+ timeout_obj, _PyTime_ROUND_CEILING) < 0) {
return NULL;
- if (timeout_val < 0) {
+ }
+ if (timeout < 0) {
PyErr_SetString(PyExc_ValueError,
"'timeout' must be a non-negative number");
return NULL;
}
- microseconds = _PyTime_AsMicroseconds(timeout_val,
+ microseconds = _PyTime_AsMicroseconds(timeout,
_PyTime_ROUND_CEILING);
if (microseconds > PY_TIMEOUT_MAX) {
PyErr_SetString(PyExc_OverflowError,
"timeout value is too large");
return NULL;
}
- endtime = _PyTime_GetMonotonicClock() + timeout_val;
+ endtime = _PyDeadline_Init(timeout);
}
else {
/* Infinitely blocking */
r = PyThread_acquire_lock_timed(self->lock, microseconds, 1);
Py_END_ALLOW_THREADS
}
+
if (r == PY_LOCK_INTR && Py_MakePendingCalls() < 0) {
return NULL;
}
return NULL;
}
self->locked = 1;
+
/* Adjust timeout for next iteration (if any) */
- if (endtime > 0) {
- timeout_val = endtime - _PyTime_GetMonotonicClock();
- microseconds = _PyTime_AsMicroseconds(timeout_val, _PyTime_ROUND_CEILING);
+ if (microseconds > 0) {
+ timeout = _PyDeadline_Get(endtime);
+ microseconds = _PyTime_AsMicroseconds(timeout,
+ _PyTime_ROUND_CEILING);
}
}
+
/* BEGIN GIL-protected critical section */
assert(self->lst_pos < PyList_GET_SIZE(self->lst));
item = simplequeue_pop_item(self);
timeout = GET_SOCKET_TIMEOUT(sock);
has_timeout = (timeout > 0);
- if (has_timeout)
- deadline = _PyTime_GetMonotonicClock() + timeout;
+ if (has_timeout) {
+ deadline = _PyDeadline_Init(timeout);
+ }
/* Actually negotiate SSL connection */
/* XXX If SSL_do_handshake() returns 0, it's also a failure. */
goto error;
if (has_timeout)
- timeout = deadline - _PyTime_GetMonotonicClock();
+ timeout = _PyDeadline_Get(deadline);
if (err.ssl == SSL_ERROR_WANT_READ) {
sockstate = PySSL_select(sock, 0, timeout);
timeout = GET_SOCKET_TIMEOUT(sock);
has_timeout = (timeout > 0);
- if (has_timeout)
- deadline = _PyTime_GetMonotonicClock() + timeout;
+ if (has_timeout) {
+ deadline = _PyDeadline_Init(timeout);
+ }
sockstate = PySSL_select(sock, 1, timeout);
if (sockstate == SOCKET_HAS_TIMED_OUT) {
if (PyErr_CheckSignals())
goto error;
- if (has_timeout)
- timeout = deadline - _PyTime_GetMonotonicClock();
+ if (has_timeout) {
+ timeout = _PyDeadline_Get(deadline);
+ }
if (err.ssl == SSL_ERROR_WANT_READ) {
sockstate = PySSL_select(sock, 0, timeout);
timeout = GET_SOCKET_TIMEOUT(sock);
has_timeout = (timeout > 0);
if (has_timeout)
- deadline = _PyTime_GetMonotonicClock() + timeout;
+ deadline = _PyDeadline_Init(timeout);
do {
PySSL_BEGIN_ALLOW_THREADS
if (PyErr_CheckSignals())
goto error;
- if (has_timeout)
- timeout = deadline - _PyTime_GetMonotonicClock();
+ if (has_timeout) {
+ timeout = _PyDeadline_Get(deadline);
+ }
if (err.ssl == SSL_ERROR_WANT_READ) {
sockstate = PySSL_select(sock, 0, timeout);
timeout = GET_SOCKET_TIMEOUT(sock);
has_timeout = (timeout > 0);
- if (has_timeout)
- deadline = _PyTime_GetMonotonicClock() + timeout;
+ if (has_timeout) {
+ deadline = _PyDeadline_Init(timeout);
+ }
while (1) {
PySSL_BEGIN_ALLOW_THREADS
continue;
}
- if (has_timeout)
- timeout = deadline - _PyTime_GetMonotonicClock();
+ if (has_timeout) {
+ timeout = _PyDeadline_Get(deadline);
+ }
/* Possibly retry shutdown until timeout or failure */
if (err.ssl == SSL_ERROR_WANT_READ)
static PyLockStatus
acquire_timed(PyThread_type_lock lock, _PyTime_t timeout)
{
- PyLockStatus r;
_PyTime_t endtime = 0;
-
if (timeout > 0) {
- endtime = _PyTime_GetMonotonicClock() + timeout;
+ endtime = _PyDeadline_Init(timeout);
}
+ PyLockStatus r;
do {
_PyTime_t microseconds;
microseconds = _PyTime_AsMicroseconds(timeout, _PyTime_ROUND_CEILING);
/* If we're using a timeout, recompute the timeout after processing
* signals, since those can take time. */
if (timeout > 0) {
- timeout = endtime - _PyTime_GetMonotonicClock();
+ timeout = _PyDeadline_Get(endtime);
/* Check for negative values, since those mean block forever.
*/
static PyObject *
_queue_SimpleQueue_get_impl(simplequeueobject *self, PyTypeObject *cls,
- int block, PyObject *timeout);
+ int block, PyObject *timeout_obj);
static PyObject *
_queue_SimpleQueue_get(simplequeueobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
static const char * const _keywords[] = {"block", "timeout", NULL};
static _PyArg_Parser _parser = {"|pO:get", _keywords, 0};
int block = 1;
- PyObject *timeout = Py_None;
+ PyObject *timeout_obj = Py_None;
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
- &block, &timeout)) {
+ &block, &timeout_obj)) {
goto exit;
}
- return_value = _queue_SimpleQueue_get_impl(self, cls, block, timeout);
+ return_value = _queue_SimpleQueue_get_impl(self, cls, block, timeout_obj);
exit:
return return_value;
exit:
return return_value;
}
-/*[clinic end generated code: output=96cc57168d72aab1 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=acfaf0191d8935db input=a9049054013a1b77]*/
if (omax > max) max = omax;
if (emax > max) max = emax;
- if (tvp)
- deadline = _PyTime_GetMonotonicClock() + timeout;
+ if (tvp) {
+ deadline = _PyDeadline_Init(timeout);
+ }
do {
Py_BEGIN_ALLOW_THREADS
goto finally;
if (tvp) {
- timeout = deadline - _PyTime_GetMonotonicClock();
+ timeout = _PyDeadline_Get(deadline);
if (timeout < 0) {
/* bpo-35310: lists were unmodified -- clear them explicitly */
FD_ZERO(&ifdset);
}
if (timeout >= 0) {
- deadline = _PyTime_GetMonotonicClock() + timeout;
+ deadline = _PyDeadline_Init(timeout);
}
}
}
if (timeout >= 0) {
- timeout = deadline - _PyTime_GetMonotonicClock();
+ timeout = _PyDeadline_Get(deadline);
if (timeout < 0) {
poll_result = 0;
break;
dvp.dp_nfds = self->max_n_fds;
dvp.dp_timeout = (int)ms;
- if (timeout >= 0)
- deadline = _PyTime_GetMonotonicClock() + timeout;
+ if (timeout >= 0) {
+ deadline = _PyDeadline_Init(timeout);
+ }
do {
/* call devpoll() */
return NULL;
if (timeout >= 0) {
- timeout = deadline - _PyTime_GetMonotonicClock();
+ timeout = _PyDeadline_Get(deadline);
if (timeout < 0) {
poll_result = 0;
break;
}
if (timeout >= 0) {
- deadline = _PyTime_GetMonotonicClock() + timeout;
+ deadline = _PyDeadline_Init(timeout);
}
}
goto error;
if (timeout >= 0) {
- timeout = deadline - _PyTime_GetMonotonicClock();
+ timeout = _PyDeadline_Get(deadline);
if (timeout < 0) {
nfds = 0;
break;
}
}
- if (ptimeoutspec)
- deadline = _PyTime_GetMonotonicClock() + timeout;
+ if (ptimeoutspec) {
+ deadline = _PyDeadline_Init(timeout);
+ }
do {
Py_BEGIN_ALLOW_THREADS
goto error;
if (ptimeoutspec) {
- timeout = deadline - _PyTime_GetMonotonicClock();
+ timeout = _PyDeadline_Get(deadline);
if (timeout < 0) {
gotevents = 0;
break;
PyObject *timeout_obj)
/*[clinic end generated code: output=59c8971e8ae18a64 input=87fd39237cf0b7ba]*/
{
- struct timespec ts;
- siginfo_t si;
- int res;
- _PyTime_t timeout, deadline, monotonic;
-
+ _PyTime_t timeout;
if (_PyTime_FromSecondsObject(&timeout,
timeout_obj, _PyTime_ROUND_CEILING) < 0)
return NULL;
return NULL;
}
- deadline = _PyTime_GetMonotonicClock() + timeout;
+ _PyTime_t deadline = _PyDeadline_Init(timeout);
+ siginfo_t si;
do {
- if (_PyTime_AsTimespec(timeout, &ts) < 0)
+ struct timespec ts;
+ if (_PyTime_AsTimespec(timeout, &ts) < 0) {
return NULL;
+ }
+ int res;
Py_BEGIN_ALLOW_THREADS
res = sigtimedwait(&sigset, &si, &ts);
Py_END_ALLOW_THREADS
if (PyErr_CheckSignals())
return NULL;
- monotonic = _PyTime_GetMonotonicClock();
- timeout = deadline - monotonic;
- if (timeout < 0)
+ timeout = _PyDeadline_Get(deadline);
+ if (timeout < 0) {
break;
+ }
} while (1);
return fill_siginfo(&si);
if (deadline_initialized) {
/* recompute the timeout */
- interval = deadline - _PyTime_GetMonotonicClock();
+ interval = _PyDeadline_Get(deadline);
}
else {
deadline_initialized = 1;
- deadline = _PyTime_GetMonotonicClock() + timeout;
+ deadline = _PyDeadline_Init(timeout);
interval = timeout;
}
- if (interval >= 0)
+ if (interval >= 0) {
res = internal_select(s, writing, interval, connect);
- else
+ }
+ else {
res = 1;
+ }
}
else {
res = internal_select(s, writing, timeout, connect);
Py_buffer pbuf;
struct sock_send ctx;
int has_timeout = (s->sock_timeout > 0);
- _PyTime_t interval = s->sock_timeout;
+ _PyTime_t timeout = s->sock_timeout;
_PyTime_t deadline = 0;
int deadline_initialized = 0;
PyObject *res = NULL;
if (has_timeout) {
if (deadline_initialized) {
/* recompute the timeout */
- interval = deadline - _PyTime_GetMonotonicClock();
+ timeout = _PyDeadline_Get(deadline);
}
else {
deadline_initialized = 1;
- deadline = _PyTime_GetMonotonicClock() + s->sock_timeout;
+ deadline = _PyDeadline_Init(timeout);
}
- if (interval <= 0) {
+ if (timeout <= 0) {
PyErr_SetString(PyExc_TimeoutError, "timed out");
goto done;
}
ctx.buf = buf;
ctx.len = len;
ctx.flags = flags;
- if (sock_call_ex(s, 1, sock_send_impl, &ctx, 0, NULL, interval) < 0)
+ if (sock_call_ex(s, 1, sock_send_impl, &ctx, 0, NULL, timeout) < 0)
goto done;
n = ctx.result;
assert(n >= 0);
}
-// 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;
+ }
}
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;
}
}
+// 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);
}
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)) {
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;
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;
+}
}
}
} 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) {
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) {
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
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
}
#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;