@@ -27,8 +27,6 @@ from cpython cimport PyObject_GetBuffer, PyBuffer_Release, PyBUF_SIMPLE, \
27
27
Py_buffer, PyBytes_AsString, PyBytes_CheckExact, \
28
28
Py_SIZE, PyBytes_AS_STRING
29
29
30
- from cpython cimport PyErr_CheckSignals
31
-
32
30
from . import _noop
33
31
34
32
@@ -149,6 +147,7 @@ cdef class Loop:
149
147
self , " loop._exec_queued_writes" ,
150
148
< method_t> self ._exec_queued_writes, self ))
151
149
150
+ self ._signals = set ()
152
151
self ._ssock = self ._csock = None
153
152
self ._signal_handlers = {}
154
153
self ._listening_signals = False
@@ -234,7 +233,7 @@ cdef class Loop:
234
233
self ._ssock.setblocking(False )
235
234
self ._csock.setblocking(False )
236
235
try :
237
- signal_set_wakeup_fd (self ._csock.fileno())
236
+ _set_signal_wakeup_fd (self ._csock.fileno())
238
237
except (OSError , ValueError ):
239
238
# Not the main thread
240
239
self ._ssock.close()
@@ -290,23 +289,54 @@ cdef class Loop:
290
289
291
290
self ._listening_signals = False
292
291
292
+ def __sighandler (self , signum , frame ):
293
+ self ._signals.add(signum)
294
+
295
+ cdef inline _ceval_process_signals(self ):
296
+ # Invoke CPython eval loop to let process signals.
297
+ PyErr_CheckSignals()
298
+ # Calling a pure-Python function will invoke
299
+ # _PyEval_EvalFrameDefault which will process
300
+ # pending signal callbacks.
301
+ _noop.noop() # Might raise ^C
302
+
293
303
cdef _read_from_self(self ):
304
+ cdef bytes sigdata
305
+ sigdata = b' '
294
306
while True :
295
307
try :
296
- data = self ._ssock.recv(4096 )
308
+ data = self ._ssock.recv(65536 )
297
309
if not data:
298
310
break
299
- self ._process_self_data( data)
311
+ sigdata += data
300
312
except InterruptedError:
301
313
continue
302
314
except BlockingIOError:
303
315
break
316
+ if sigdata:
317
+ self ._invoke_signals(sigdata)
318
+
319
+ cdef _invoke_signals(self , bytes data):
320
+ cdef set sigs
321
+
322
+ self ._ceval_process_signals()
304
323
305
- cdef _process_self_data(self , data):
324
+ sigs = self ._signals.copy()
325
+ self ._signals.clear()
306
326
for signum in data:
307
327
if not signum:
308
- # ignore null bytes written by _write_to_self ()
328
+ # ignore null bytes written by set_wakeup_fd ()
309
329
continue
330
+ sigs.discard(signum)
331
+ self ._handle_signal(signum)
332
+
333
+ for signum in sigs:
334
+ # Since not all signals are registered by add_signal_handler()
335
+ # (for instance, we use the default SIGINT handler) not all
336
+ # signals will trigger loop.__sighandler() callback. Therefore
337
+ # we combine two datasources: one is self-pipe, one is data
338
+ # from __sighandler; this ensures that signals shouldn't be
339
+ # lost even if set_wakeup_fd() couldn't write to the self-pipe.
310
340
self ._handle_signal(signum)
311
341
312
342
cdef _handle_signal(self , sig):
@@ -318,11 +348,7 @@ cdef class Loop:
318
348
handle = None
319
349
320
350
if handle is None :
321
- # Some signal that we aren't listening through
322
- # add_signal_handler. Invoke CPython eval loop
323
- # to let it being processed.
324
- PyErr_CheckSignals()
325
- _noop.noop()
351
+ self ._ceval_process_signals()
326
352
return
327
353
328
354
if handle._cancelled:
@@ -2516,13 +2542,12 @@ cdef class Loop:
2516
2542
2517
2543
self ._check_signal(sig)
2518
2544
self ._check_closed()
2519
-
2520
2545
try :
2521
2546
# set_wakeup_fd() raises ValueError if this is not the
2522
2547
# main thread. By calling it early we ensure that an
2523
2548
# event loop running in another thread cannot add a signal
2524
2549
# handler.
2525
- signal_set_wakeup_fd (self ._csock.fileno())
2550
+ _set_signal_wakeup_fd (self ._csock.fileno())
2526
2551
except (ValueError , OSError ) as exc:
2527
2552
raise RuntimeError (str (exc))
2528
2553
@@ -2532,7 +2557,7 @@ cdef class Loop:
2532
2557
try :
2533
2558
# Register a dummy signal handler to ask Python to write the signal
2534
2559
# number in the wakeup file descriptor.
2535
- signal_signal(sig, _sighandler_noop )
2560
+ signal_signal(sig, self .__sighandler )
2536
2561
2537
2562
# Set SA_RESTART to limit EINTR occurrences.
2538
2563
signal_siginterrupt(sig, False )
@@ -2867,9 +2892,11 @@ cdef __install_pymem():
2867
2892
raise convert_error(err)
2868
2893
2869
2894
2870
- def _sighandler_noop (signum , frame ):
2871
- """ Dummy signal handler."""
2872
- pass
2895
+ cdef _set_signal_wakeup_fd(fd):
2896
+ if sys_version_info >= (3 , 7 , 0 ) and fd >= 0 :
2897
+ signal_set_wakeup_fd(fd, warn_on_full_buffer = False )
2898
+ else :
2899
+ signal_set_wakeup_fd(fd)
2873
2900
2874
2901
2875
2902
# ########## Stuff for tests:
0 commit comments