@@ -330,31 +330,33 @@ _PyEval_SignalReceived(void)
330330
331331/* Push one item onto the queue while holding the lock. */
332332static int
333- _push_pending_call (int (* func )(void * ), void * arg )
333+ _push_pending_call (struct _pending_calls * pending ,
334+ int (* func )(void * ), void * arg )
334335{
335- int i = _PyRuntime . ceval . pending . last ;
336+ int i = pending -> last ;
336337 int j = (i + 1 ) % NPENDINGCALLS ;
337- if (j == _PyRuntime . ceval . pending . first ) {
338+ if (j == pending -> first ) {
338339 return -1 ; /* Queue full */
339340 }
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 ;
343344 return 0 ;
344345}
345346
346347/* Pop one item off the queue while holding the lock. */
347348static void
348- _pop_pending_call (int (* * func )(void * ), void * * arg )
349+ _pop_pending_call (struct _pending_calls * pending ,
350+ int (* * func )(void * ), void * * arg )
349351{
350- int i = _PyRuntime . ceval . pending . first ;
351- if (i == _PyRuntime . ceval . pending . last ) {
352+ int i = pending -> first ;
353+ if (i == pending -> last ) {
352354 return ; /* Queue empty */
353355 }
354356
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 ;
358360}
359361
360362/* This implementation is thread-safe. It allows
@@ -365,9 +367,23 @@ _pop_pending_call(int (**func)(void *), void **arg)
365367int
366368Py_AddPendingCall (int (* func )(void * ), void * arg )
367369{
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 );
371387
372388 /* signal main loop */
373389 SIGNAL_PENDING_CALLS ();
@@ -400,7 +416,7 @@ handle_signals(void)
400416}
401417
402418static int
403- make_pending_calls (void )
419+ make_pending_calls (struct _pending_calls * pending )
404420{
405421 static int busy = 0 ;
406422
@@ -425,9 +441,9 @@ make_pending_calls(void)
425441 void * arg = NULL ;
426442
427443 /* 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 );
431447
432448 /* having released the lock, perform the callback */
433449 if (func == NULL ) {
@@ -448,6 +464,30 @@ make_pending_calls(void)
448464 return res ;
449465}
450466
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+
451491/* Py_MakePendingCalls() is a simple wrapper for the sake
452492 of backward-compatibility. */
453493int
@@ -462,7 +502,7 @@ Py_MakePendingCalls(void)
462502 return res ;
463503 }
464504
465- res = make_pending_calls ();
505+ res = make_pending_calls (& _PyRuntime . ceval . pending );
466506 if (res != 0 ) {
467507 return res ;
468508 }
@@ -1012,7 +1052,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
10121052 if (_Py_atomic_load_relaxed (
10131053 & _PyRuntime .ceval .pending .calls_to_do ))
10141054 {
1015- if (make_pending_calls () != 0 ) {
1055+ if (make_pending_calls (& _PyRuntime . ceval . pending ) != 0 ) {
10161056 goto error ;
10171057 }
10181058 }
0 commit comments