1919#include "pycore_object.h" // _PyDebug_PrintTotalRefs()
2020#include "pycore_obmalloc.h" // _PyMem_init_obmalloc()
2121#include "pycore_optimizer.h" // _Py_Executors_InvalidateAll
22+ #include "pycore_parking_lot.h" // _PyParkingLot
2223#include "pycore_pathconfig.h" // _PyPathConfig_UpdateGlobal()
2324#include "pycore_pyerrors.h" // _PyErr_Occurred()
2425#include "pycore_pylifecycle.h" // _PyErr_Print()
@@ -2314,7 +2315,39 @@ make_pre_finalization_calls(PyThreadState *tstate, int subinterpreters)
23142315 finalize_subinterpreters ();
23152316 }
23162317
2318+ // This is used as a throttle to prevent constant spinning while
2319+ // on finalization guards.
2320+ for (;;) {
2321+ uintptr_t num_guards = _Py_atomic_load_uintptr (& interp -> finalization_guards );
2322+ if (num_guards == 0 ) {
2323+ break ;
2324+ }
23172325
2326+ int ret = _PyParkingLot_Park (& interp -> finalization_guards ,
2327+ & num_guards , sizeof (num_guards ), -1 ,
2328+ NULL , /*detach=*/ 1 );
2329+ if (ret == Py_PARK_OK ) {
2330+ break ;
2331+ }
2332+ else if (ret == Py_PARK_INTR ) {
2333+ if (PyErr_CheckSignals () < 0 ) {
2334+ int fatal = PyErr_ExceptionMatches (PyExc_KeyboardInterrupt );
2335+ PyErr_FormatUnraisable ("Exception ignored while waiting on finalization guards" );
2336+ if (fatal ) {
2337+ fputs ("Interrupted while waiting on finalization guards" , stderr );
2338+ exit (1 );
2339+ }
2340+ }
2341+ assert (!PyErr_Occurred ());
2342+ }
2343+ else if (ret == Py_PARK_AGAIN ) {
2344+ continue ;
2345+ }
2346+ else {
2347+ assert (ret == Py_PARK_TIMEOUT );
2348+ Py_UNREACHABLE ();
2349+ }
2350+ }
23182351
23192352 /* Stop the world to prevent other threads from creating threads or
23202353 * atexit callbacks. On the default build, this is simply locked by
@@ -2329,13 +2362,13 @@ make_pre_finalization_calls(PyThreadState *tstate, int subinterpreters)
23292362 int has_subinterpreters = subinterpreters
23302363 ? runtime_has_subinterpreters (interp -> runtime )
23312364 : 0 ;
2332- uintptr_t finalization_guards_expected = 0 ;
2365+ uintptr_t guards_expected = 0 ;
23332366 int should_continue = (interp_has_threads (interp )
23342367 || interp_has_atexit_callbacks (interp )
23352368 || interp_has_pending_calls (interp )
23362369 || has_subinterpreters
23372370 || _Py_atomic_compare_exchange_uintptr (& interp -> finalization_guards ,
2338- & finalization_guards_expected ,
2371+ & guards_expected ,
23392372 _PyInterpreterGuard_GUARDS_NOT_ALLOWED ) == 0 );
23402373 if (!should_continue ) {
23412374 break ;
0 commit comments