cpython: 5194a84ed9f3 (original) (raw)
Mercurial > cpython
changeset 95308:5194a84ed9f3
Issue #23485: select.epoll.poll() is now retried when interrupted by a signal [#23485]
Victor Stinner victor.stinner@gmail.com | |
---|---|
date | Mon, 30 Mar 2015 21:59:21 +0200 |
parents | 69b1683ee001 |
children | a5cc958861e4 |
files | Doc/library/select.rst Doc/whatsnew/3.5.rst Lib/selectors.py Lib/test/eintrdata/eintr_tester.py Modules/selectmodule.c |
diffstat | 5 files changed, 71 insertions(+), 23 deletions(-)[+] [-] Doc/library/select.rst 6 Doc/whatsnew/3.5.rst 2 Lib/selectors.py 6 Lib/test/eintrdata/eintr_tester.py 11 Modules/selectmodule.c 69 |
line wrap: on
line diff
--- a/Doc/library/select.rst +++ b/Doc/library/select.rst @@ -329,6 +329,12 @@ Edge and Level Trigger Polling (epoll) O Wait for events. timeout in seconds (float)
- .. versionchanged:: 3.5
The function is now retried with a recomputed timeout when interrupted by[](#l1.8)
a signal, except if the signal handler raises an exception (see[](#l1.9)
:pep:`475` for the rationale), instead of raising[](#l1.10)
:exc:`InterruptedError`.[](#l1.11)
--- a/Doc/whatsnew/3.5.rst +++ b/Doc/whatsnew/3.5.rst @@ -621,7 +621,7 @@ Changes in the Python API
--- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -423,11 +423,9 @@ if hasattr(select, 'epoll'): # FD is registered. max_ev = max(len(self._fd_to_key), 1)
fd_event_list = self._epoll.poll(timeout, max_ev)[](#l3.7)
try:[](#l3.10)
fd_event_list = self._epoll.poll(timeout, max_ev)[](#l3.11)
except InterruptedError:[](#l3.12)
return ready[](#l3.13) for fd, event in fd_event_list:[](#l3.14) events = 0[](#l3.15) if event & ~select.EPOLLIN:[](#l3.16)
--- a/Lib/test/eintrdata/eintr_tester.py +++ b/Lib/test/eintrdata/eintr_tester.py @@ -329,6 +329,17 @@ class SelectEINTRTest(EINTRBaseTest): dt = time.monotonic() - t0 self.assertGreaterEqual(dt, self.sleep_time)
- @unittest.skipUnless(hasattr(select, 'epoll'), 'need select.epoll')
- def test_epoll(self):
poller = select.epoll()[](#l4.9)
self.addCleanup(poller.close)[](#l4.10)
t0 = time.monotonic()[](#l4.12)
poller.poll(self.sleep_time)[](#l4.13)
self.stop_alarm()[](#l4.14)
dt = time.monotonic() - t0[](#l4.15)
self.assertGreaterEqual(dt, self.sleep_time)[](#l4.16)
+ def test_main(): support.run_unittest(
--- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -535,7 +535,7 @@ poll_poll(pollObject *self, PyObject *ar if (timeout_obj == NULL || timeout_obj == Py_None) { timeout = -1; ms = -1;
deadline = 0;[](#l5.7)
} else { if (_PyTime_FromMillisecondsObject(&timeout, timeout_obj,deadline = 0; /* initialize to prevent gcc warning */[](#l5.8)
@@ -1465,34 +1465,46 @@ fd is the target file descriptor of the static PyObject * pyepoll_poll(pyEpoll_Object *self, PyObject *args, PyObject *kwds) {
- 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;
if (self->epfd < 0) return pyepoll_err_closed();
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "|di:poll", kwlist,
&dtimeout, &maxevents)) {[](#l5.31)
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oi:poll", kwlist,
}&timeout_obj, &maxevents)) {[](#l5.33) return NULL;[](#l5.34)
- }
- else if (dtimeout * 1000.0 > INT_MAX) {
PyErr_SetString(PyExc_OverflowError,[](#l5.42)
"timeout is too large");[](#l5.43)
return NULL;[](#l5.44)
/* epoll_wait() has a resolution of 1 millisecond, round away from zero[](#l5.49)
to wait *at least* dtimeout seconds. */[](#l5.50)
timeout = (int)ceil(dtimeout * 1000.0);[](#l5.51)
/* epoll_wait() has a resolution of 1 millisecond, round towards[](#l5.52)
infinity to wait at least timeout seconds. */[](#l5.53)
if (_PyTime_FromSecondsObject(&timeout, timeout_obj,[](#l5.54)
_PyTime_ROUND_CEILING) < 0) {[](#l5.55)
if (PyErr_ExceptionMatches(PyExc_TypeError)) {[](#l5.56)
PyErr_SetString(PyExc_TypeError,[](#l5.57)
"timeout must be an integer or None");[](#l5.58)
}[](#l5.59)
return NULL;[](#l5.60)
}[](#l5.61)
ms = _PyTime_AsMilliseconds(timeout, _PyTime_ROUND_CEILING);[](#l5.63)
if (ms < INT_MIN || ms > INT_MAX) {[](#l5.64)
PyErr_SetString(PyExc_OverflowError, "timeout is too large");[](#l5.65)
return NULL;[](#l5.66)
}[](#l5.67)
} if (maxevents == -1) { @@ -1511,9 +1523,30 @@ pyepoll_poll(pyEpoll_Object *self, PyObj return NULL; }deadline = _PyTime_GetMonotonicClock() + timeout;[](#l5.69)
- do {
Py_BEGIN_ALLOW_THREADS[](#l5.81)
errno = 0;[](#l5.82)
nfds = epoll_wait(self->epfd, evs, maxevents, (int)ms);[](#l5.83)
Py_END_ALLOW_THREADS[](#l5.84)
if (errno != EINTR)[](#l5.86)
break;[](#l5.87)
/* poll() was interrupted by a signal */[](#l5.89)
if (PyErr_CheckSignals())[](#l5.90)
goto error;[](#l5.91)
if (timeout >= 0) {[](#l5.93)
timeout = deadline - _PyTime_GetMonotonicClock();[](#l5.94)
if (timeout < 0) {[](#l5.95)
nfds = 0;[](#l5.96)
break;[](#l5.97)
}[](#l5.98)
ms = _PyTime_AsMilliseconds(timeout, _PyTime_ROUND_CEILING);[](#l5.99)
/* retry epoll_wait() with the recomputed timeout */[](#l5.100)
}[](#l5.101)
- } while(1);
+ if (nfds < 0) { PyErr_SetFromErrno(PyExc_OSError); goto error;