@@ -100,14 +100,15 @@ static volatile struct {
100100
101101static volatile struct {
102102 SOCKET_T fd ;
103+ int warn_on_full_buffer ;
103104 int use_send ;
104- int send_err_set ;
105- int send_errno ;
106- int send_win_error ;
107- } wakeup = {INVALID_FD , 0 , 0 };
105+ } wakeup = {.fd = INVALID_FD , .warn_on_full_buffer = 1 , .use_send = 0 };
108106#else
109107#define INVALID_FD (-1)
110- static volatile sig_atomic_t wakeup_fd = -1 ;
108+ static volatile struct {
109+ sig_atomic_t fd ;
110+ int warn_on_full_buffer ;
111+ } wakeup = {.fd = INVALID_FD , .warn_on_full_buffer = 1 };
111112#endif
112113
113114/* Speed up sigcheck() when none tripped */
@@ -210,28 +211,15 @@ report_wakeup_write_error(void *data)
210211
211212#ifdef MS_WINDOWS
212213static int
213- report_wakeup_send_error (void * Py_UNUSED ( data ) )
214+ report_wakeup_send_error (void * data )
214215{
215- PyObject * res ;
216-
217- if (wakeup .send_win_error ) {
218- /* PyErr_SetExcFromWindowsErr() invokes FormatMessage() which
219- recognizes the error codes used by both GetLastError() and
220- WSAGetLastError */
221- res = PyErr_SetExcFromWindowsErr (PyExc_OSError , wakeup .send_win_error );
222- }
223- else {
224- errno = wakeup .send_errno ;
225- res = PyErr_SetFromErrno (PyExc_OSError );
226- }
227-
228- assert (res == NULL );
229- wakeup .send_err_set = 0 ;
230-
216+ /* PyErr_SetExcFromWindowsErr() invokes FormatMessage() which
217+ recognizes the error codes used by both GetLastError() and
218+ WSAGetLastError */
219+ PyErr_SetExcFromWindowsErr (PyExc_OSError , (int ) (intptr_t ) data );
231220 PySys_WriteStderr ("Exception ignored when trying to send to the "
232221 "signal wakeup fd:\n" );
233222 PyErr_WriteUnraisable (NULL );
234-
235223 return 0 ;
236224}
237225#endif /* MS_WINDOWS */
@@ -257,7 +245,7 @@ trip_signal(int sig_num)
257245 and then set the flag, but this allowed the following sequence of events
258246 (especially on windows, where trip_signal may run in a new thread):
259247
260- - main thread blocks on select([wakeup_fd ], ...)
248+ - main thread blocks on select([wakeup.fd ], ...)
261249 - signal arrives
262250 - trip_signal writes to the wakeup fd
263251 - the main thread wakes up
@@ -274,41 +262,43 @@ trip_signal(int sig_num)
274262#ifdef MS_WINDOWS
275263 fd = Py_SAFE_DOWNCAST (wakeup .fd , SOCKET_T , int );
276264#else
277- fd = wakeup_fd ;
265+ fd = wakeup . fd ;
278266#endif
279267
280268 if (fd != INVALID_FD ) {
281269 byte = (unsigned char )sig_num ;
282270#ifdef MS_WINDOWS
283271 if (wakeup .use_send ) {
284- do {
285- rc = send ( fd , & byte , 1 , 0 );
286- } while (rc < 0 && errno == EINTR );
287-
288- /* we only have a storage for one error in the wakeup structure */
289- if ( rc < 0 && ! wakeup . send_err_set ) {
290- wakeup . send_err_set = 1 ;
291- wakeup . send_errno = errno ;
292- wakeup . send_win_error = GetLastError ();
293- /* Py_AddPendingCall() isn't signal-safe, but we
294- still use it for this exceptional case. */
295- Py_AddPendingCall ( report_wakeup_send_error , NULL );
272+ rc = send ( fd , & byte , 1 , 0 );
273+
274+ if (rc < 0 ) {
275+ int last_error = GetLastError ();
276+ if ( wakeup . warn_on_full_buffer ||
277+ last_error != WSAEWOULDBLOCK )
278+ {
279+ /* Py_AddPendingCall() isn't signal-safe, but we
280+ still use it for this exceptional case. */
281+ Py_AddPendingCall ( report_wakeup_send_error ,
282+ ( void * )( intptr_t ) last_error );
283+ }
296284 }
297285 }
298286 else
299287#endif
300288 {
301- byte = (unsigned char )sig_num ;
302-
303289 /* _Py_write_noraise() retries write() if write() is interrupted by
304290 a signal (fails with EINTR). */
305291 rc = _Py_write_noraise (fd , & byte , 1 );
306292
307293 if (rc < 0 ) {
308- /* Py_AddPendingCall() isn't signal-safe, but we
309- still use it for this exceptional case. */
310- Py_AddPendingCall (report_wakeup_write_error ,
311- (void * )(intptr_t )errno );
294+ if (wakeup .warn_on_full_buffer ||
295+ (errno != EWOULDBLOCK && errno != EAGAIN ))
296+ {
297+ /* Py_AddPendingCall() isn't signal-safe, but we
298+ still use it for this exceptional case. */
299+ Py_AddPendingCall (report_wakeup_write_error ,
300+ (void * )(intptr_t )errno );
301+ }
312302 }
313303 }
314304 }
@@ -549,9 +539,13 @@ signal_siginterrupt_impl(PyObject *module, int signalnum, int flag)
549539
550540
551541static PyObject *
552- signal_set_wakeup_fd (PyObject * self , PyObject * args )
542+ signal_set_wakeup_fd (PyObject * self , PyObject * args , PyObject * kwds )
553543{
554544 struct _Py_stat_struct status ;
545+ static char * kwlist [] = {
546+ "" , "warn_on_full_buffer" , NULL ,
547+ };
548+ int warn_on_full_buffer = 1 ;
555549#ifdef MS_WINDOWS
556550 PyObject * fdobj ;
557551 SOCKET_T sockfd , old_sockfd ;
@@ -560,7 +554,8 @@ signal_set_wakeup_fd(PyObject *self, PyObject *args)
560554 PyObject * mod ;
561555 int is_socket ;
562556
563- if (!PyArg_ParseTuple (args , "O:set_wakeup_fd" , & fdobj ))
557+ if (!PyArg_ParseTupleAndKeywords (args , kwds , "O|$p:set_wakeup_fd" , kwlist ,
558+ & fdobj , & warn_on_full_buffer ))
564559 return NULL ;
565560
566561 sockfd = PyLong_AsSocket_t (fdobj );
@@ -569,7 +564,8 @@ signal_set_wakeup_fd(PyObject *self, PyObject *args)
569564#else
570565 int fd , old_fd ;
571566
572- if (!PyArg_ParseTuple (args , "i:set_wakeup_fd" , & fd ))
567+ if (!PyArg_ParseTupleAndKeywords (args , kwds , "i|$p:set_wakeup_fd" , kwlist ,
568+ & fd , & warn_on_full_buffer ))
573569 return NULL ;
574570#endif
575571
@@ -620,6 +616,7 @@ signal_set_wakeup_fd(PyObject *self, PyObject *args)
620616
621617 old_sockfd = wakeup .fd ;
622618 wakeup .fd = sockfd ;
619+ wakeup .warn_on_full_buffer = warn_on_full_buffer ;
623620 wakeup .use_send = is_socket ;
624621
625622 if (old_sockfd != INVALID_FD )
@@ -644,15 +641,16 @@ signal_set_wakeup_fd(PyObject *self, PyObject *args)
644641 }
645642 }
646643
647- old_fd = wakeup_fd ;
648- wakeup_fd = fd ;
644+ old_fd = wakeup .fd ;
645+ wakeup .fd = fd ;
646+ wakeup .warn_on_full_buffer = warn_on_full_buffer ;
649647
650648 return PyLong_FromLong (old_fd );
651649#endif
652650}
653651
654652PyDoc_STRVAR (set_wakeup_fd_doc ,
655- "set_wakeup_fd(fd) -> fd\n\
653+ "set_wakeup_fd(fd, *, warn_on_full_buffer=True ) -> fd\n\
656654\n\
657655Sets the fd to be written to (with the signal number) when a signal\n\
658656comes in. A library can use this to wakeup select or poll.\n\
@@ -670,11 +668,11 @@ PySignal_SetWakeupFd(int fd)
670668
671669#ifdef MS_WINDOWS
672670 old_fd = Py_SAFE_DOWNCAST (wakeup .fd , SOCKET_T , int );
673- wakeup .fd = fd ;
674671#else
675- old_fd = wakeup_fd ;
676- wakeup_fd = fd ;
672+ old_fd = wakeup .fd ;
677673#endif
674+ wakeup .fd = fd ;
675+ wakeup .warn_on_full_buffer = 1 ;
678676 return old_fd ;
679677}
680678
@@ -1155,7 +1153,7 @@ static PyMethodDef signal_methods[] = {
11551153 SIGNAL_GETITIMER_METHODDEF
11561154 SIGNAL_SIGNAL_METHODDEF
11571155 SIGNAL_GETSIGNAL_METHODDEF
1158- {"set_wakeup_fd" , signal_set_wakeup_fd , METH_VARARGS , set_wakeup_fd_doc },
1156+ {"set_wakeup_fd" , ( PyCFunction ) signal_set_wakeup_fd , METH_VARARGS | METH_KEYWORDS , set_wakeup_fd_doc },
11591157 SIGNAL_SIGINTERRUPT_METHODDEF
11601158 SIGNAL_PAUSE_METHODDEF
11611159 SIGNAL_PTHREAD_KILL_METHODDEF
0 commit comments