From 167cab126adf38192e312b0e356640c41e0a7910 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Thu, 21 Mar 2024 16:32:04 -0600 Subject: [PATCH 1/4] Drop the fallback code in _PyInterpreterState_IsRunningMain(). --- Python/pystate.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Python/pystate.c b/Python/pystate.c index 47d327ae28933b..74529f4846ecef 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1042,10 +1042,12 @@ _PyInterpreterState_IsRunningMain(PyInterpreterState *interp) if (interp->threads.main != NULL) { return 1; } - // For now, we assume the main interpreter is always running. - if (_Py_IsMainInterpreter(interp)) { - return 1; - } + // Embedders might not know to call _PyInterpreterState_SetRunningMain(), + // so their main thread wouldn't show it is running the main interpreter's + // program. (Py_Main() doesn't have this problem.) For now this isn't + // critical. If it were, we would need to infer "running main" from other + // information, like if it's the main interpreter. We used to do that + // but the naive approach led to some inconsistencies that caused problems. return 0; } @@ -1067,9 +1069,8 @@ _PyThreadState_IsRunningMain(PyThreadState *tstate) if (interp->threads.main != NULL) { return tstate == interp->threads.main; } - if (_Py_IsMainInterpreter(interp)) { - return tstate->thread_id == interp->runtime->main_thread; - } + // See the note in _PyInterpreterState_IsRunningMain() about + // possible false negatives here for embedders. return 0; } From 00301ee67b983be1ff47303a43158e28f4aa2d4d Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Thu, 21 Mar 2024 16:39:49 -0600 Subject: [PATCH 2/4] Drop is_running_main(). --- Python/pystate.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/Python/pystate.c b/Python/pystate.c index 74529f4846ecef..921e74ed5a9826 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1051,17 +1051,6 @@ _PyInterpreterState_IsRunningMain(PyInterpreterState *interp) return 0; } -#ifndef NDEBUG -static int -is_running_main(PyThreadState *tstate) -{ - if (tstate->interp->threads.main != NULL) { - return tstate == tstate->interp->threads.main; - } - return 0; -} -#endif - int _PyThreadState_IsRunningMain(PyThreadState *tstate) { @@ -1572,7 +1561,7 @@ PyThreadState_Clear(PyThreadState *tstate) { assert(tstate->_status.initialized && !tstate->_status.cleared); assert(current_fast_get()->interp == tstate->interp); - assert(!is_running_main(tstate)); + assert(!_PyThreadState_IsRunningMain(tstate)); // XXX assert(!tstate->_status.bound || tstate->_status.unbound); tstate->_status.finalizing = 1; // just in case @@ -1671,7 +1660,7 @@ tstate_delete_common(PyThreadState *tstate) assert(tstate->_status.cleared && !tstate->_status.finalized); assert(tstate->state != _Py_THREAD_ATTACHED); tstate_verify_not_active(tstate); - assert(!is_running_main(tstate)); + assert(!_PyThreadState_IsRunningMain(tstate)); PyInterpreterState *interp = tstate->interp; if (interp == NULL) { From 875e4454f09d2d47c10e08a50d065f4d4b99a447 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Thu, 21 Mar 2024 16:40:43 -0600 Subject: [PATCH 3/4] Add a fallback check in _xxsubinterpreters for is-running-main. --- Modules/_xxsubinterpretersmodule.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index befa225c9183c5..5e5b3c10201867 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -56,6 +56,24 @@ _get_current_module(void) } +static int +is_running_main(PyInterpreterState *interp) +{ + if (_PyInterpreterState_IsRunningMain(interp)) { + return 1; + } + // Unlike with the general C-API, we can be confident that someone + // using this module for the main interpreter is doing so through + // the main program. Thus we can make this extra check. This benefits + // applications that embed Python but haven't been updated yet + // to call_PyInterpreterState_SetRunningMain(). + if (_Py_IsMainInterpreter(interp)) { + return 1; + } + return 0; +} + + /* Cross-interpreter Buffer Views *******************************************/ // XXX Release when the original interpreter is destroyed. @@ -509,7 +527,7 @@ interp_destroy(PyObject *self, PyObject *args, PyObject *kwds) // Ensure the interpreter isn't running. /* XXX We *could* support destroying a running interpreter but aren't going to worry about it for now. */ - if (_PyInterpreterState_IsRunningMain(interp)) { + if (is_running_main(interp)) { PyErr_Format(PyExc_RuntimeError, "interpreter running"); return NULL; } @@ -977,7 +995,7 @@ interp_is_running(PyObject *self, PyObject *args, PyObject *kwds) if (interp == NULL) { return NULL; } - if (_PyInterpreterState_IsRunningMain(interp)) { + if (is_running_main(interp)) { Py_RETURN_TRUE; } Py_RETURN_FALSE; From 785e65f388281c332bc1e540bf73ed8aed2f75cb Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Thu, 21 Mar 2024 15:31:12 -0600 Subject: [PATCH 4/4] Set running main in Py_FrozenMain(). --- Python/frozenmain.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Python/frozenmain.c b/Python/frozenmain.c index 3ce9476c9ad46c..ec4566bd4f84bc 100644 --- a/Python/frozenmain.c +++ b/Python/frozenmain.c @@ -54,6 +54,12 @@ Py_FrozenMain(int argc, char **argv) Py_ExitStatusException(status); } + PyInterpreterState *interp = PyInterpreterState_Get(); + if (_PyInterpreterState_SetRunningMain(interp) < 0) { + PyErr_Print(); + exit(1); + } + #ifdef MS_WINDOWS PyWinFreeze_ExeInit(); #endif @@ -83,6 +89,9 @@ Py_FrozenMain(int argc, char **argv) #ifdef MS_WINDOWS PyWinFreeze_ExeTerm(); #endif + + _PyInterpreterState_SetNotRunningMain(interp); + if (Py_FinalizeEx() < 0) { sts = 120; }