Skip to content

Commit 74f4ed0

Browse files
Make sure there's only one tstate left.
1 parent 6b26e0a commit 74f4ed0

File tree

1 file changed

+44
-13
lines changed

1 file changed

+44
-13
lines changed

Python/pylifecycle.c

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2422,33 +2422,61 @@ _Py_IsInterpreterFinalizing(PyInterpreterState *interp)
24222422
static void
24232423
finalize_subinterpreters(void)
24242424
{
2425+
PyThreadState *final_tstate = _PyThreadState_GET();
24252426
PyInterpreterState *main_interp = _PyInterpreterState_Main();
2426-
assert(_PyInterpreterState_GET() == main_interp);
2427+
assert(final_tstate->interp == main_interp);
24272428
_PyRuntimeState *runtime = main_interp->runtime;
24282429
struct pyinterpreters *interpreters = &runtime->interpreters;
24292430

2430-
/* Clean up all remaining subinterpreters. */
2431+
/* Get the first interpreter in the list. */
24312432
HEAD_LOCK(runtime);
24322433
PyInterpreterState *interp = interpreters->head;
24332434
if (interp == main_interp) {
24342435
interp = interp->next;
24352436
}
24362437
HEAD_UNLOCK(runtime);
2437-
if (interp != NULL) {
2438-
(void)PyErr_WarnEx(
2439-
PyExc_RuntimeWarning,
2440-
"remaining subinterpreters; "
2441-
"destroy them with _interpreters.destroy()",
2442-
0);
2438+
2439+
/* Bail out if there are no subinterpreters left. */
2440+
if (interp == NULL) {
2441+
return;
24432442
}
2443+
2444+
/* Warn the user if they forgot to clean up subinterpreters. */
2445+
(void)PyErr_WarnEx(
2446+
PyExc_RuntimeWarning,
2447+
"remaining subinterpreters; "
2448+
"destroy them with _interpreters.destroy()",
2449+
0);
2450+
2451+
/* Swap out the current tstate, which we know must belong
2452+
to the main interpreter. */
2453+
_PyThreadState_Detach(final_tstate);
2454+
2455+
/* Clean up all remaining subinterpreters. */
24442456
while (interp != NULL) {
2445-
/* Destroy the subinterpreter. */
24462457
assert(!_PyInterpreterState_IsRunningMain(interp));
2447-
PyThreadState *tstate =
2448-
_PyThreadState_NewBound(interp, _PyThreadState_WHENCE_FINI);
2449-
PyThreadState *save_tstate = PyThreadState_Swap(tstate);
2458+
2459+
/* Find the tstate to use for fini. We assume the interpreter
2460+
will have at most one tstate at this point. */
2461+
PyThreadState *tstate = interp->threads.head;
2462+
if (tstate != NULL) {
2463+
/* Ideally we would be able to use tstate as-is, and rely
2464+
on it being in a ready state: no exception set, not
2465+
running anything (tstate->current_frame), matching the
2466+
current thread ID (tstate->thread_id). To play it safe,
2467+
we always delete it and use a fresh tstate instead. */
2468+
assert(tstate != final_tstate);
2469+
_PyThreadState_Attach(tstate);
2470+
PyThreadState_Clear(tstate);
2471+
_PyThreadState_Detach(tstate);
2472+
PyThreadState_Delete(tstate);
2473+
}
2474+
tstate = _PyThreadState_NewBound(interp, _PyThreadState_WHENCE_FINI);
2475+
2476+
/* Destroy the subinterpreter. */
2477+
_PyThreadState_Attach(tstate);
24502478
Py_EndInterpreter(tstate);
2451-
(void)PyThreadState_Swap(save_tstate);
2479+
assert(_PyThreadState_GET() == NULL);
24522480

24532481
/* Advance to the next interpreter. */
24542482
HEAD_LOCK(runtime);
@@ -2458,6 +2486,9 @@ finalize_subinterpreters(void)
24582486
}
24592487
HEAD_UNLOCK(runtime);
24602488
}
2489+
2490+
/* Switch back to the main interpreter. */
2491+
_PyThreadState_Attach(final_tstate);
24612492
}
24622493

24632494

0 commit comments

Comments
 (0)