mirror of
https://github.com/python/cpython.git
synced 2025-10-09 16:34:44 +00:00
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().
This commit is contained in:
parent
54957f16a6
commit
833fdf126c
11 changed files with 177 additions and 109 deletions
|
@ -27,6 +27,8 @@
|
||||||
//
|
//
|
||||||
// Some functions clamp the result in the range [_PyTime_MIN; _PyTime_MAX], so
|
// 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.
|
// 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:
|
// Clocks:
|
||||||
//
|
//
|
||||||
|
@ -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);
|
PyAPI_FUNC(void) _PyTime_AsTimespec_clamp(_PyTime_t t, struct timespec *ts);
|
||||||
#endif
|
#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.
|
/* Compute ticks * mul / div.
|
||||||
|
Clamp to [_PyTime_MIN; _PyTime_MAX] on overflow.
|
||||||
The caller must ensure that ((div - 1) * mul) cannot overflow. */
|
The caller must ensure that ((div - 1) * mul) cannot overflow. */
|
||||||
PyAPI_FUNC(_PyTime_t) _PyTime_MulDiv(_PyTime_t ticks,
|
PyAPI_FUNC(_PyTime_t) _PyTime_MulDiv(_PyTime_t ticks,
|
||||||
_PyTime_t mul,
|
_PyTime_t mul,
|
||||||
|
@ -299,6 +306,15 @@ PyAPI_FUNC(int) _PyTime_GetPerfCounterWithInfo(
|
||||||
_PyTime_t *t,
|
_PyTime_t *t,
|
||||||
_Py_clock_info_t *info);
|
_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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -182,7 +182,7 @@ _queue.SimpleQueue.get
|
||||||
cls: defining_class
|
cls: defining_class
|
||||||
/
|
/
|
||||||
block: bool = True
|
block: bool = True
|
||||||
timeout: object = None
|
timeout as timeout_obj: object = None
|
||||||
|
|
||||||
Remove and return an item from the queue.
|
Remove and return an item from the queue.
|
||||||
|
|
||||||
|
@ -198,11 +198,11 @@ in that case).
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_queue_SimpleQueue_get_impl(simplequeueobject *self, PyTypeObject *cls,
|
_queue_SimpleQueue_get_impl(simplequeueobject *self, PyTypeObject *cls,
|
||||||
int block, PyObject *timeout)
|
int block, PyObject *timeout_obj)
|
||||||
/*[clinic end generated code: output=1969aefa7db63666 input=5fc4d56b9a54757e]*/
|
/*[clinic end generated code: output=5c2cca914cd1e55b input=5b4047bfbc645ec1]*/
|
||||||
{
|
{
|
||||||
_PyTime_t endtime = 0;
|
_PyTime_t endtime = 0;
|
||||||
_PyTime_t timeout_val;
|
_PyTime_t timeout;
|
||||||
PyObject *item;
|
PyObject *item;
|
||||||
PyLockStatus r;
|
PyLockStatus r;
|
||||||
PY_TIMEOUT_T microseconds;
|
PY_TIMEOUT_T microseconds;
|
||||||
|
@ -211,24 +211,25 @@ _queue_SimpleQueue_get_impl(simplequeueobject *self, PyTypeObject *cls,
|
||||||
/* Non-blocking */
|
/* Non-blocking */
|
||||||
microseconds = 0;
|
microseconds = 0;
|
||||||
}
|
}
|
||||||
else if (timeout != Py_None) {
|
else if (timeout_obj != Py_None) {
|
||||||
/* With timeout */
|
/* With timeout */
|
||||||
if (_PyTime_FromSecondsObject(&timeout_val,
|
if (_PyTime_FromSecondsObject(&timeout,
|
||||||
timeout, _PyTime_ROUND_CEILING) < 0)
|
timeout_obj, _PyTime_ROUND_CEILING) < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
if (timeout_val < 0) {
|
}
|
||||||
|
if (timeout < 0) {
|
||||||
PyErr_SetString(PyExc_ValueError,
|
PyErr_SetString(PyExc_ValueError,
|
||||||
"'timeout' must be a non-negative number");
|
"'timeout' must be a non-negative number");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
microseconds = _PyTime_AsMicroseconds(timeout_val,
|
microseconds = _PyTime_AsMicroseconds(timeout,
|
||||||
_PyTime_ROUND_CEILING);
|
_PyTime_ROUND_CEILING);
|
||||||
if (microseconds > PY_TIMEOUT_MAX) {
|
if (microseconds > PY_TIMEOUT_MAX) {
|
||||||
PyErr_SetString(PyExc_OverflowError,
|
PyErr_SetString(PyExc_OverflowError,
|
||||||
"timeout value is too large");
|
"timeout value is too large");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
endtime = _PyTime_GetMonotonicClock() + timeout_val;
|
endtime = _PyDeadline_Init(timeout);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Infinitely blocking */
|
/* Infinitely blocking */
|
||||||
|
@ -247,6 +248,7 @@ _queue_SimpleQueue_get_impl(simplequeueobject *self, PyTypeObject *cls,
|
||||||
r = PyThread_acquire_lock_timed(self->lock, microseconds, 1);
|
r = PyThread_acquire_lock_timed(self->lock, microseconds, 1);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r == PY_LOCK_INTR && Py_MakePendingCalls() < 0) {
|
if (r == PY_LOCK_INTR && Py_MakePendingCalls() < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -258,12 +260,15 @@ _queue_SimpleQueue_get_impl(simplequeueobject *self, PyTypeObject *cls,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
self->locked = 1;
|
self->locked = 1;
|
||||||
|
|
||||||
/* Adjust timeout for next iteration (if any) */
|
/* Adjust timeout for next iteration (if any) */
|
||||||
if (endtime > 0) {
|
if (microseconds > 0) {
|
||||||
timeout_val = endtime - _PyTime_GetMonotonicClock();
|
timeout = _PyDeadline_Get(endtime);
|
||||||
microseconds = _PyTime_AsMicroseconds(timeout_val, _PyTime_ROUND_CEILING);
|
microseconds = _PyTime_AsMicroseconds(timeout,
|
||||||
|
_PyTime_ROUND_CEILING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* BEGIN GIL-protected critical section */
|
/* BEGIN GIL-protected critical section */
|
||||||
assert(self->lst_pos < PyList_GET_SIZE(self->lst));
|
assert(self->lst_pos < PyList_GET_SIZE(self->lst));
|
||||||
item = simplequeue_pop_item(self);
|
item = simplequeue_pop_item(self);
|
||||||
|
|
|
@ -949,8 +949,9 @@ _ssl__SSLSocket_do_handshake_impl(PySSLSocket *self)
|
||||||
|
|
||||||
timeout = GET_SOCKET_TIMEOUT(sock);
|
timeout = GET_SOCKET_TIMEOUT(sock);
|
||||||
has_timeout = (timeout > 0);
|
has_timeout = (timeout > 0);
|
||||||
if (has_timeout)
|
if (has_timeout) {
|
||||||
deadline = _PyTime_GetMonotonicClock() + timeout;
|
deadline = _PyDeadline_Init(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
/* Actually negotiate SSL connection */
|
/* Actually negotiate SSL connection */
|
||||||
/* XXX If SSL_do_handshake() returns 0, it's also a failure. */
|
/* XXX If SSL_do_handshake() returns 0, it's also a failure. */
|
||||||
|
@ -965,7 +966,7 @@ _ssl__SSLSocket_do_handshake_impl(PySSLSocket *self)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (has_timeout)
|
if (has_timeout)
|
||||||
timeout = deadline - _PyTime_GetMonotonicClock();
|
timeout = _PyDeadline_Get(deadline);
|
||||||
|
|
||||||
if (err.ssl == SSL_ERROR_WANT_READ) {
|
if (err.ssl == SSL_ERROR_WANT_READ) {
|
||||||
sockstate = PySSL_select(sock, 0, timeout);
|
sockstate = PySSL_select(sock, 0, timeout);
|
||||||
|
@ -2326,8 +2327,9 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b)
|
||||||
|
|
||||||
timeout = GET_SOCKET_TIMEOUT(sock);
|
timeout = GET_SOCKET_TIMEOUT(sock);
|
||||||
has_timeout = (timeout > 0);
|
has_timeout = (timeout > 0);
|
||||||
if (has_timeout)
|
if (has_timeout) {
|
||||||
deadline = _PyTime_GetMonotonicClock() + timeout;
|
deadline = _PyDeadline_Init(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
sockstate = PySSL_select(sock, 1, timeout);
|
sockstate = PySSL_select(sock, 1, timeout);
|
||||||
if (sockstate == SOCKET_HAS_TIMED_OUT) {
|
if (sockstate == SOCKET_HAS_TIMED_OUT) {
|
||||||
|
@ -2354,8 +2356,9 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b)
|
||||||
if (PyErr_CheckSignals())
|
if (PyErr_CheckSignals())
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (has_timeout)
|
if (has_timeout) {
|
||||||
timeout = deadline - _PyTime_GetMonotonicClock();
|
timeout = _PyDeadline_Get(deadline);
|
||||||
|
}
|
||||||
|
|
||||||
if (err.ssl == SSL_ERROR_WANT_READ) {
|
if (err.ssl == SSL_ERROR_WANT_READ) {
|
||||||
sockstate = PySSL_select(sock, 0, timeout);
|
sockstate = PySSL_select(sock, 0, timeout);
|
||||||
|
@ -2494,7 +2497,7 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len,
|
||||||
timeout = GET_SOCKET_TIMEOUT(sock);
|
timeout = GET_SOCKET_TIMEOUT(sock);
|
||||||
has_timeout = (timeout > 0);
|
has_timeout = (timeout > 0);
|
||||||
if (has_timeout)
|
if (has_timeout)
|
||||||
deadline = _PyTime_GetMonotonicClock() + timeout;
|
deadline = _PyDeadline_Init(timeout);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
PySSL_BEGIN_ALLOW_THREADS
|
PySSL_BEGIN_ALLOW_THREADS
|
||||||
|
@ -2506,8 +2509,9 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len,
|
||||||
if (PyErr_CheckSignals())
|
if (PyErr_CheckSignals())
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (has_timeout)
|
if (has_timeout) {
|
||||||
timeout = deadline - _PyTime_GetMonotonicClock();
|
timeout = _PyDeadline_Get(deadline);
|
||||||
|
}
|
||||||
|
|
||||||
if (err.ssl == SSL_ERROR_WANT_READ) {
|
if (err.ssl == SSL_ERROR_WANT_READ) {
|
||||||
sockstate = PySSL_select(sock, 0, timeout);
|
sockstate = PySSL_select(sock, 0, timeout);
|
||||||
|
@ -2592,8 +2596,9 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self)
|
||||||
|
|
||||||
timeout = GET_SOCKET_TIMEOUT(sock);
|
timeout = GET_SOCKET_TIMEOUT(sock);
|
||||||
has_timeout = (timeout > 0);
|
has_timeout = (timeout > 0);
|
||||||
if (has_timeout)
|
if (has_timeout) {
|
||||||
deadline = _PyTime_GetMonotonicClock() + timeout;
|
deadline = _PyDeadline_Init(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
PySSL_BEGIN_ALLOW_THREADS
|
PySSL_BEGIN_ALLOW_THREADS
|
||||||
|
@ -2626,8 +2631,9 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_timeout)
|
if (has_timeout) {
|
||||||
timeout = deadline - _PyTime_GetMonotonicClock();
|
timeout = _PyDeadline_Get(deadline);
|
||||||
|
}
|
||||||
|
|
||||||
/* Possibly retry shutdown until timeout or failure */
|
/* Possibly retry shutdown until timeout or failure */
|
||||||
if (err.ssl == SSL_ERROR_WANT_READ)
|
if (err.ssl == SSL_ERROR_WANT_READ)
|
||||||
|
|
|
@ -84,13 +84,12 @@ lock_dealloc(lockobject *self)
|
||||||
static PyLockStatus
|
static PyLockStatus
|
||||||
acquire_timed(PyThread_type_lock lock, _PyTime_t timeout)
|
acquire_timed(PyThread_type_lock lock, _PyTime_t timeout)
|
||||||
{
|
{
|
||||||
PyLockStatus r;
|
|
||||||
_PyTime_t endtime = 0;
|
_PyTime_t endtime = 0;
|
||||||
|
|
||||||
if (timeout > 0) {
|
if (timeout > 0) {
|
||||||
endtime = _PyTime_GetMonotonicClock() + timeout;
|
endtime = _PyDeadline_Init(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyLockStatus r;
|
||||||
do {
|
do {
|
||||||
_PyTime_t microseconds;
|
_PyTime_t microseconds;
|
||||||
microseconds = _PyTime_AsMicroseconds(timeout, _PyTime_ROUND_CEILING);
|
microseconds = _PyTime_AsMicroseconds(timeout, _PyTime_ROUND_CEILING);
|
||||||
|
@ -114,7 +113,7 @@ acquire_timed(PyThread_type_lock lock, _PyTime_t timeout)
|
||||||
/* If we're using a timeout, recompute the timeout after processing
|
/* If we're using a timeout, recompute the timeout after processing
|
||||||
* signals, since those can take time. */
|
* signals, since those can take time. */
|
||||||
if (timeout > 0) {
|
if (timeout > 0) {
|
||||||
timeout = endtime - _PyTime_GetMonotonicClock();
|
timeout = _PyDeadline_Get(endtime);
|
||||||
|
|
||||||
/* Check for negative values, since those mean block forever.
|
/* Check for negative values, since those mean block forever.
|
||||||
*/
|
*/
|
||||||
|
|
10
Modules/clinic/_queuemodule.c.h
generated
10
Modules/clinic/_queuemodule.c.h
generated
|
@ -139,7 +139,7 @@ PyDoc_STRVAR(_queue_SimpleQueue_get__doc__,
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_queue_SimpleQueue_get_impl(simplequeueobject *self, PyTypeObject *cls,
|
_queue_SimpleQueue_get_impl(simplequeueobject *self, PyTypeObject *cls,
|
||||||
int block, PyObject *timeout);
|
int block, PyObject *timeout_obj);
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_queue_SimpleQueue_get(simplequeueobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
|
_queue_SimpleQueue_get(simplequeueobject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
|
||||||
|
@ -148,13 +148,13 @@ _queue_SimpleQueue_get(simplequeueobject *self, PyTypeObject *cls, PyObject *con
|
||||||
static const char * const _keywords[] = {"block", "timeout", NULL};
|
static const char * const _keywords[] = {"block", "timeout", NULL};
|
||||||
static _PyArg_Parser _parser = {"|pO:get", _keywords, 0};
|
static _PyArg_Parser _parser = {"|pO:get", _keywords, 0};
|
||||||
int block = 1;
|
int block = 1;
|
||||||
PyObject *timeout = Py_None;
|
PyObject *timeout_obj = Py_None;
|
||||||
|
|
||||||
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
|
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
|
||||||
&block, &timeout)) {
|
&block, &timeout_obj)) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
return_value = _queue_SimpleQueue_get_impl(self, cls, block, timeout);
|
return_value = _queue_SimpleQueue_get_impl(self, cls, block, timeout_obj);
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
|
@ -248,4 +248,4 @@ _queue_SimpleQueue_qsize(simplequeueobject *self, PyObject *Py_UNUSED(ignored))
|
||||||
exit:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
/*[clinic end generated code: output=96cc57168d72aab1 input=a9049054013a1b77]*/
|
/*[clinic end generated code: output=acfaf0191d8935db input=a9049054013a1b77]*/
|
||||||
|
|
|
@ -318,8 +318,9 @@ select_select_impl(PyObject *module, PyObject *rlist, PyObject *wlist,
|
||||||
if (omax > max) max = omax;
|
if (omax > max) max = omax;
|
||||||
if (emax > max) max = emax;
|
if (emax > max) max = emax;
|
||||||
|
|
||||||
if (tvp)
|
if (tvp) {
|
||||||
deadline = _PyTime_GetMonotonicClock() + timeout;
|
deadline = _PyDeadline_Init(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
@ -335,7 +336,7 @@ select_select_impl(PyObject *module, PyObject *rlist, PyObject *wlist,
|
||||||
goto finally;
|
goto finally;
|
||||||
|
|
||||||
if (tvp) {
|
if (tvp) {
|
||||||
timeout = deadline - _PyTime_GetMonotonicClock();
|
timeout = _PyDeadline_Get(deadline);
|
||||||
if (timeout < 0) {
|
if (timeout < 0) {
|
||||||
/* bpo-35310: lists were unmodified -- clear them explicitly */
|
/* bpo-35310: lists were unmodified -- clear them explicitly */
|
||||||
FD_ZERO(&ifdset);
|
FD_ZERO(&ifdset);
|
||||||
|
@ -599,7 +600,7 @@ select_poll_poll_impl(pollObject *self, PyObject *timeout_obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timeout >= 0) {
|
if (timeout >= 0) {
|
||||||
deadline = _PyTime_GetMonotonicClock() + timeout;
|
deadline = _PyDeadline_Init(timeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -646,7 +647,7 @@ select_poll_poll_impl(pollObject *self, PyObject *timeout_obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timeout >= 0) {
|
if (timeout >= 0) {
|
||||||
timeout = deadline - _PyTime_GetMonotonicClock();
|
timeout = _PyDeadline_Get(deadline);
|
||||||
if (timeout < 0) {
|
if (timeout < 0) {
|
||||||
poll_result = 0;
|
poll_result = 0;
|
||||||
break;
|
break;
|
||||||
|
@ -938,8 +939,9 @@ select_devpoll_poll_impl(devpollObject *self, PyObject *timeout_obj)
|
||||||
dvp.dp_nfds = self->max_n_fds;
|
dvp.dp_nfds = self->max_n_fds;
|
||||||
dvp.dp_timeout = (int)ms;
|
dvp.dp_timeout = (int)ms;
|
||||||
|
|
||||||
if (timeout >= 0)
|
if (timeout >= 0) {
|
||||||
deadline = _PyTime_GetMonotonicClock() + timeout;
|
deadline = _PyDeadline_Init(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
/* call devpoll() */
|
/* call devpoll() */
|
||||||
|
@ -956,7 +958,7 @@ select_devpoll_poll_impl(devpollObject *self, PyObject *timeout_obj)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (timeout >= 0) {
|
if (timeout >= 0) {
|
||||||
timeout = deadline - _PyTime_GetMonotonicClock();
|
timeout = _PyDeadline_Get(deadline);
|
||||||
if (timeout < 0) {
|
if (timeout < 0) {
|
||||||
poll_result = 0;
|
poll_result = 0;
|
||||||
break;
|
break;
|
||||||
|
@ -1550,7 +1552,7 @@ select_epoll_poll_impl(pyEpoll_Object *self, PyObject *timeout_obj,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timeout >= 0) {
|
if (timeout >= 0) {
|
||||||
deadline = _PyTime_GetMonotonicClock() + timeout;
|
deadline = _PyDeadline_Init(timeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1584,7 +1586,7 @@ select_epoll_poll_impl(pyEpoll_Object *self, PyObject *timeout_obj,
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (timeout >= 0) {
|
if (timeout >= 0) {
|
||||||
timeout = deadline - _PyTime_GetMonotonicClock();
|
timeout = _PyDeadline_Get(deadline);
|
||||||
if (timeout < 0) {
|
if (timeout < 0) {
|
||||||
nfds = 0;
|
nfds = 0;
|
||||||
break;
|
break;
|
||||||
|
@ -2172,8 +2174,9 @@ select_kqueue_control_impl(kqueue_queue_Object *self, PyObject *changelist,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ptimeoutspec)
|
if (ptimeoutspec) {
|
||||||
deadline = _PyTime_GetMonotonicClock() + timeout;
|
deadline = _PyDeadline_Init(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
@ -2190,7 +2193,7 @@ select_kqueue_control_impl(kqueue_queue_Object *self, PyObject *changelist,
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (ptimeoutspec) {
|
if (ptimeoutspec) {
|
||||||
timeout = deadline - _PyTime_GetMonotonicClock();
|
timeout = _PyDeadline_Get(deadline);
|
||||||
if (timeout < 0) {
|
if (timeout < 0) {
|
||||||
gotevents = 0;
|
gotevents = 0;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1221,11 +1221,7 @@ signal_sigtimedwait_impl(PyObject *module, sigset_t sigset,
|
||||||
PyObject *timeout_obj)
|
PyObject *timeout_obj)
|
||||||
/*[clinic end generated code: output=59c8971e8ae18a64 input=87fd39237cf0b7ba]*/
|
/*[clinic end generated code: output=59c8971e8ae18a64 input=87fd39237cf0b7ba]*/
|
||||||
{
|
{
|
||||||
struct timespec ts;
|
_PyTime_t timeout;
|
||||||
siginfo_t si;
|
|
||||||
int res;
|
|
||||||
_PyTime_t timeout, deadline, monotonic;
|
|
||||||
|
|
||||||
if (_PyTime_FromSecondsObject(&timeout,
|
if (_PyTime_FromSecondsObject(&timeout,
|
||||||
timeout_obj, _PyTime_ROUND_CEILING) < 0)
|
timeout_obj, _PyTime_ROUND_CEILING) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1235,12 +1231,16 @@ signal_sigtimedwait_impl(PyObject *module, sigset_t sigset,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
deadline = _PyTime_GetMonotonicClock() + timeout;
|
_PyTime_t deadline = _PyDeadline_Init(timeout);
|
||||||
|
siginfo_t si;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (_PyTime_AsTimespec(timeout, &ts) < 0)
|
struct timespec ts;
|
||||||
|
if (_PyTime_AsTimespec(timeout, &ts) < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res;
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
res = sigtimedwait(&sigset, &si, &ts);
|
res = sigtimedwait(&sigset, &si, &ts);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
@ -1259,10 +1259,10 @@ signal_sigtimedwait_impl(PyObject *module, sigset_t sigset,
|
||||||
if (PyErr_CheckSignals())
|
if (PyErr_CheckSignals())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
monotonic = _PyTime_GetMonotonicClock();
|
timeout = _PyDeadline_Get(deadline);
|
||||||
timeout = deadline - monotonic;
|
if (timeout < 0) {
|
||||||
if (timeout < 0)
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
} while (1);
|
} while (1);
|
||||||
|
|
||||||
return fill_siginfo(&si);
|
return fill_siginfo(&si);
|
||||||
|
|
|
@ -840,18 +840,20 @@ sock_call_ex(PySocketSockObject *s,
|
||||||
|
|
||||||
if (deadline_initialized) {
|
if (deadline_initialized) {
|
||||||
/* recompute the timeout */
|
/* recompute the timeout */
|
||||||
interval = deadline - _PyTime_GetMonotonicClock();
|
interval = _PyDeadline_Get(deadline);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
deadline_initialized = 1;
|
deadline_initialized = 1;
|
||||||
deadline = _PyTime_GetMonotonicClock() + timeout;
|
deadline = _PyDeadline_Init(timeout);
|
||||||
interval = timeout;
|
interval = timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (interval >= 0)
|
if (interval >= 0) {
|
||||||
res = internal_select(s, writing, interval, connect);
|
res = internal_select(s, writing, interval, connect);
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
res = 1;
|
res = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
res = internal_select(s, writing, timeout, connect);
|
res = internal_select(s, writing, timeout, connect);
|
||||||
|
@ -4176,7 +4178,7 @@ sock_sendall(PySocketSockObject *s, PyObject *args)
|
||||||
Py_buffer pbuf;
|
Py_buffer pbuf;
|
||||||
struct sock_send ctx;
|
struct sock_send ctx;
|
||||||
int has_timeout = (s->sock_timeout > 0);
|
int has_timeout = (s->sock_timeout > 0);
|
||||||
_PyTime_t interval = s->sock_timeout;
|
_PyTime_t timeout = s->sock_timeout;
|
||||||
_PyTime_t deadline = 0;
|
_PyTime_t deadline = 0;
|
||||||
int deadline_initialized = 0;
|
int deadline_initialized = 0;
|
||||||
PyObject *res = NULL;
|
PyObject *res = NULL;
|
||||||
|
@ -4195,14 +4197,14 @@ sock_sendall(PySocketSockObject *s, PyObject *args)
|
||||||
if (has_timeout) {
|
if (has_timeout) {
|
||||||
if (deadline_initialized) {
|
if (deadline_initialized) {
|
||||||
/* recompute the timeout */
|
/* recompute the timeout */
|
||||||
interval = deadline - _PyTime_GetMonotonicClock();
|
timeout = _PyDeadline_Get(deadline);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
deadline_initialized = 1;
|
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");
|
PyErr_SetString(PyExc_TimeoutError, "timed out");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -4211,7 +4213,7 @@ sock_sendall(PySocketSockObject *s, PyObject *args)
|
||||||
ctx.buf = buf;
|
ctx.buf = buf;
|
||||||
ctx.len = len;
|
ctx.len = len;
|
||||||
ctx.flags = flags;
|
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;
|
goto done;
|
||||||
n = ctx.result;
|
n = ctx.result;
|
||||||
assert(n >= 0);
|
assert(n >= 0);
|
||||||
|
|
|
@ -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
|
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) {
|
if (t2 > 0 && *t1 > _PyTime_MAX - t2) {
|
||||||
*t = _PyTime_MAX;
|
*t1 = _PyTime_MAX;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else if (t2 < 0 && *t < _PyTime_MIN - t2) {
|
else if (t2 < 0 && *t1 < _PyTime_MIN - t2) {
|
||||||
*t = _PyTime_MIN;
|
*t1 = _PyTime_MIN;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
*t += t2;
|
*t1 += t2;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline int
|
_PyTime_t
|
||||||
_PyTime_check_mul_overflow(_PyTime_t a, _PyTime_t b)
|
_PyTime_Add(_PyTime_t t1, _PyTime_t t2)
|
||||||
{
|
{
|
||||||
assert(b > 0);
|
(void)pytime_add(&t1, t2);
|
||||||
return ((a < _PyTime_MIN / b) || (_PyTime_MAX / b < a));
|
return t1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
pytime_mul_check_overflow(_PyTime_t a, _PyTime_t b)
|
||||||
|
{
|
||||||
|
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
|
static inline int
|
||||||
pytime_mul(_PyTime_t *t, _PyTime_t k)
|
pytime_mul(_PyTime_t *t, _PyTime_t k)
|
||||||
{
|
{
|
||||||
assert(k > 0);
|
assert(k >= 0);
|
||||||
if (_PyTime_check_mul_overflow(*t, k)) {
|
if (pytime_mul_check_overflow(*t, k)) {
|
||||||
*t = (*t >= 0) ? _PyTime_MAX : _PyTime_MIN;
|
*t = (*t >= 0) ? _PyTime_MAX : _PyTime_MIN;
|
||||||
return -1;
|
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_t
|
||||||
_PyTime_MulDiv(_PyTime_t ticks, _PyTime_t mul, _PyTime_t div)
|
_PyTime_MulDiv(_PyTime_t ticks, _PyTime_t mul, _PyTime_t div)
|
||||||
{
|
{
|
||||||
_PyTime_t intpart, remaining;
|
/* Compute (ticks * mul / div) in two parts to reduce the risk of integer
|
||||||
/* Compute (ticks * mul / div) in two parts to prevent integer overflow:
|
overflow: compute the integer part, and then the remaining part.
|
||||||
compute integer part, and then the remaining part.
|
|
||||||
|
|
||||||
(ticks * mul) / div == (ticks / div) * mul + (ticks % div) * mul / div
|
(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;
|
intpart = ticks / div;
|
||||||
ticks %= div;
|
ticks %= div;
|
||||||
remaining = ticks * mul;
|
remaining = _PyTime_Mul(ticks, mul) / div;
|
||||||
remaining /= div;
|
// intpart * mul + remaining
|
||||||
return 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);
|
return pytime_from_double(tp, d, round, unit_to_ns);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Py_BUILD_ASSERT(sizeof(long long) <= sizeof(_PyTime_t));
|
|
||||||
long long sec = PyLong_AsLongLong(obj);
|
long long sec = PyLong_AsLongLong(obj);
|
||||||
if (sec == -1 && PyErr_Occurred()) {
|
if (sec == -1 && PyErr_Occurred()) {
|
||||||
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
|
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
|
||||||
|
@ -514,11 +536,12 @@ pytime_from_object(_PyTime_t *tp, PyObject *obj, _PyTime_round_t round,
|
||||||
return -1;
|
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();
|
pytime_overflow();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
_PyTime_t ns = sec * unit_to_ns;
|
|
||||||
|
|
||||||
*tp = pytime_from_nanoseconds(ns);
|
*tp = pytime_from_nanoseconds(ns);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1292,3 +1315,19 @@ _PyTime_gmtime(time_t t, struct tm *tm)
|
||||||
return 0;
|
return 0;
|
||||||
#endif /* MS_WINDOWS */
|
#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;
|
||||||
|
}
|
||||||
|
|
|
@ -75,20 +75,20 @@ EnterNonRecursiveMutex(PNRMUTEX mutex, DWORD milliseconds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (milliseconds != 0) {
|
} else if (milliseconds != 0) {
|
||||||
/* wait at least until the target */
|
/* wait at least until the deadline */
|
||||||
_PyTime_t now = _PyTime_GetPerfCounter();
|
|
||||||
_PyTime_t nanoseconds = _PyTime_FromNanoseconds((_PyTime_t)milliseconds * 1000000);
|
_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) {
|
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) {
|
if (PyCOND_TIMEDWAIT(&mutex->cv, &mutex->cs, microseconds) < 0) {
|
||||||
result = WAIT_FAILED;
|
result = WAIT_FAILED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
now = _PyTime_GetPerfCounter();
|
nanoseconds = deadline - _PyTime_GetPerfCounter();
|
||||||
if (target <= now)
|
if (nanoseconds <= 0) {
|
||||||
break;
|
break;
|
||||||
nanoseconds = target - now;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!mutex->locked) {
|
if (!mutex->locked) {
|
||||||
|
|
|
@ -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",
|
dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) called\n",
|
||||||
lock, microseconds, intr_flag));
|
lock, microseconds, intr_flag));
|
||||||
|
|
||||||
_PyTime_t timeout;
|
_PyTime_t timeout; // relative timeout
|
||||||
if (microseconds >= 0) {
|
if (microseconds >= 0) {
|
||||||
_PyTime_t ns;
|
_PyTime_t ns;
|
||||||
if (microseconds <= _PyTime_MAX / 1000) {
|
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;
|
struct timespec abs_timeout;
|
||||||
// Local scope for deadline
|
// Local scope for deadline
|
||||||
{
|
{
|
||||||
_PyTime_t deadline = _PyTime_GetMonotonicClock() + timeout;
|
_PyTime_t deadline = _PyTime_Add(_PyTime_GetMonotonicClock(), timeout);
|
||||||
_PyTime_AsTimespec_clamp(deadline, &abs_timeout);
|
_PyTime_AsTimespec_clamp(deadline, &abs_timeout);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
_PyTime_t deadline = 0;
|
_PyTime_t deadline = 0;
|
||||||
if (timeout > 0
|
if (timeout > 0 && !intr_flag) {
|
||||||
&& !intr_flag
|
deadline = _PyDeadline_Init(timeout);
|
||||||
)
|
|
||||||
{
|
|
||||||
deadline = _PyTime_GetMonotonicClock() + timeout;
|
|
||||||
}
|
}
|
||||||
#endif
|
#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,
|
status = fix_status(sem_clockwait(thelock, CLOCK_MONOTONIC,
|
||||||
&abs_timeout));
|
&abs_timeout));
|
||||||
#else
|
#else
|
||||||
_PyTime_t abs_timeout = _PyTime_GetSystemClock() + timeout;
|
_PyTime_t abs_time = _PyTime_Add(_PyTime_GetSystemClock(),
|
||||||
|
timeout);
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
_PyTime_AsTimespec_clamp(abs_timeout, &ts);
|
_PyTime_AsTimespec_clamp(abs_time, &ts);
|
||||||
status = fix_status(sem_timedwait(thelock, &ts));
|
status = fix_status(sem_timedwait(thelock, &ts));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -508,7 +506,7 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
|
||||||
#ifndef HAVE_SEM_CLOCKWAIT
|
#ifndef HAVE_SEM_CLOCKWAIT
|
||||||
if (timeout > 0) {
|
if (timeout > 0) {
|
||||||
/* wait interrupted by a signal (EINTR): recompute the timeout */
|
/* wait interrupted by a signal (EINTR): recompute the timeout */
|
||||||
_PyTime_t timeout = deadline - _PyTime_GetMonotonicClock();
|
_PyTime_t timeout = _PyDeadline_Get(deadline);
|
||||||
if (timeout < 0) {
|
if (timeout < 0) {
|
||||||
status = ETIMEDOUT;
|
status = ETIMEDOUT;
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue