diff options
author | Nathaniel J. Smith <njs@pobox.com> | 2017-12-18 04:10:18 (GMT) |
---|---|---|
committer | Yury Selivanov <yury@magic.io> | 2017-12-18 04:10:18 (GMT) |
commit | 902ab80b590e474bb2077b1fae8aac497b856d66 (patch) | |
tree | 427ee762a41bc71af3e35dcace840dac8ac92173 /Modules | |
parent | 1b7c11ff0ee3efafbf5b38c3c6f37de5d63efb81 (diff) | |
download | cpython-902ab80b590e474bb2077b1fae8aac497b856d66.zip cpython-902ab80b590e474bb2077b1fae8aac497b856d66.tar.gz cpython-902ab80b590e474bb2077b1fae8aac497b856d66.tar.bz2 |
bpo-30050: Allow disabling full buffer warnings in signal.set_wakeup_fd (#4792)
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/signalmodule.c | 104 |
1 files changed, 51 insertions, 53 deletions
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index 1023244..b553eed 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -100,14 +100,15 @@ static volatile struct { static volatile struct { SOCKET_T fd; + int warn_on_full_buffer; int use_send; - int send_err_set; - int send_errno; - int send_win_error; -} wakeup = {INVALID_FD, 0, 0}; +} wakeup = {.fd = INVALID_FD, .warn_on_full_buffer = 1, .use_send = 0}; #else #define INVALID_FD (-1) -static volatile sig_atomic_t wakeup_fd = -1; +static volatile struct { + sig_atomic_t fd; + int warn_on_full_buffer; +} wakeup = {.fd = INVALID_FD, .warn_on_full_buffer = 1}; #endif /* Speed up sigcheck() when none tripped */ @@ -210,28 +211,15 @@ report_wakeup_write_error(void *data) #ifdef MS_WINDOWS static int -report_wakeup_send_error(void* Py_UNUSED(data)) +report_wakeup_send_error(void* data) { - PyObject *res; - - if (wakeup.send_win_error) { - /* PyErr_SetExcFromWindowsErr() invokes FormatMessage() which - recognizes the error codes used by both GetLastError() and - WSAGetLastError */ - res = PyErr_SetExcFromWindowsErr(PyExc_OSError, wakeup.send_win_error); - } - else { - errno = wakeup.send_errno; - res = PyErr_SetFromErrno(PyExc_OSError); - } - - assert(res == NULL); - wakeup.send_err_set = 0; - + /* PyErr_SetExcFromWindowsErr() invokes FormatMessage() which + recognizes the error codes used by both GetLastError() and + WSAGetLastError */ + PyErr_SetExcFromWindowsErr(PyExc_OSError, (int) (intptr_t) data); PySys_WriteStderr("Exception ignored when trying to send to the " "signal wakeup fd:\n"); PyErr_WriteUnraisable(NULL); - return 0; } #endif /* MS_WINDOWS */ @@ -257,7 +245,7 @@ trip_signal(int sig_num) and then set the flag, but this allowed the following sequence of events (especially on windows, where trip_signal may run in a new thread): - - main thread blocks on select([wakeup_fd], ...) + - main thread blocks on select([wakeup.fd], ...) - signal arrives - trip_signal writes to the wakeup fd - the main thread wakes up @@ -274,41 +262,43 @@ trip_signal(int sig_num) #ifdef MS_WINDOWS fd = Py_SAFE_DOWNCAST(wakeup.fd, SOCKET_T, int); #else - fd = wakeup_fd; + fd = wakeup.fd; #endif if (fd != INVALID_FD) { byte = (unsigned char)sig_num; #ifdef MS_WINDOWS if (wakeup.use_send) { - do { - rc = send(fd, &byte, 1, 0); - } while (rc < 0 && errno == EINTR); - - /* we only have a storage for one error in the wakeup structure */ - if (rc < 0 && !wakeup.send_err_set) { - wakeup.send_err_set = 1; - wakeup.send_errno = errno; - wakeup.send_win_error = GetLastError(); - /* Py_AddPendingCall() isn't signal-safe, but we - still use it for this exceptional case. */ - Py_AddPendingCall(report_wakeup_send_error, NULL); + rc = send(fd, &byte, 1, 0); + + if (rc < 0) { + int last_error = GetLastError(); + if (wakeup.warn_on_full_buffer || + last_error != WSAEWOULDBLOCK) + { + /* Py_AddPendingCall() isn't signal-safe, but we + still use it for this exceptional case. */ + Py_AddPendingCall(report_wakeup_send_error, + (void *)(intptr_t) last_error); + } } } else #endif { - byte = (unsigned char)sig_num; - /* _Py_write_noraise() retries write() if write() is interrupted by a signal (fails with EINTR). */ rc = _Py_write_noraise(fd, &byte, 1); if (rc < 0) { - /* Py_AddPendingCall() isn't signal-safe, but we - still use it for this exceptional case. */ - Py_AddPendingCall(report_wakeup_write_error, - (void *)(intptr_t)errno); + if (wakeup.warn_on_full_buffer || + (errno != EWOULDBLOCK && errno != EAGAIN)) + { + /* Py_AddPendingCall() isn't signal-safe, but we + still use it for this exceptional case. */ + Py_AddPendingCall(report_wakeup_write_error, + (void *)(intptr_t)errno); + } } } } @@ -549,9 +539,13 @@ signal_siginterrupt_impl(PyObject *module, int signalnum, int flag) static PyObject* -signal_set_wakeup_fd(PyObject *self, PyObject *args) +signal_set_wakeup_fd(PyObject *self, PyObject *args, PyObject *kwds) { struct _Py_stat_struct status; + static char *kwlist[] = { + "", "warn_on_full_buffer", NULL, + }; + int warn_on_full_buffer = 1; #ifdef MS_WINDOWS PyObject *fdobj; SOCKET_T sockfd, old_sockfd; @@ -560,7 +554,8 @@ signal_set_wakeup_fd(PyObject *self, PyObject *args) PyObject *mod; int is_socket; - if (!PyArg_ParseTuple(args, "O:set_wakeup_fd", &fdobj)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|$p:set_wakeup_fd", kwlist, + &fdobj, &warn_on_full_buffer)) return NULL; sockfd = PyLong_AsSocket_t(fdobj); @@ -569,7 +564,8 @@ signal_set_wakeup_fd(PyObject *self, PyObject *args) #else int fd, old_fd; - if (!PyArg_ParseTuple(args, "i:set_wakeup_fd", &fd)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "i|$p:set_wakeup_fd", kwlist, + &fd, &warn_on_full_buffer)) return NULL; #endif @@ -620,6 +616,7 @@ signal_set_wakeup_fd(PyObject *self, PyObject *args) old_sockfd = wakeup.fd; wakeup.fd = sockfd; + wakeup.warn_on_full_buffer = warn_on_full_buffer; wakeup.use_send = is_socket; if (old_sockfd != INVALID_FD) @@ -644,15 +641,16 @@ signal_set_wakeup_fd(PyObject *self, PyObject *args) } } - old_fd = wakeup_fd; - wakeup_fd = fd; + old_fd = wakeup.fd; + wakeup.fd = fd; + wakeup.warn_on_full_buffer = warn_on_full_buffer; return PyLong_FromLong(old_fd); #endif } PyDoc_STRVAR(set_wakeup_fd_doc, -"set_wakeup_fd(fd) -> fd\n\ +"set_wakeup_fd(fd, *, warn_on_full_buffer=True) -> fd\n\ \n\ Sets the fd to be written to (with the signal number) when a signal\n\ comes in. A library can use this to wakeup select or poll.\n\ @@ -670,11 +668,11 @@ PySignal_SetWakeupFd(int fd) #ifdef MS_WINDOWS old_fd = Py_SAFE_DOWNCAST(wakeup.fd, SOCKET_T, int); - wakeup.fd = fd; #else - old_fd = wakeup_fd; - wakeup_fd = fd; + old_fd = wakeup.fd; #endif + wakeup.fd = fd; + wakeup.warn_on_full_buffer = 1; return old_fd; } @@ -1155,7 +1153,7 @@ static PyMethodDef signal_methods[] = { SIGNAL_GETITIMER_METHODDEF SIGNAL_SIGNAL_METHODDEF SIGNAL_GETSIGNAL_METHODDEF - {"set_wakeup_fd", signal_set_wakeup_fd, METH_VARARGS, set_wakeup_fd_doc}, + {"set_wakeup_fd", (PyCFunction)signal_set_wakeup_fd, METH_VARARGS | METH_KEYWORDS, set_wakeup_fd_doc}, SIGNAL_SIGINTERRUPT_METHODDEF SIGNAL_PAUSE_METHODDEF SIGNAL_PTHREAD_KILL_METHODDEF |