@@ -1455,6 +1455,15 @@ free_threadstate(_PyThreadStateImpl *tstate)
14551455    }
14561456}
14571457
1458+ static  void 
1459+ decref_threadstate (_PyThreadStateImpl  * tstate )
1460+ {
1461+     if  (_Py_atomic_add_ssize (& tstate -> refcount , -1 ) ==  1 ) {
1462+         // The last reference to the thread state is gone. 
1463+         free_threadstate (tstate );
1464+     }
1465+ }
1466+ 
14581467/* Get the thread state to a minimal consistent state. 
14591468   Further init happens in pylifecycle.c before it can be used. 
14601469   All fields not initialized here are expected to be zeroed out, 
@@ -1919,8 +1928,12 @@ _PyThreadState_RemoveExcept(PyThreadState *tstate)
19191928// Deletes the thread states in the linked list `list`. 
19201929// 
19211930// This is intended to be used in conjunction with _PyThreadState_RemoveExcept. 
1931+ // 
1932+ // If `is_after_fork` is true, the thread states are immediately freed. 
1933+ // Otherwise, they are decref'd because they may still be referenced by an 
1934+ // OS thread. 
19221935void 
1923- _PyThreadState_DeleteList (PyThreadState  * list )
1936+ _PyThreadState_DeleteList (PyThreadState  * list ,  int   is_after_fork )
19241937{
19251938    // The world can't be stopped because we PyThreadState_Clear() can 
19261939    // call destructors. 
@@ -1930,7 +1943,12 @@ _PyThreadState_DeleteList(PyThreadState *list)
19301943    for  (p  =  list ; p ; p  =  next ) {
19311944        next  =  p -> next ;
19321945        PyThreadState_Clear (p );
1933-         free_threadstate ((_PyThreadStateImpl  * )p );
1946+         if  (is_after_fork ) {
1947+             free_threadstate ((_PyThreadStateImpl  * )p );
1948+         }
1949+         else  {
1950+             decref_threadstate ((_PyThreadStateImpl  * )p );
1951+         }
19341952    }
19351953}
19361954
@@ -2063,12 +2081,19 @@ static void
20632081tstate_wait_attach (PyThreadState  * tstate )
20642082{
20652083    do  {
2066-         int  expected  =  _Py_THREAD_SUSPENDED ;
2067- 
2068-         // Wait until we're switched out of SUSPENDED to DETACHED. 
2069-         _PyParkingLot_Park (& tstate -> state , & expected , sizeof (tstate -> state ),
2070-                            /*timeout=*/ -1 , NULL , /*detach=*/ 0 );
2071- 
2084+         int  state  =  _Py_atomic_load_int_relaxed (& tstate -> state );
2085+         if  (state  ==  _Py_THREAD_SUSPENDED ) {
2086+             // Wait until we're switched out of SUSPENDED to DETACHED. 
2087+             _PyParkingLot_Park (& tstate -> state , & state , sizeof (tstate -> state ),
2088+                                /*timeout=*/ -1 , NULL , /*detach=*/ 0 );
2089+         }
2090+         else  if  (state  ==  _Py_THREAD_SHUTTING_DOWN ) {
2091+             // We're shutting down, so we can't attach. 
2092+             _PyThreadState_HangThread (tstate );
2093+         }
2094+         else  {
2095+             assert (state  ==  _Py_THREAD_DETACHED );
2096+         }
20722097        // Once we're back in DETACHED we can re-attach 
20732098    } while  (!tstate_try_attach (tstate ));
20742099}
@@ -2100,7 +2125,7 @@ _PyThreadState_Attach(PyThreadState *tstate)
21002125        }
21012126
21022127#ifdef  Py_GIL_DISABLED 
2103-         if  (_PyEval_IsGILEnabled (tstate ) &&  !tstate -> _status . holds_gil ) {
2128+         if  (_PyEval_IsGILEnabled (tstate ) &&  !tstate -> holds_gil ) {
21042129            // The GIL was enabled between our call to _PyEval_AcquireLock() 
21052130            // and when we attached (the GIL can't go from enabled to disabled 
21062131            // here because only a thread holding the GIL can disable 
@@ -2183,6 +2208,15 @@ _PyThreadState_Suspend(PyThreadState *tstate)
21832208    HEAD_UNLOCK (runtime );
21842209}
21852210
2211+ void 
2212+ _PyThreadState_SetShuttingDown (PyThreadState  * tstate )
2213+ {
2214+     _Py_atomic_store_int (& tstate -> state , _Py_THREAD_SHUTTING_DOWN );
2215+ #ifdef  Py_GIL_DISABLED 
2216+     _PyParkingLot_UnparkAll (& tstate -> state );
2217+ #endif 
2218+ }
2219+ 
21862220// Decrease stop-the-world counter of remaining number of threads that need to 
21872221// pause. If we are the final thread to pause, notify the requesting thread. 
21882222static  void 
@@ -2983,43 +3017,27 @@ _PyThreadState_CheckConsistency(PyThreadState *tstate)
29833017#endif 
29843018
29853019
2986- // Check if a Python thread must exit immediately, rather than taking the GIL 
2987- // if Py_Finalize() has been called. 
3020+ // Check if a Python thread must call _PyThreadState_HangThread(), rather than 
3021+ // taking the GIL or attaching to the interpreter if Py_Finalize() has been 
3022+ // called. 
29883023// 
29893024// When this function is called by a daemon thread after Py_Finalize() has been 
2990- // called, the GIL does no longer exist. 
2991- // 
2992- // tstate can be a dangling pointer (point to freed memory): only tstate value 
2993- // is used, the pointer is not deferenced. 
3025+ // called, the GIL may no longer exist. 
29943026// 
29953027// tstate must be non-NULL. 
29963028int 
29973029_PyThreadState_MustExit (PyThreadState  * tstate )
29983030{
2999-     /* bpo-39877: Access _PyRuntime directly rather than using 
3000-        tstate->interp->runtime to support calls from Python daemon threads. 
3001-        After Py_Finalize() has been called, tstate can be a dangling pointer: 
3002-        point to PyThreadState freed memory. */ 
3003-     unsigned long  finalizing_id  =  _PyRuntimeState_GetFinalizingID (& _PyRuntime );
3004-     PyThreadState  * finalizing  =  _PyRuntimeState_GetFinalizing (& _PyRuntime );
3005-     if  (finalizing  ==  NULL ) {
3006-         // XXX This isn't completely safe from daemon thraeds, 
3007-         // since tstate might be a dangling pointer. 
3008-         finalizing  =  _PyInterpreterState_GetFinalizing (tstate -> interp );
3009-         finalizing_id  =  _PyInterpreterState_GetFinalizingID (tstate -> interp );
3010-     }
3011-     // XXX else check &_PyRuntime._main_interpreter._initial_thread 
3012-     if  (finalizing  ==  NULL ) {
3013-         return  0 ;
3014-     }
3015-     else  if  (finalizing  ==  tstate ) {
3016-         return  0 ;
3017-     }
3018-     else  if  (finalizing_id  ==  PyThread_get_thread_ident ()) {
3019-         /* gh-109793: we must have switched interpreters. */ 
3020-         return  0 ;
3021-     }
3022-     return  1 ;
3031+     int  state  =  _Py_atomic_load_int_relaxed (& tstate -> state );
3032+     return  state  ==  _Py_THREAD_SHUTTING_DOWN ;
3033+ }
3034+ 
3035+ void 
3036+ _PyThreadState_HangThread (PyThreadState  * tstate )
3037+ {
3038+     _PyThreadStateImpl  * tstate_impl  =  (_PyThreadStateImpl  * )tstate ;
3039+     decref_threadstate (tstate_impl );
3040+     PyThread_hang_thread ();
30233041}
30243042
30253043/********************/ 
0 commit comments