Skip to content

Commit d3beea4

Browse files
Tweaks to resolve_final_tstate().
1 parent 361d477 commit d3beea4

File tree

1 file changed

+33
-23
lines changed

1 file changed

+33
-23
lines changed

Python/pylifecycle.c

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1923,6 +1923,9 @@ resolve_final_tstate(_PyRuntimeState *runtime, struct pyfinalize_args *args)
19231923
assert(tstate->interp->runtime == runtime);
19241924
assert(tstate->thread_id == PyThread_get_thread_ident());
19251925
PyInterpreterState *main_interp = _PyInterpreterState_Main();
1926+
PyThreadState *main_tstate = runtime->main_tstate;
1927+
1928+
/* First we report unexpected Py_Finalize() usage. */
19261929

19271930
#define PRINT_ERROR(msg) \
19281931
if (args->verbose) { \
@@ -1931,9 +1934,10 @@ resolve_final_tstate(_PyRuntimeState *runtime, struct pyfinalize_args *args)
19311934

19321935
/* The main tstate is set by Py_Initialize(), but can be unset
19331936
* or even replaced in unlikely cases. */
1934-
PyThreadState *main_tstate = runtime->main_tstate;
19351937
if (main_tstate == NULL) {
19361938
PRINT_ERROR("main thread state not set");
1939+
/* Ideally, we would make sure a main tstate is set.
1940+
For now we leave it unset. */
19371941
}
19381942
else {
19391943
assert(main_tstate->thread_id == runtime->main_thread);
@@ -1949,48 +1953,51 @@ resolve_final_tstate(_PyRuntimeState *runtime, struct pyfinalize_args *args)
19491953
}
19501954
}
19511955

1952-
if (_Py_IsMainThread()) {
1956+
if (!_Py_IsMainThread()) {
1957+
PRINT_ERROR("expected to be in the main thread");
1958+
}
1959+
1960+
if (tstate->interp != main_interp) {
1961+
PRINT_ERROR("expected main interpreter to be active");
1962+
}
1963+
1964+
#undef PRINT_ERROR
1965+
1966+
/* Then we decide the thread state we should use for finalization. */
1967+
1968+
PyThreadState *final_tstate = tstate;
1969+
if (_Py_IsMainThread() && main_tstate != NULL) {
19531970
if (tstate != main_tstate) {
19541971
/* This implies that Py_Finalize() was called while
19551972
a non-main interpreter was active or while the main
19561973
tstate was temporarily swapped out with another.
19571974
Neither case should be allowed, but, until we get around
19581975
to fixing that (and Py_Exit()), we're letting it go. */
1959-
if (tstate->interp != main_interp) {
1960-
PRINT_ERROR("expected main interpreter to be active");
1961-
}
1962-
(void)PyThreadState_Swap(main_tstate);
1976+
final_tstate = main_tstate;
19631977
}
19641978
}
19651979
else {
1966-
PRINT_ERROR("expected to be in the main thread");
19671980
/* This is another unfortunate case where Py_Finalize() was
19681981
called when it shouldn't have been. We can't simply switch
19691982
over to the main thread. At the least, however, we can make
19701983
sure the main interpreter is active. */
1971-
if (!_Py_IsMainInterpreter(tstate->interp)) {
1972-
PRINT_ERROR("expected main interpreter to be active");
1984+
if (tstate->interp != main_interp) {
19731985
/* We don't go to the trouble of updating runtime->main_tstate
19741986
since it will be dead soon anyway. */
1975-
main_tstate =
1987+
final_tstate =
19761988
_PyThreadState_New(main_interp, _PyThreadState_WHENCE_FINI);
1977-
if (main_tstate != NULL) {
1978-
_PyThreadState_Bind(main_tstate);
1979-
(void)PyThreadState_Swap(main_tstate);
1980-
}
1981-
else {
1982-
/* Fall back to the current tstate. It's better than nothing. */
1983-
main_tstate = tstate;
1989+
if (final_tstate != NULL) {
1990+
_PyThreadState_Bind(final_tstate);
19841991
}
1992+
/* Otherwise we fall back to the current tstate.
1993+
It's better than nothing. */
19851994
}
19861995
}
1987-
assert(main_tstate != NULL);
1996+
assert(final_tstate != NULL);
19881997

1989-
/* We might want to warn if main_tstate->current_frame != NULL. */
1998+
/* We might want to warn if final_tstate->current_frame != NULL. */
19901999

1991-
return main_tstate;
1992-
1993-
#undef PRINT_ERROR
2000+
return final_tstate;
19942001
}
19952002

19962003
int
@@ -2003,8 +2010,11 @@ _Py_Finalize(_PyRuntimeState *runtime, struct pyfinalize_args *args)
20032010
return status;
20042011
}
20052012

2006-
/* Get final thread state pointer. */
2013+
/* Get/attach the final thread state pointer. */
20072014
PyThreadState *tstate = resolve_final_tstate(runtime, args);
2015+
if (tstate != _PyThreadState_GET()) {
2016+
(void)PyThreadState_Swap(tstate);
2017+
}
20082018

20092019
// Block some operations.
20102020
tstate->interp->finalizing = 1;

0 commit comments

Comments
 (0)