Skip to content

Commit c839974

Browse files
[3.13] gh-113433: Automatically Clean Up Subinterpreters in Py_Finalize() (gh-121067)
This change makes things a little less painful for some users. It also fixes a failing assert (gh-120765), by making sure all subinterpreters are destroyed before the main interpreter. As part of that, we make sure Py_Finalize() always runs with the main interpreter active. (cherry picked from commit 4be1f37, AKA gh-121060) Co-authored-by: Eric Snow <[email protected]>
1 parent c052b19 commit c839974

File tree

3 files changed

+151
-9
lines changed

3 files changed

+151
-9
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Subinterpreters now get cleaned up automatically during runtime
2+
finalization.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:c:func:`Py_Finalize()` and :c:func:`Py_FinalizeEx()` now always run with
2+
the main interpreter active.

Python/pylifecycle.c

Lines changed: 147 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ static PyStatus init_sys_streams(PyThreadState *tstate);
7474
static PyStatus init_android_streams(PyThreadState *tstate);
7575
#endif
7676
static void wait_for_thread_shutdown(PyThreadState *tstate);
77+
static void finalize_subinterpreters(void);
7778
static void call_ll_exitfuncs(_PyRuntimeState *runtime);
7879

7980
/* The following places the `_PyRuntime` structure in a location that can be
@@ -1908,20 +1909,73 @@ finalize_interp_delete(PyInterpreterState *interp)
19081909
}
19091910

19101911

1911-
int
1912-
Py_FinalizeEx(void)
1912+
/* Conceptually, there isn't a good reason for Py_Finalize()
1913+
to be called in any other thread than the one where Py_Initialize()
1914+
was called. Consequently, it would make sense to fail if the thread
1915+
or thread state (or interpreter) don't match. However, such
1916+
constraints have never been enforced, and, as unlikely as it may be,
1917+
there may be users relying on the unconstrained behavior. Thus,
1918+
we do our best here to accommodate that possibility. */
1919+
1920+
static PyThreadState *
1921+
resolve_final_tstate(_PyRuntimeState *runtime)
1922+
{
1923+
PyThreadState *main_tstate = runtime->main_tstate;
1924+
assert(main_tstate != NULL);
1925+
assert(main_tstate->thread_id == runtime->main_thread);
1926+
PyInterpreterState *main_interp = _PyInterpreterState_Main();
1927+
assert(main_tstate->interp == main_interp);
1928+
1929+
PyThreadState *tstate = _PyThreadState_GET();
1930+
if (_Py_IsMainThread()) {
1931+
if (tstate != main_tstate) {
1932+
/* This implies that Py_Finalize() was called while
1933+
a non-main interpreter was active or while the main
1934+
tstate was temporarily swapped out with another.
1935+
Neither case should be allowed, but, until we get around
1936+
to fixing that (and Py_Exit()), we're letting it go. */
1937+
(void)PyThreadState_Swap(main_tstate);
1938+
}
1939+
}
1940+
else {
1941+
/* This is another unfortunate case where Py_Finalize() was
1942+
called when it shouldn't have been. We can't simply switch
1943+
over to the main thread. At the least, however, we can make
1944+
sure the main interpreter is active. */
1945+
if (!_Py_IsMainInterpreter(tstate->interp)) {
1946+
/* We don't go to the trouble of updating runtime->main_tstate
1947+
since it will be dead soon anyway. */
1948+
main_tstate =
1949+
_PyThreadState_New(main_interp, _PyThreadState_WHENCE_FINI);
1950+
if (main_tstate != NULL) {
1951+
_PyThreadState_Bind(main_tstate);
1952+
(void)PyThreadState_Swap(main_tstate);
1953+
}
1954+
else {
1955+
/* Fall back to the current tstate. It's better than nothing. */
1956+
main_tstate = tstate;
1957+
}
1958+
}
1959+
}
1960+
assert(main_tstate != NULL);
1961+
1962+
/* We might want to warn if main_tstate->current_frame != NULL. */
1963+
1964+
return main_tstate;
1965+
}
1966+
1967+
static int
1968+
_Py_Finalize(_PyRuntimeState *runtime)
19131969
{
19141970
int status = 0;
19151971

1916-
_PyRuntimeState *runtime = &_PyRuntime;
1972+
/* Bail out early if already finalized (or never initialized). */
19171973
if (!runtime->initialized) {
19181974
return status;
19191975
}
19201976

1921-
/* Get current thread state and interpreter pointer */
1922-
PyThreadState *tstate = _PyThreadState_GET();
1923-
// XXX assert(_Py_IsMainInterpreter(tstate->interp));
1924-
// XXX assert(_Py_IsMainThread());
1977+
/* Get final thread state pointer. */
1978+
PyThreadState *tstate = resolve_final_tstate(runtime);
19251979

19261980
// Block some operations.
19271981
tstate->interp->finalizing = 1;
@@ -1944,6 +1998,8 @@ Py_FinalizeEx(void)
19441998

19451999
_PyAtExit_Call(tstate->interp);
19462000

2001+
assert(_PyThreadState_GET() == tstate);
2002+
19472003
/* Copy the core config, PyInterpreterState_Delete() free
19482004
the core config memory */
19492005
#ifdef Py_REF_DEBUG
@@ -2024,6 +2080,9 @@ Py_FinalizeEx(void)
20242080
_PyImport_FiniExternal(tstate->interp);
20252081
finalize_modules(tstate);
20262082

2083+
/* Clean up any lingering subinterpreters. */
2084+
finalize_subinterpreters();
2085+
20272086
/* Print debug stats if any */
20282087
_PyEval_Fini();
20292088

@@ -2141,10 +2200,16 @@ Py_FinalizeEx(void)
21412200
return status;
21422201
}
21432202

