@@ -2314,37 +2314,6 @@ make_pre_finalization_calls(PyThreadState *tstate, int subinterpreters)
23142314 finalize_subinterpreters ();
23152315 }
23162316
2317- /* Wait on finalization guards.
2318- *
2319- * To avoid eating CPU cycles, we use an event to signal when we reach
2320- * zero remaining guards. But, this isn't atomic! This event can be reset
2321- * later if another thread creates a new finalization guard. The actual
2322- * atomic check is made below, when we hold the finalization guard lock.
2323- * Again, this is purely an optimization to avoid overloading the CPU.
2324- */
2325- for (;;) {
2326- if (_Py_atomic_load_ssize_relaxed (& interp -> finalization_guards .countdown ) == 0 ) {
2327- break ;
2328- }
2329-
2330- PyTime_t wait_ns = 1000 * 1000 ; // 1ms
2331- if (PyEvent_WaitTimed (& interp -> finalization_guards .done , wait_ns , /*detach=*/ 1 )) {
2332- break ;
2333- }
2334-
2335- // For debugging purposes, we emit a fatal error if someone
2336- // CTRL^C'ed the process.
2337- if (PyErr_CheckSignals ()) {
2338- int fatal = PyErr_ExceptionMatches (PyExc_KeyboardInterrupt );
2339- PyErr_FormatUnraisable ("Exception ignored while waiting on finalization guards" );
2340-
2341- if (fatal ) {
2342- fputs ("Interrupted while waiting on finalization guard" , stderr );
2343- exit (1 );
2344- }
2345- }
2346- }
2347-
23482317 /* Stop the world to prevent other threads from creating threads or
23492318 * atexit callbacks. On the default build, this is simply locked by
23502319 * the GIL. For pending calls, we acquire the dedicated mutex, because
@@ -2355,27 +2324,28 @@ make_pre_finalization_calls(PyThreadState *tstate, int subinterpreters)
23552324 // XXX Why does _PyThreadState_DeleteList() rely on all interpreters
23562325 // being stopped?
23572326 _PyEval_StopTheWorldAll (interp -> runtime );
2358- _PyRWMutex_Lock (& interp -> finalization_guards .lock );
23592327 int has_subinterpreters = subinterpreters
23602328 ? runtime_has_subinterpreters (interp -> runtime )
23612329 : 0 ;
2330+ uintptr_t finalization_guards_expected = 0 ;
23622331 int should_continue = (interp_has_threads (interp )
23632332 || interp_has_atexit_callbacks (interp )
23642333 || interp_has_pending_calls (interp )
23652334 || has_subinterpreters
2366- || _Py_atomic_load_ssize_acquire (& interp -> finalization_guards .countdown ) > 0 );
2335+ || _Py_atomic_compare_exchange_uintptr (& interp -> finalization_guards ,
2336+ & finalization_guards_expected ,
2337+ _PyInterpreterGuard_GUARDS_NOT_ALLOWED ) == 0 );
23672338 if (!should_continue ) {
23682339 break ;
23692340 }
23702341 // Temporarily let other threads execute
23712342 _PyThreadState_Detach (tstate );
2372- _PyRWMutex_Unlock (& interp -> finalization_guards .lock );
23732343 _PyEval_StartTheWorldAll (interp -> runtime );
23742344 PyMutex_Unlock (& interp -> ceval .pending .mutex );
23752345 _PyThreadState_Attach (tstate );
23762346 }
23772347 assert (PyMutex_IsLocked (& interp -> ceval .pending .mutex ));
2378- assert (_Py_atomic_load_ssize (& interp -> finalization_guards . countdown ) == 0 );
2348+ assert (_Py_atomic_load_uintptr (& interp -> finalization_guards ) == _PyInterpreterGuard_GUARDS_NOT_ALLOWED );
23792349 ASSERT_WORLD_STOPPED (interp );
23802350}
23812351
@@ -2434,7 +2404,6 @@ _Py_Finalize(_PyRuntimeState *runtime)
24342404 for (PyThreadState * p = list ; p != NULL ; p = p -> next ) {
24352405 _PyThreadState_SetShuttingDown (p );
24362406 }
2437- _PyRWMutex_Unlock (& tstate -> interp -> finalization_guards .lock );
24382407 _PyEval_StartTheWorldAll (runtime );
24392408 PyMutex_Unlock (& tstate -> interp -> ceval .pending .mutex );
24402409
@@ -2817,7 +2786,6 @@ Py_EndInterpreter(PyThreadState *tstate)
28172786 _PyThreadState_SetShuttingDown (p );
28182787 }
28192788
2820- _PyRWMutex_Unlock (& interp -> finalization_guards .lock );
28212789 _PyEval_StartTheWorldAll (interp -> runtime );
28222790 PyMutex_Unlock (& interp -> ceval .pending .mutex );
28232791 _PyThreadState_DeleteList (list , /*is_after_fork=*/ 0 );
0 commit comments