summaryrefslogtreecommitdiffstats
path: root/Modules/selectmodule.c
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2015-03-30 19:59:21 (GMT)
committerVictor Stinner <victor.stinner@gmail.com>2015-03-30 19:59:21 (GMT)
commit41eba224de4d4752346ab051b6a411ec6f4a29fb (patch)
tree0bf84e5e39ab19990fa9ae6a0382d99ff5992558 /Modules/selectmodule.c
parent3c7d6e069331ceab0da6b794e4069f07bb3d4aac (diff)
downloadcpython-41eba224de4d4752346ab051b6a411ec6f4a29fb.zip
cpython-41eba224de4d4752346ab051b6a411ec6f4a29fb.tar.gz
cpython-41eba224de4d4752346ab051b6a411ec6f4a29fb.tar.bz2
Issue #23485: select.epoll.poll() is now retried when interrupted by a signal
Diffstat (limited to 'Modules/selectmodule.c')
-rw-r--r--Modules/selectmodule.c69
1 files changed, 51 insertions, 18 deletions
diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c
index 71b6683..96be5ba 100644
--- a/Modules/selectmodule.c
+++ b/Modules/selectmodule.c
@@ -535,7 +535,7 @@ poll_poll(pollObject *self, PyObject *args)
if (timeout_obj == NULL || timeout_obj == Py_None) {
timeout = -1;
ms = -1;
- deadline = 0;
+ deadline = 0; /* initialize to prevent gcc warning */
}
else {
if (_PyTime_FromMillisecondsObject(&timeout, timeout_obj,
@@ -1465,34 +1465,46 @@ fd is the target file descriptor of the operation.");
static PyObject *
pyepoll_poll(pyEpoll_Object *self, PyObject *args, PyObject *kwds)
{
- double dtimeout = -1.;
- int timeout;
+ static char *kwlist[] = {"timeout", "maxevents", NULL};
+ PyObject *timeout_obj = NULL;
int maxevents = -1;
int nfds, i;
PyObject *elist = NULL, *etuple = NULL;
struct epoll_event *evs = NULL;
- static char *kwlist[] = {"timeout", "maxevents", NULL};
+ _PyTime_t timeout, ms, deadline;
if (self->epfd < 0)
return pyepoll_err_closed();
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "|di:poll", kwlist,
- &dtimeout, &maxevents)) {
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oi:poll", kwlist,
+ &timeout_obj, &maxevents)) {
return NULL;
}
- if (dtimeout < 0) {
+ if (timeout_obj == NULL || timeout_obj == Py_None) {
timeout = -1;
- }
- else if (dtimeout * 1000.0 > INT_MAX) {
- PyErr_SetString(PyExc_OverflowError,
- "timeout is too large");
- return NULL;
+ ms = -1;
+ deadline = 0; /* initialize to prevent gcc warning */
}
else {
- /* epoll_wait() has a resolution of 1 millisecond, round away from zero
- to wait *at least* dtimeout seconds. */
- timeout = (int)ceil(dtimeout * 1000.0);
+ /* epoll_wait() has a resolution of 1 millisecond, round towards
+ infinity to wait at least timeout seconds. */
+ if (_PyTime_FromSecondsObject(&timeout, timeout_obj,
+ _PyTime_ROUND_CEILING) < 0) {
+ if (PyErr_ExceptionMatches(PyExc_TypeError)) {
+ PyErr_SetString(PyExc_TypeError,
+ "timeout must be an integer or None");
+ }
+ return NULL;
+ }
+
+ ms = _PyTime_AsMilliseconds(timeout, _PyTime_ROUND_CEILING);
+ if (ms < INT_MIN || ms > INT_MAX) {
+ PyErr_SetString(PyExc_OverflowError, "timeout is too large");
+ return NULL;
+ }
+
+ deadline = _PyTime_GetMonotonicClock() + timeout;
}
if (maxevents == -1) {
@@ -1511,9 +1523,30 @@ pyepoll_poll(pyEpoll_Object *self, PyObject *args, PyObject *kwds)
return NULL;
}
- Py_BEGIN_ALLOW_THREADS
- nfds = epoll_wait(self->epfd, evs, maxevents, timeout);
- Py_END_ALLOW_THREADS
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ errno = 0;
+ nfds = epoll_wait(self->epfd, evs, maxevents, (int)ms);
+ Py_END_ALLOW_THREADS
+
+ if (errno != EINTR)
+ break;
+
+ /* poll() was interrupted by a signal */
+ if (PyErr_CheckSignals())
+ goto error;
+
+ if (timeout >= 0) {
+ timeout = deadline - _PyTime_GetMonotonicClock();
+ if (timeout < 0) {
+ nfds = 0;
+ break;
+ }
+ ms = _PyTime_AsMilliseconds(timeout, _PyTime_ROUND_CEILING);
+ /* retry epoll_wait() with the recomputed timeout */
+ }
+ } while(1);
+
if (nfds < 0) {
PyErr_SetFromErrno(PyExc_OSError);
goto error;