summaryrefslogtreecommitdiff
path: root/Modules/selectmodule.c
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2015-03-30 21:16:11 +0200
committerVictor Stinner <victor.stinner@gmail.com>2015-03-30 21:16:11 +0200
commitf70e1ca0fc30426d12aa8fc6684764ee11a66777 (patch)
treeadde4b05e331c51ea39f603aff8171ca1527cef6 /Modules/selectmodule.c
parent3f5d48bead8e937aef6f94a3211406270c1a5f8f (diff)
downloadcpython-git-f70e1ca0fc30426d12aa8fc6684764ee11a66777.tar.gz
Issue #23485: select.select() is now retried automatically with the recomputed
timeout when interrupted by a signal, except if the signal handler raises an exception. This change is part of the PEP 475. The asyncore and selectors module doesn't catch the InterruptedError exception anymore when calling select.select(), since this function should not raise InterruptedError anymore.
Diffstat (limited to 'Modules/selectmodule.c')
-rw-r--r--Modules/selectmodule.c53
1 files changed, 39 insertions, 14 deletions
diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c
index a8523440a9..a6d6a83750 100644
--- a/Modules/selectmodule.c
+++ b/Modules/selectmodule.c
@@ -193,29 +193,31 @@ select_select(PyObject *self, PyObject *args)
#endif /* SELECT_USES_HEAP */
PyObject *ifdlist, *ofdlist, *efdlist;
PyObject *ret = NULL;
- PyObject *tout = Py_None;
+ PyObject *timeout_obj = Py_None;
fd_set ifdset, ofdset, efdset;
struct timeval tv, *tvp;
int imax, omax, emax, max;
int n;
+ _PyTime_t timeout, deadline = 0;
/* convert arguments */
if (!PyArg_UnpackTuple(args, "select", 3, 4,
- &ifdlist, &ofdlist, &efdlist, &tout))
+ &ifdlist, &ofdlist, &efdlist, &timeout_obj))
return NULL;
- if (tout == Py_None)
- tvp = (struct timeval *)0;
+ if (timeout_obj == Py_None)
+ tvp = (struct timeval *)NULL;
else {
- _PyTime_t ts;
-
- if (_PyTime_FromSecondsObject(&ts, tout, _PyTime_ROUND_CEILING) < 0) {
- PyErr_SetString(PyExc_TypeError,
- "timeout must be a float or None");
+ if (_PyTime_FromSecondsObject(&timeout, timeout_obj,
+ _PyTime_ROUND_CEILING) < 0) {
+ if (PyErr_ExceptionMatches(PyExc_TypeError)) {
+ PyErr_SetString(PyExc_TypeError,
+ "timeout must be a float or None");
+ }
return NULL;
}
- if (_PyTime_AsTimeval(ts, &tv, _PyTime_ROUND_CEILING) == -1)
+ if (_PyTime_AsTimeval(timeout, &tv, _PyTime_ROUND_CEILING) == -1)
return NULL;
if (tv.tv_sec < 0) {
PyErr_SetString(PyExc_ValueError, "timeout must be non-negative");
@@ -224,7 +226,6 @@ select_select(PyObject *self, PyObject *args)
tvp = &tv;
}
-
#ifdef SELECT_USES_HEAP
/* Allocate memory for the lists */
rfd2obj = PyMem_NEW(pylist, FD_SETSIZE + 1);
@@ -237,6 +238,7 @@ select_select(PyObject *self, PyObject *args)
return PyErr_NoMemory();
}
#endif /* SELECT_USES_HEAP */
+
/* Convert sequences to fd_sets, and get maximum fd number
* propagates the Python exception set in seq2set()
*/
@@ -249,13 +251,36 @@ select_select(PyObject *self, PyObject *args)
goto finally;
if ((emax=seq2set(efdlist, &efdset, efd2obj)) < 0)
goto finally;
+
max = imax;
if (omax > max) max = omax;
if (emax > max) max = emax;
- Py_BEGIN_ALLOW_THREADS
- n = select(max, &ifdset, &ofdset, &efdset, tvp);
- Py_END_ALLOW_THREADS
+ if (tvp)
+ deadline = _PyTime_GetMonotonicClock() + timeout;
+
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ errno = 0;
+ n = select(max, &ifdset, &ofdset, &efdset, tvp);
+ Py_END_ALLOW_THREADS
+
+ if (errno != EINTR)
+ break;
+
+ /* select() was interrupted by a signal */
+ if (PyErr_CheckSignals())
+ goto finally;
+
+ if (tvp) {
+ timeout = deadline - _PyTime_GetMonotonicClock();
+ if (timeout < 0) {
+ n = 0;
+ break;
+ }
+ _PyTime_AsTimeval_noraise(timeout, &tv, _PyTime_ROUND_CEILING);
+ }
+ } while (1);
#ifdef MS_WINDOWS
if (n == SOCKET_ERROR) {