diff -r 0d0989359bbb Modules/selectmodule.c --- a/Modules/selectmodule.c Sun May 24 16:41:42 2015 -0700 +++ b/Modules/selectmodule.c Sun May 24 22:23:47 2015 -0700 @@ -194,10 +194,14 @@ PyObject *ifdlist, *ofdlist, *efdlist; PyObject *ret = NULL; PyObject *timeout_obj = Py_None; - fd_set ifdset, ofdset, efdset; + fd_set orig_ifdset, ifdset, ofdset, efdset; struct timeval tv, *tvp; int imax, omax, emax, max; int n; + int is_main_thread = _PyOS_IsMainThread(); + int wakeup_fds[2]; + int prev_wakeup_fd = -1; + char wakeup_signal = 0; _PyTime_t timeout, deadline = 0; /* convert arguments */ @@ -252,6 +256,27 @@ if ((emax=seq2set(efdlist, &efdset, efd2obj)) < 0) goto finally; + if (is_main_thread) { + int flags = 0; +#ifdef O_NONBLOCK + flags |= O_NONBLOCK; +#endif +#ifdef O_CLOEXEC + flags |= O_CLOEXEC; +#endif + if (pipe2(wakeup_fds, flags)) { + PyErr_SetFromErrno(PyExc_OSError); + goto finally; + } + prev_wakeup_fd = PySignal_SetWakeupFd(wakeup_fds[1]); + FD_SET(wakeup_fds[0], &ifdset); + if (wakeup_fds[0] >= imax) { + imax = wakeup_fds[0] + 1; + } + if (PyErr_CheckSignals()) + goto finally; + } + max = imax; if (omax > max) max = omax; if (emax > max) max = emax; @@ -259,28 +284,63 @@ if (tvp) deadline = _PyTime_GetMonotonicClock() + timeout; + orig_ifdset = ifdset; do { Py_BEGIN_ALLOW_THREADS errno = 0; n = select(max, &ifdset, &ofdset, &efdset, tvp); Py_END_ALLOW_THREADS - if (errno != EINTR) - break; + if (errno == EINTR) { + /* select() was interrupted by a signal */ + if (PyErr_CheckSignals()) + goto finally; - /* 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); + /* retry select() with the recomputed timeout */ + } + continue; + } - if (tvp) { - timeout = deadline - _PyTime_GetMonotonicClock(); - if (timeout < 0) { - n = 0; + if (is_main_thread && FD_ISSET(wakeup_fds[0], &ifdset)) { + /* Delete fd from everything that will be returned up. */ + FD_CLR(wakeup_fds[0], &ifdset); + n -= 1; + + while (read(wakeup_fds[0], &wakeup_signal, 1) < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + break; + } else if (errno == EINTR) { + continue; + } else { + PyErr_SetFromErrno(PyExc_OSError); + } + } + + if (prev_wakeup_fd != -1 && wakeup_signal != 0) { + while (write(prev_wakeup_fd, &wakeup_signal, 1) < 0) { + if (errno == EINTR) { + continue; + } + PyErr_SetFromErrno(PyExc_OSError); + } + } + if (PyErr_CheckSignals()) + goto finally; + if (n) { break; + } else { + ifdset = orig_ifdset; + continue; } - _PyTime_AsTimeval_noraise(timeout, &tv, _PyTime_ROUND_CEILING); - /* retry select() with the recomputed timeout */ } + break; } while (1); #ifdef MS_WINDOWS @@ -311,6 +371,21 @@ } finally: + if (is_main_thread) { + int i; + for (i = 0; i < 2; i++) { + while (close(wakeup_fds[i]) == -1) { + if (errno == EINTR) { + continue; + } + PyErr_SetFromErrno(PyExc_OSError); + Py_CLEAR(ret); + } + } + if (prev_wakeup_fd != -1) { + PySignal_SetWakeupFd(prev_wakeup_fd); + } + } reap_obj(rfd2obj); reap_obj(wfd2obj); reap_obj(efd2obj);