@@ -96,7 +96,7 @@ static PyStatus init_android_streams(PyThreadState *tstate);
9696#if defined(__APPLE__ ) && HAS_APPLE_SYSTEM_LOG
9797static PyStatus init_apple_streams (PyThreadState * tstate );
9898#endif
99- static void wait_for_thread_shutdown (PyThreadState * tstate );
99+ static int wait_for_thread_shutdown (PyThreadState * tstate );
100100static void finalize_subinterpreters (void );
101101static void call_ll_exitfuncs (_PyRuntimeState * runtime );
102102
@@ -2003,6 +2003,39 @@ resolve_final_tstate(_PyRuntimeState *runtime)
20032003 return main_tstate ;
20042004}
20052005
2006+ static void
2007+ make_pre_finalization_calls (PyThreadState * tstate )
2008+ {
2009+ /* Each of these functions can start one another, e.g. a pending call
2010+ * could start a thread or vice versa. To ensure that we properly clean
2011+ * call everything, we run these in a loop until none of them run anything. */
2012+ for (;;) {
2013+ int called = 0 ;
2014+
2015+ // Wrap up existing "threading"-module-created, non-daemon threads.
2016+ called = Py_MAX (called , wait_for_thread_shutdown (tstate ));
2017+
2018+ // Make any remaining pending calls.
2019+ called = Py_MAX (called , _Py_FinishPendingCalls (tstate ));
2020+
2021+ /* The interpreter is still entirely intact at this point, and the
2022+ * exit funcs may be relying on that. In particular, if some thread
2023+ * or exit func is still waiting to do an import, the import machinery
2024+ * expects Py_IsInitialized() to return true. So don't say the
2025+ * runtime is uninitialized until after the exit funcs have run.
2026+ * Note that Threading.py uses an exit func to do a join on all the
2027+ * threads created thru it, so this also protects pending imports in
2028+ * the threads created via Threading.
2029+ */
2030+
2031+ called = Py_MAX (called , _PyAtExit_Call (tstate -> interp ));
2032+
2033+ if (called == 0 ) {
2034+ break ;
2035+ }
2036+ }
2037+ }
2038+
20062039static int
20072040_Py_Finalize (_PyRuntimeState * runtime )
20082041{
@@ -2019,23 +2052,7 @@ _Py_Finalize(_PyRuntimeState *runtime)
20192052 // Block some operations.
20202053 tstate -> interp -> finalizing = 1 ;
20212054
2022- // Wrap up existing "threading"-module-created, non-daemon threads.
2023- wait_for_thread_shutdown (tstate );
2024-
2025- // Make any remaining pending calls.
2026- _Py_FinishPendingCalls (tstate );
2027-
2028- /* The interpreter is still entirely intact at this point, and the
2029- * exit funcs may be relying on that. In particular, if some thread
2030- * or exit func is still waiting to do an import, the import machinery
2031- * expects Py_IsInitialized() to return true. So don't say the
2032- * runtime is uninitialized until after the exit funcs have run.
2033- * Note that Threading.py uses an exit func to do a join on all the
2034- * threads created thru it, so this also protects pending imports in
2035- * the threads created via Threading.
2036- */
2037-
2038- _PyAtExit_Call (tstate -> interp );
2055+ make_pre_finalization_calls (tstate );
20392056
20402057 assert (_PyThreadState_GET () == tstate );
20412058
@@ -3442,7 +3459,7 @@ Py_ExitStatusException(PyStatus status)
34423459 the threading module was imported in the first place.
34433460 The shutdown routine will wait until all non-daemon
34443461 "threading" threads have completed. */
3445- static void
3462+ static int
34463463wait_for_thread_shutdown (PyThreadState * tstate )
34473464{
34483465 PyObject * result ;
@@ -3452,16 +3469,19 @@ wait_for_thread_shutdown(PyThreadState *tstate)
34523469 PyErr_FormatUnraisable ("Exception ignored on threading shutdown" );
34533470 }
34543471 /* else: threading not imported */
3455- return ;
3472+ return 0 ;
34563473 }
3474+ int called = 0 ;
34573475 result = PyObject_CallMethodNoArgs (threading , & _Py_ID (_shutdown ));
34583476 if (result == NULL ) {
34593477 PyErr_FormatUnraisable ("Exception ignored on threading shutdown" );
34603478 }
34613479 else {
3462- Py_DECREF (result );
3480+ assert (PyBool_Check (result ) && _Py_IsImmortal (result ));
3481+ called = result == Py_True ;
34633482 }
34643483 Py_DECREF (threading );
3484+ return called ;
34653485}
34663486
34673487int Py_AtExit (void (* func )(void ))
0 commit comments