Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions Include/cpython/pytime.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
//
// 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:
//
Expand Down Expand Up @@ -215,7 +217,12 @@ PyAPI_FUNC(int) _PyTime_AsTimespec(_PyTime_t t, struct timespec *ts);
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,
Expand Down Expand Up @@ -299,6 +306,15 @@ PyAPI_FUNC(int) _PyTime_GetPerfCounterWithInfo(
_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
Expand Down
31 changes: 18 additions & 13 deletions Modules/_queuemodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ _queue.SimpleQueue.get
cls: defining_class
/
block: bool = True
timeout: object = None
timeout as timeout_obj: object = None

Remove and return an item from the queue.

Expand All @@ -198,11 +198,11 @@ in that case).

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;
Expand All @@ -211,24 +211,25 @@ _queue_SimpleQueue_get_impl(simplequeueobject *self, PyTypeObject *cls,
/* 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 */
Expand All @@ -247,6 +248,7 @@ _queue_SimpleQueue_get_impl(simplequeueobject *self, PyTypeObject *cls,
r = PyThread_acquire_lock_timed(self->lock, microseconds, 1);
Py_END_ALLOW_THREADS
}

if (r == PY_LOCK_INTR && Py_MakePendingCalls() < 0) {
return NULL;
}
Expand All @@ -258,12 +260,15 @@ _queue_SimpleQueue_get_impl(simplequeueobject *self, PyTypeObject *cls,
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);
Expand Down
34 changes: 20 additions & 14 deletions Modules/_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -949,8 +949,9 @@ _ssl__SSLSocket_do_handshake_impl(PySSLSocket *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. */
Expand All @@ -965,7 +966,7 @@ _ssl__SSLSocket_do_handshake_impl(PySSLSocket *self)
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);
Expand Down Expand Up @@ -2326,8 +2327,9 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b)

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) {
Expand All @@ -2354,8 +2356,9 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b)
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);
Expand Down Expand Up @@ -2494,7 +2497,7 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len,
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
Expand All @@ -2506,8 +2509,9 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len,
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);
Expand Down Expand Up @@ -2592,8 +2596,9 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self)

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
Expand Down Expand Up @@ -2626,8 +2631,9 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self)
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)
Expand Down
7 changes: 3 additions & 4 deletions Modules/_threadmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,12 @@ lock_dealloc(lockobject *self)
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);
Expand All @@ -114,7 +113,7 @@ acquire_timed(PyThread_type_lock lock, _PyTime_t timeout)
/* 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.
*/
Expand Down
10 changes: 5 additions & 5 deletions Modules/clinic/_queuemodule.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 16 additions & 13 deletions Modules/selectmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -318,8 +318,9 @@ select_select_impl(PyObject *module, PyObject *rlist, PyObject *wlist,
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
Expand All @@ -335,7 +336,7 @@ select_select_impl(PyObject *module, PyObject *rlist, PyObject *wlist,
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);
Expand Down Expand Up @@ -599,7 +600,7 @@ select_poll_poll_impl(pollObject *self, PyObject *timeout_obj)
}

if (timeout >= 0) {
deadline = _PyTime_GetMonotonicClock() + timeout;
deadline = _PyDeadline_Init(timeout);
}
}

Expand Down Expand Up @@ -646,7 +647,7 @@ select_poll_poll_impl(pollObject *self, PyObject *timeout_obj)
}

if (timeout >= 0) {
timeout = deadline - _PyTime_GetMonotonicClock();
timeout = _PyDeadline_Get(deadline);
if (timeout < 0) {
poll_result = 0;
break;
Expand Down Expand Up @@ -938,8 +939,9 @@ select_devpoll_poll_impl(devpollObject *self, PyObject *timeout_obj)
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() */
Expand All @@ -956,7 +958,7 @@ select_devpoll_poll_impl(devpollObject *self, PyObject *timeout_obj)
return NULL;

if (timeout >= 0) {
timeout = deadline - _PyTime_GetMonotonicClock();
timeout = _PyDeadline_Get(deadline);
if (timeout < 0) {
poll_result = 0;
break;
Expand Down Expand Up @@ -1550,7 +1552,7 @@ select_epoll_poll_impl(pyEpoll_Object *self, PyObject *timeout_obj,
}

if (timeout >= 0) {
deadline = _PyTime_GetMonotonicClock() + timeout;
deadline = _PyDeadline_Init(timeout);
}
}

Expand Down Expand Up @@ -1584,7 +1586,7 @@ select_epoll_poll_impl(pyEpoll_Object *self, PyObject *timeout_obj,
goto error;

if (timeout >= 0) {
timeout = deadline - _PyTime_GetMonotonicClock();
timeout = _PyDeadline_Get(deadline);
if (timeout < 0) {
nfds = 0;
break;
Expand Down Expand Up @@ -2172,8 +2174,9 @@ select_kqueue_control_impl(kqueue_queue_Object *self, PyObject *changelist,
}
}

if (ptimeoutspec)
deadline = _PyTime_GetMonotonicClock() + timeout;
if (ptimeoutspec) {
deadline = _PyDeadline_Init(timeout);
}

do {
Py_BEGIN_ALLOW_THREADS
Expand All @@ -2190,7 +2193,7 @@ select_kqueue_control_impl(kqueue_queue_Object *self, PyObject *changelist,
goto error;

if (ptimeoutspec) {
timeout = deadline - _PyTime_GetMonotonicClock();
timeout = _PyDeadline_Get(deadline);
if (timeout < 0) {
gotevents = 0;
break;
Expand Down
Loading