diff --git a/Include/ceval.h b/Include/ceval.h index e9df8684996e23f..418bd13d6321a68 100644 --- a/Include/ceval.h +++ b/Include/ceval.h @@ -124,6 +124,20 @@ PyAPI_FUNC(void) PyEval_ReleaseThread(PyThreadState *tstate); #define Py_END_ALLOW_THREADS PyEval_RestoreThread(_save); \ } + +/* Conditionally release and restore the GIL. */ +#define _Py_BEGIN_ALLOW_THREADS_COND(cond) \ + { \ + PyThreadState *_save = NULL; \ + if (cond) { \ + _save = PyEval_SaveThread(); \ + } +#define _Py_END_ALLOW_THREADS_COND \ + if (_save != NULL) { \ + PyEval_RestoreThread(_save); \ + } \ + } + /* Masks and values used by FORMAT_VALUE opcode. */ #define FVC_MASK 0x3 #define FVC_NONE 0x0 diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c index b9fb7762e3dacdf..47361466f65a8e0 100644 --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -357,7 +357,8 @@ select_select_impl(PyObject *module, PyObject *rlist, PyObject *wlist, } do { - Py_BEGIN_ALLOW_THREADS + int timeout_is_zero = (tvp != NULL && tvp->tv_sec == 0 && tvp->tv_usec == 0); + _Py_BEGIN_ALLOW_THREADS_COND(!timeout_is_zero) errno = 0; n = select( max, @@ -365,7 +366,7 @@ select_select_impl(PyObject *module, PyObject *rlist, PyObject *wlist, omax ? &ofdset : NULL, emax ? &efdset : NULL, tvp); - Py_END_ALLOW_THREADS + _Py_END_ALLOW_THREADS_COND if (errno != EINTR) break; @@ -698,14 +699,14 @@ select_poll_poll_impl(pollObject *self, PyObject *timeout_obj) /* call poll() */ async_err = 0; do { - Py_BEGIN_ALLOW_THREADS + _Py_BEGIN_ALLOW_THREADS_COND(ms != 0) errno = 0; #ifdef HAVE_PPOLL poll_result = ppoll(self->ufds, self->ufd_len, ts_p, NULL); #else poll_result = poll(self->ufds, self->ufd_len, (int)ms); #endif - Py_END_ALLOW_THREADS + _Py_END_ALLOW_THREADS_COND if (errno != EINTR) break; @@ -1034,10 +1035,10 @@ select_devpoll_poll_impl(devpollObject *self, PyObject *timeout_obj) do { /* call devpoll() */ - Py_BEGIN_ALLOW_THREADS + _Py_BEGIN_ALLOW_THREADS_COND(ms != 0) errno = 0; poll_result = ioctl(self->fd_devpoll, DP_POLL, &dvp); - Py_END_ALLOW_THREADS + _Py_END_ALLOW_THREADS_COND if (errno != EINTR) break; @@ -1513,17 +1514,13 @@ pyepoll_internal_ctl(int epfd, int op, int fd, unsigned int events) case EPOLL_CTL_MOD: ev.events = events; ev.data.fd = fd; - Py_BEGIN_ALLOW_THREADS result = epoll_ctl(epfd, op, fd, &ev); - Py_END_ALLOW_THREADS break; case EPOLL_CTL_DEL: /* In kernel versions before 2.6.9, the EPOLL_CTL_DEL * operation required a non-NULL pointer in event, even * though this argument is ignored. */ - Py_BEGIN_ALLOW_THREADS result = epoll_ctl(epfd, op, fd, &ev); - Py_END_ALLOW_THREADS break; default: result = -1; @@ -1673,10 +1670,10 @@ select_epoll_poll_impl(pyEpoll_Object *self, PyObject *timeout_obj, } do { - Py_BEGIN_ALLOW_THREADS + _Py_BEGIN_ALLOW_THREADS_COND(ms != 0) errno = 0; nfds = epoll_wait(self->epfd, evs, maxevents, (int)ms); - Py_END_ALLOW_THREADS + _Py_END_ALLOW_THREADS_COND if (errno != EINTR) break; @@ -2429,11 +2426,14 @@ select_kqueue_control_impl(kqueue_queue_Object *self, PyObject *changelist, } do { - Py_BEGIN_ALLOW_THREADS + int timeout_is_zero = (ptimeoutspec != NULL && + ptimeoutspec->tv_sec == 0 && + ptimeoutspec->tv_nsec == 0); + _Py_BEGIN_ALLOW_THREADS_COND(!timeout_is_zero) errno = 0; gotevents = kevent(self->kqfd, chl, nchanges, evl, maxevents, ptimeoutspec); - Py_END_ALLOW_THREADS + _Py_END_ALLOW_THREADS_COND if (errno != EINTR) break; diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 82899572f80255a..915d0b36be900b1 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -976,7 +976,7 @@ internal_select(PySocketSockObject *s, int writing, PyTime_t interval, When the function is retried, recompute the timeout using a monotonic clock. sock_call_ex() must be called with the GIL held. The socket function is - called with the GIL released. */ + called with the GIL released if the socket is blocking. */ static int sock_call_ex(PySocketSockObject *s, int writing, @@ -1059,9 +1059,9 @@ sock_call_ex(PySocketSockObject *s, /* inner loop to retry sock_func() when sock_func() is interrupted by a signal */ while (1) { - Py_BEGIN_ALLOW_THREADS + _Py_BEGIN_ALLOW_THREADS_COND(s->sock_timeout) res = sock_func(s, data); - Py_END_ALLOW_THREADS + _Py_END_ALLOW_THREADS_COND if (res) { /* sock_func() succeeded */ @@ -3655,9 +3655,9 @@ _socket_socket_close_impl(PySocketSockObject *s) http://lwn.net/Articles/576478/ and http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html for more details. */ - Py_BEGIN_ALLOW_THREADS + _Py_BEGIN_ALLOW_THREADS_COND(s->sock_timeout) res = SOCKETCLOSE(fd); - Py_END_ALLOW_THREADS + _Py_END_ALLOW_THREADS_COND /* bpo-30319: The peer can already have closed the connection. Python ignores ECONNRESET on close(). */ if (res < 0 && errno != ECONNRESET) {