Skip to content

Commit 025cc17

Browse files
committed
Fix subinterpreter cleanup.
1 parent 953b49e commit 025cc17

1 file changed

Lines changed: 27 additions & 25 deletions

File tree

Python/pylifecycle.c

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2054,12 +2054,23 @@ _Py_Finalize(_PyRuntimeState *runtime)
20542054
int malloc_stats = tstate->interp->config.malloc_stats;
20552055
#endif
20562056

2057+
/* Clean up any lingering subinterpreters.
2058+
2059+
Two preconditions need to be met here:
2060+
2061+
- This has to happen before _PyRuntimeState_SetFinalizing is
2062+
called, or else threads might get prematurely blocked.
2063+
- The world must not be stopped, as finalizers can run.
2064+
*/
2065+
finalize_subinterpreters();
2066+
20572067
/* Ensure that remaining threads are detached */
20582068
_PyEval_StopTheWorldAll(runtime);
20592069

20602070
/* Remaining daemon threads will be trapped in PyThread_hang_thread
20612071
when they attempt to take the GIL (ex: PyEval_RestoreThread()). */
20622072
_PyInterpreterState_SetFinalizing(tstate->interp, tstate);
2073+
20632074
_PyRuntimeState_SetFinalizing(runtime, tstate);
20642075
runtime->initialized = 0;
20652076
runtime->core_initialized = 0;
@@ -2121,9 +2132,6 @@ _Py_Finalize(_PyRuntimeState *runtime)
21212132
_PyImport_FiniExternal(tstate->interp);
21222133
finalize_modules(tstate);
21232134

2124-
/* Clean up any lingering subinterpreters. */
2125-
finalize_subinterpreters();
2126-
21272135
/* Print debug stats if any */
21282136
_PyEval_Fini();
21292137

@@ -2438,14 +2446,15 @@ Py_EndInterpreter(PyThreadState *tstate)
24382446
_Py_FinishPendingCalls(tstate);
24392447

24402448
_PyAtExit_Call(tstate->interp);
2441-
2442-
if (tstate != interp->threads.head || tstate->next != NULL) {
2443-
Py_FatalError("not the last thread");
2444-
}
2449+
_PyRuntimeState *runtime = interp->runtime;
2450+
_PyEval_StopTheWorldAll(runtime);
2451+
PyThreadState *list = _PyThreadState_RemoveExcept(tstate);
24452452

24462453
/* Remaining daemon threads will automatically exit
24472454
when they attempt to take the GIL (ex: PyEval_RestoreThread()). */
24482455
_PyInterpreterState_SetFinalizing(interp, tstate);
2456+
_PyEval_StartTheWorldAll(runtime);
2457+
_PyThreadState_DeleteList(list);
24492458

24502459
// XXX Call something like _PyImport_Disable() here?
24512460

@@ -2476,6 +2485,8 @@ finalize_subinterpreters(void)
24762485
PyInterpreterState *main_interp = _PyInterpreterState_Main();
24772486
assert(final_tstate->interp == main_interp);
24782487
_PyRuntimeState *runtime = main_interp->runtime;
2488+
assert(!runtime->stoptheworld.world_stopped);
2489+
assert(_PyRuntimeState_GetFinalizing(runtime) == NULL);
24792490
struct pyinterpreters *interpreters = &runtime->interpreters;
24802491

24812492
/* Get the first interpreter in the list. */
@@ -2504,27 +2515,18 @@ finalize_subinterpreters(void)
25042515

25052516
/* Clean up all remaining subinterpreters. */
25062517
while (interp != NULL) {
2507-
assert(!_PyInterpreterState_IsRunningMain(interp));
2508-
2509-
/* Find the tstate to use for fini. We assume the interpreter
2510-
will have at most one tstate at this point. */
2511-
PyThreadState *tstate = interp->threads.head;
2512-
if (tstate != NULL) {
2513-
/* Ideally we would be able to use tstate as-is, and rely
2514-
on it being in a ready state: no exception set, not
2515-
running anything (tstate->current_frame), matching the
2516-
current thread ID (tstate->thread_id). To play it safe,
2517-
we always delete it and use a fresh tstate instead. */
2518-
assert(tstate != final_tstate);
2519-
_PyThreadState_Attach(tstate);
2520-
PyThreadState_Clear(tstate);
2521-
_PyThreadState_Detach(tstate);
2522-
PyThreadState_Delete(tstate);
2518+
/* Make a tstate for finalization. */
2519+
PyThreadState *tstate = _PyThreadState_NewBound(interp, _PyThreadState_WHENCE_FINI);
2520+
if (tstate == NULL)
2521+
{
2522+
// XXX Some graceful way to always get a thread state?
2523+
Py_FatalError("thread state allocation failed");
25232524
}
2524-
tstate = _PyThreadState_NewBound(interp, _PyThreadState_WHENCE_FINI);
25252525

2526-
/* Destroy the subinterpreter. */
2526+
/* Enter the subinterpreter. */
25272527
_PyThreadState_Attach(tstate);
2528+
2529+
/* Destroy the subinterpreter. */
25282530
Py_EndInterpreter(tstate);
25292531
assert(_PyThreadState_GET() == NULL);
25302532

0 commit comments

Comments
 (0)