@@ -100,6 +100,7 @@ static long dxp[256];
100
100
_Py_atomic_store_relaxed( \
101
101
&_PyRuntime.ceval.eval_breaker, \
102
102
GIL_REQUEST | \
103
+ _Py_atomic_load_relaxed(&_PyRuntime.ceval.signals_pending) | \
103
104
_Py_atomic_load_relaxed(&_PyRuntime.ceval.pending.calls_to_do) | \
104
105
_PyRuntime.ceval.pending.async_exc)
105
106
@@ -128,6 +129,18 @@ static long dxp[256];
128
129
COMPUTE_EVAL_BREAKER(); \
129
130
} while (0)
130
131
132
+ #define SIGNAL_PENDING_SIGNALS () \
133
+ do { \
134
+ _Py_atomic_store_relaxed(&_PyRuntime.ceval.signals_pending, 1); \
135
+ _Py_atomic_store_relaxed(&_PyRuntime.ceval.eval_breaker, 1); \
136
+ } while (0)
137
+
138
+ #define UNSIGNAL_PENDING_SIGNALS () \
139
+ do { \
140
+ _Py_atomic_store_relaxed(&_PyRuntime.ceval.signals_pending, 0); \
141
+ COMPUTE_EVAL_BREAKER(); \
142
+ } while (0)
143
+
131
144
#define SIGNAL_ASYNC_EXC () \
132
145
do { \
133
146
_PyRuntime.ceval.pending.async_exc = 1; \
@@ -306,7 +319,7 @@ _PyEval_SignalReceived(void)
306
319
/* bpo-30703: Function called when the C signal handler of Python gets a
307
320
signal. We cannot queue a callback using Py_AddPendingCall() since
308
321
that function is not async-signal-safe. */
309
- SIGNAL_PENDING_CALLS ();
322
+ SIGNAL_PENDING_SIGNALS ();
310
323
}
311
324
312
325
/* This implementation is thread-safe. It allows
@@ -356,44 +369,57 @@ Py_AddPendingCall(int (*func)(void *), void *arg)
356
369
return result ;
357
370
}
358
371
359
- int
360
- Py_MakePendingCalls (void )
372
+ static int
373
+ handle_signals (void )
361
374
{
362
- static int busy = 0 ;
363
- int i ;
364
- int r = 0 ;
365
-
366
- assert (PyGILState_Check ());
375
+ /* Only handle signals on main thread. */
376
+ if (_PyRuntime .ceval .pending .main_thread &&
377
+ PyThread_get_thread_ident () != _PyRuntime .ceval .pending .main_thread )
378
+ {
379
+ return 0 ;
380
+ }
367
381
368
- if (!_PyRuntime .ceval .pending .lock ) {
369
- /* initial allocation of the lock */
370
- _PyRuntime .ceval .pending .lock = PyThread_allocate_lock ();
371
- if (_PyRuntime .ceval .pending .lock == NULL )
372
- return -1 ;
382
+ UNSIGNAL_PENDING_SIGNALS ();
383
+ if (PyErr_CheckSignals () < 0 ) {
384
+ SIGNAL_PENDING_SIGNALS (); /* We're not done yet */
385
+ return -1 ;
373
386
}
387
+ return 0 ;
388
+ }
389
+
390
+ static int
391
+ make_pending_calls (void )
392
+ {
393
+ static int busy = 0 ;
374
394
375
395
/* only service pending calls on main thread */
376
396
if (_PyRuntime .ceval .pending .main_thread &&
377
397
PyThread_get_thread_ident () != _PyRuntime .ceval .pending .main_thread )
378
398
{
379
399
return 0 ;
380
400
}
401
+
381
402
/* don't perform recursive pending calls */
382
- if (busy )
403
+ if (busy ) {
383
404
return 0 ;
405
+ }
384
406
busy = 1 ;
385
407
/* unsignal before starting to call callbacks, so that any callback
386
408
added in-between re-signals */
387
409
UNSIGNAL_PENDING_CALLS ();
410
+ int res = 0 ;
388
411
389
- /* Python signal handler doesn't really queue a callback: it only signals
390
- that a signal was received, see _PyEval_SignalReceived(). */
391
- if (PyErr_CheckSignals () < 0 ) {
392
- goto error ;
412
+ if (!_PyRuntime .ceval .pending .lock ) {
413
+ /* initial allocation of the lock */
414
+ _PyRuntime .ceval .pending .lock = PyThread_allocate_lock ();
415
+ if (_PyRuntime .ceval .pending .lock == NULL ) {
416
+ res = -1 ;
417
+ goto error ;
418
+ }
393
419
}
394
420
395
421
/* perform a bounded number of calls, in case of recursion */
396
- for (i = 0 ; i < NPENDINGCALLS ; i ++ ) {
422
+ for (int i = 0 ; i < NPENDINGCALLS ; i ++ ) {
397
423
int j ;
398
424
int (* func )(void * );
399
425
void * arg = NULL ;
@@ -412,19 +438,41 @@ Py_MakePendingCalls(void)
412
438
/* having released the lock, perform the callback */
413
439
if (func == NULL )
414
440
break ;
415
- r = func (arg );
416
- if (r ) {
441
+ res = func (arg );
442
+ if (res ) {
417
443
goto error ;
418
444
}
419
445
}
420
446
421
447
busy = 0 ;
422
- return r ;
448
+ return res ;
423
449
424
450
error :
425
451
busy = 0 ;
426
- SIGNAL_PENDING_CALLS (); /* We're not done yet */
427
- return -1 ;
452
+ SIGNAL_PENDING_CALLS ();
453
+ return res ;
454
+ }
455
+
456
+ /* Py_MakePendingCalls() is a simple wrapper for the sake
457
+ of backward-compatibility. */
458
+ int
459
+ Py_MakePendingCalls (void )
460
+ {
461
+ assert (PyGILState_Check ());
462
+
463
+ /* Python signal handler doesn't really queue a callback: it only signals
464
+ that a signal was received, see _PyEval_SignalReceived(). */
465
+ int res = handle_signals ();
466
+ if (res != 0 ) {
467
+ return res ;
468
+ }
469
+
470
+ res = make_pending_calls ();
471
+ if (res != 0 ) {
472
+ return res ;
473
+ }
474
+
475
+ return 0 ;
428
476
}
429
477
430
478
/* The interpreter's recursion limit */
@@ -957,12 +1005,22 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
957
1005
*/
958
1006
goto fast_next_opcode ;
959
1007
}
1008
+
1009
+ if (_Py_atomic_load_relaxed (
1010
+ & _PyRuntime .ceval .signals_pending ))
1011
+ {
1012
+ if (handle_signals () != 0 ) {
1013
+ goto error ;
1014
+ }
1015
+ }
960
1016
if (_Py_atomic_load_relaxed (
961
1017
& _PyRuntime .ceval .pending .calls_to_do ))
962
1018
{
963
- if (Py_MakePendingCalls () < 0 )
1019
+ if (make_pending_calls () != 0 ) {
964
1020
goto error ;
1021
+ }
965
1022
}
1023
+
966
1024
if (_Py_atomic_load_relaxed (
967
1025
& _PyRuntime .ceval .gil_drop_request ))
968
1026
{
0 commit comments