2203+
int
2204+
Py_FinalizeEx(void)
2205+
{
2206+
return _Py_Finalize(&_PyRuntime);
2207+
}
2208+
21442209
void
21452210
Py_Finalize(void)
21462211
{
2147-
Py_FinalizeEx();
2212+
(void)_Py_Finalize(&_PyRuntime);
21482213
}
21492214

21502215

@@ -2356,6 +2421,79 @@ _Py_IsInterpreterFinalizing(PyInterpreterState *interp)
23562421
return finalizing != NULL;
23572422
}
23582423

2424+
static void
2425+
finalize_subinterpreters(void)
2426+
{
2427+
PyThreadState *final_tstate = _PyThreadState_GET();
2428+
PyInterpreterState *main_interp = _PyInterpreterState_Main();
2429+
assert(final_tstate->interp == main_interp);
2430+
_PyRuntimeState *runtime = main_interp->runtime;
2431+
struct pyinterpreters *interpreters = &runtime->interpreters;
2432+
2433+
/* Get the first interpreter in the list. */
2434+
HEAD_LOCK(runtime);
2435+
PyInterpreterState *interp = interpreters->head;
2436+
if (interp == main_interp) {
2437+
interp = interp->next;
2438+
}
2439+
HEAD_UNLOCK(runtime);
2440+
2441+
/* Bail out if there are no subinterpreters left. */
2442+
if (interp == NULL) {
2443+
return;
2444+
}
2445+
2446+
/* Warn the user if they forgot to clean up subinterpreters. */
2447+
(void)PyErr_WarnEx(
2448+
PyExc_RuntimeWarning,
2449+
"remaining subinterpreters; "
2450+
"destroy them with _interpreters.destroy()",
2451+
0);
2452+
2453+
/* Swap out the current tstate, which we know must belong
2454+
to the main interpreter. */
2455+
_PyThreadState_Detach(final_tstate);
2456+
2457+
/* Clean up all remaining subinterpreters. */
2458+
while (interp != NULL) {
2459+
assert(!_PyInterpreterState_IsRunningMain(interp));
2460+
2461+
/* Find the tstate to use for fini. We assume the interpreter
2462+
will have at most one tstate at this point. */
2463+
PyThreadState *tstate = interp->threads.head;
2464+
if (tstate != NULL) {
2465+
/* Ideally we would be able to use tstate as-is, and rely
2466+
on it being in a ready state: no exception set, not
2467+
running anything (tstate->current_frame), matching the
2468+
current thread ID (tstate->thread_id). To play it safe,
2469+
we always delete it and use a fresh tstate instead. */
2470+
assert(tstate != final_tstate);
2471+
_PyThreadState_Attach(tstate);
2472+
PyThreadState_Clear(tstate);
2473+
_PyThreadState_Detach(tstate);
2474+
PyThreadState_Delete(tstate);
2475+
}
2476+
tstate = _PyThreadState_NewBound(interp, _PyThreadState_WHENCE_FINI);
2477+
2478+
/* Destroy the subinterpreter. */
2479+
_PyThreadState_Attach(tstate);
2480+
Py_EndInterpreter(tstate);
2481+
assert(_PyThreadState_GET() == NULL);
2482+
2483+
/* Advance to the next interpreter. */
2484+
HEAD_LOCK(runtime);
2485+
interp = interpreters->head;
2486+
if (interp == main_interp) {
2487+
interp = interp->next;
2488+
}
2489+
HEAD_UNLOCK(runtime);
2490+
}
2491+
2492+
/* Switch back to the main interpreter. */
2493+
_PyThreadState_Attach(final_tstate);
2494+
}
2495+
2496+
23592497
/* Add the __main__ module */
23602498

23612499
static PyStatus
@@ -3217,7 +3355,7 @@ Py_Exit(int sts)
32173355
if (tstate != NULL && _PyThreadState_IsRunningMain(tstate)) {
32183356
_PyInterpreterState_SetNotRunningMain(tstate->interp);
32193357
}
3220-
if (Py_FinalizeEx() < 0) {
3358+
if (_Py_Finalize(&_PyRuntime) < 0) {
32213359
sts = 120;
32223360
}
32233361

0 commit comments

Comments
 (0)