@@ -330,31 +330,33 @@ _PyEval_SignalReceived(void)
330
330
331
331
/* Push one item onto the queue while holding the lock. */
332
332
static int
333
- _push_pending_call (int (* func )(void * ), void * arg )
333
+ _push_pending_call (struct _pending_calls * pending ,
334
+ int (* func )(void * ), void * arg )
334
335
{
335
- int i = _PyRuntime . ceval . pending . last ;
336
+ int i = pending -> last ;
336
337
int j = (i + 1 ) % NPENDINGCALLS ;
337
- if (j == _PyRuntime . ceval . pending . first ) {
338
+ if (j == pending -> first ) {
338
339
return -1 ; /* Queue full */
339
340
}
340
- _PyRuntime . ceval . pending . calls [i ].func = func ;
341
- _PyRuntime . ceval . pending . calls [i ].arg = arg ;
342
- _PyRuntime . ceval . pending . last = j ;
341
+ pending -> calls [i ].func = func ;
342
+ pending -> calls [i ].arg = arg ;
343
+ pending -> last = j ;
343
344
return 0 ;
344
345
}
345
346
346
347
/* Pop one item off the queue while holding the lock. */
347
348
static void
348
- _pop_pending_call (int (* * func )(void * ), void * * arg )
349
+ _pop_pending_call (struct _pending_calls * pending ,
350
+ int (* * func )(void * ), void * * arg )
349
351
{
350
- int i = _PyRuntime . ceval . pending . first ;
351
- if (i == _PyRuntime . ceval . pending . last ) {
352
+ int i = pending -> first ;
353
+ if (i == pending -> last ) {
352
354
return ; /* Queue empty */
353
355
}
354
356
355
- * func = _PyRuntime . ceval . pending . calls [i ].func ;
356
- * arg = _PyRuntime . ceval . pending . calls [i ].arg ;
357
- _PyRuntime . ceval . pending . first = (i + 1 ) % NPENDINGCALLS ;
357
+ * func = pending -> calls [i ].func ;
358
+ * arg = pending -> calls [i ].arg ;
359
+ pending -> first = (i + 1 ) % NPENDINGCALLS ;
358
360
}
359
361
360
362
/* This implementation is thread-safe. It allows
@@ -365,9 +367,23 @@ _pop_pending_call(int (**func)(void *), void **arg)
365
367
int
366
368
Py_AddPendingCall (int (* func )(void * ), void * arg )
367
369
{
368
- PyThread_acquire_lock (_PyRuntime .ceval .pending .lock , WAIT_LOCK );
369
- int result = _push_pending_call (func , arg );
370
- PyThread_release_lock (_PyRuntime .ceval .pending .lock );
370
+ struct _pending_calls * pending = & _PyRuntime .ceval .pending ;
371
+
372
+ PyThread_acquire_lock (pending -> lock , WAIT_LOCK );
373
+ if (pending -> finishing ) {
374
+ PyThread_release_lock (pending -> lock );
375
+
376
+ PyObject * exc , * val , * tb ;
377
+ PyErr_Fetch (& exc , & val , & tb );
378
+ PyErr_SetString (PyExc_SystemError ,
379
+ "Py_AddPendingCall: cannot add pending calls "
380
+ "(Python shutting down)" );
381
+ PyErr_Print ();
382
+ PyErr_Restore (exc , val , tb );
383
+ return -1 ;
384
+ }
385
+ int result = _push_pending_call (pending , func , arg );
386
+ PyThread_release_lock (pending -> lock );
371
387
372
388
/* signal main loop */
373
389
SIGNAL_PENDING_CALLS ();
@@ -400,7 +416,7 @@ handle_signals(void)
400
416
}
401
417
402
418
static int
403
- make_pending_calls (void )
419
+ make_pending_calls (struct _pending_calls * pending )
404
420
{
405
421
static int busy = 0 ;
406
422
@@ -425,9 +441,9 @@ make_pending_calls(void)
425
441
void * arg = NULL ;
426
442
427
443
/* pop one item off the queue while holding the lock */
428
- PyThread_acquire_lock (_PyRuntime . ceval . pending . lock , WAIT_LOCK );
429
- _pop_pending_call (& func , & arg );
430
- PyThread_release_lock (_PyRuntime . ceval . pending . lock );
444
+ PyThread_acquire_lock (pending -> lock , WAIT_LOCK );
445
+ _pop_pending_call (pending , & func , & arg );
446
+ PyThread_release_lock (pending -> lock );
431
447
432
448
/* having released the lock, perform the callback */
433
449
if (func == NULL ) {
@@ -448,6 +464,30 @@ make_pending_calls(void)
448
464
return res ;
449
465
}
450
466
467
+ void
468
+ _Py_FinishPendingCalls (void )
469
+ {
470
+ struct _pending_calls * pending = & _PyRuntime .ceval .pending ;
471
+
472
+ assert (PyGILState_Check ());
473
+
474
+ PyThread_acquire_lock (pending -> lock , WAIT_LOCK );
475
+ pending -> finishing = 1 ;
476
+ PyThread_release_lock (pending -> lock );
477
+
478
+ if (!_Py_atomic_load_relaxed (& (pending -> calls_to_do ))) {
479
+ return ;
480
+ }
481
+
482
+ if (make_pending_calls (pending ) < 0 ) {
483
+ PyObject * exc , * val , * tb ;
484
+ PyErr_Fetch (& exc , & val , & tb );
485
+ PyErr_BadInternalCall ();
486
+ _PyErr_ChainExceptions (exc , val , tb );
487
+ PyErr_Print ();
488
+ }
489
+ }
490
+
451
491
/* Py_MakePendingCalls() is a simple wrapper for the sake
452
492
of backward-compatibility. */
453
493
int
@@ -462,7 +502,7 @@ Py_MakePendingCalls(void)
462
502
return res ;
463
503
}
464
504
465
- res = make_pending_calls ();
505
+ res = make_pending_calls (& _PyRuntime . ceval . pending );
466
506
if (res != 0 ) {
467
507
return res ;
468
508
}
@@ -1012,7 +1052,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
1012
1052
if (_Py_atomic_load_relaxed (
1013
1053
& _PyRuntime .ceval .pending .calls_to_do ))
1014
1054
{
1015
- if (make_pending_calls () != 0 ) {
1055
+ if (make_pending_calls (& _PyRuntime . ceval . pending ) != 0 ) {
1016
1056
goto error ;
1017
1057
}
1018
1058
}
0 commit comments