Skip to content

Commit 0e66c88

Browse files
committed
Finalize subinterpreters as a pre-finalization check.
1 parent e202848 commit 0e66c88

File tree

1 file changed

+31
-15
lines changed

1 file changed

+31
-15
lines changed

Python/pylifecycle.c

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2060,8 +2060,18 @@ interp_has_atexit_callbacks(PyInterpreterState *interp)
20602060
return PyList_GET_SIZE(interp->atexit.callbacks) != 0;
20612061
}
20622062

2063+
static int
2064+
runtime_has_subinterpreters(_PyRuntimeState *runtime)
2065+
{
2066+
assert(runtime != NULL);
2067+
HEAD_LOCK(runtime);
2068+
PyInterpreterState *interp = runtime->interpreters.head;
2069+
HEAD_UNLOCK(runtime);
2070+
return interp->next != NULL;
2071+
}
2072+
20632073
static void
2064-
make_pre_finalization_calls(PyThreadState *tstate)
2074+
make_pre_finalization_calls(PyThreadState *tstate, int subinterpreters)
20652075
{
20662076
assert(tstate != NULL);
20672077
PyInterpreterState *interp = tstate->interp;
@@ -2089,6 +2099,19 @@ make_pre_finalization_calls(PyThreadState *tstate)
20892099

20902100
_PyAtExit_Call(tstate->interp);
20912101

2102+
if (subinterpreters) {
2103+
/* Clean up any lingering subinterpreters.
2104+
2105+
Two preconditions need to be met here:
2106+
2107+
- This has to happen before _PyRuntimeState_SetFinalizing is
2108+
called, or else threads might get prematurely blocked.
2109+
- The world must not be stopped, as finalizers can run.
2110+
*/
2111+
finalize_subinterpreters();
2112+
}
2113+
2114+
20922115
/* Stop the world to prevent other threads from creating threads or
20932116
* atexit callbacks. On the default build, this is simply locked by
20942117
* the GIL. For pending calls, we acquire the dedicated mutex, because
@@ -2099,9 +2122,13 @@ make_pre_finalization_calls(PyThreadState *tstate)
20992122
// XXX Why does _PyThreadState_DeleteList() rely on all interpreters
21002123
// being stopped?
21012124
_PyEval_StopTheWorldAll(interp->runtime);
2125+
int has_subinterpreters = subinterpreters
2126+
? runtime_has_subinterpreters(interp->runtime)
2127+
: 0;
21022128
int should_continue = (interp_has_threads(interp)
21032129
|| interp_has_atexit_callbacks(interp)
2104-
|| interp_has_pending_calls(interp));
2130+
|| interp_has_pending_calls(interp)
2131+
|| has_subinterpreters);
21052132
if (!should_continue) {
21062133
break;
21072134
}
@@ -2128,19 +2155,8 @@ _Py_Finalize(_PyRuntimeState *runtime)
21282155
// Block some operations.
21292156
tstate->interp->finalizing = 1;
21302157

2131-
/* Clean up any lingering subinterpreters.
2132-
2133-
Two preconditions need to be met here:
2134-
2135-
- This has to happen before _PyRuntimeState_SetFinalizing is
2136-
called, or else threads might get prematurely blocked.
2137-
- The world must not be stopped, as finalizers can run.
2138-
*/
2139-
// TODO: Prevent new subinterpreters after this point
2140-
finalize_subinterpreters();
2141-
21422158
// This call stops the world and takes the pending calls lock.
2143-
make_pre_finalization_calls(tstate);
2159+
make_pre_finalization_calls(tstate, /*subinterpreters=*/1);
21442160

21452161
assert(_PyThreadState_GET() == tstate);
21462162

@@ -2536,7 +2552,7 @@ Py_EndInterpreter(PyThreadState *tstate)
25362552
interp->finalizing = 1;
25372553

25382554
// This call stops the world and takes the pending calls lock.
2539-
make_pre_finalization_calls(tstate);
2555+
make_pre_finalization_calls(tstate, /*subinterpreters=*/0);
25402556

25412557
ASSERT_WORLD_STOPPED(interp);
25422558
/* Remaining daemon threads will automatically exit

0 commit comments

Comments
 (0)