From 17a405e640fbfaf5ffcea31006be55f254db56ef Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Wed, 27 Mar 2024 20:51:25 +0000 Subject: [PATCH] gh-117300: Use stop the world to make `sys._current_frames` and `sys._current_exceptions` thread-safe. This adds a stop the world pause to make the two functions thread-safe when the GIL is disabled in the free-threaded build. Additionally, the main test thread may call `sys._current_exceptions()` as soon as `g_raised.set()` is called. The background thread may not yet reach the `leave_g.wait()` line. --- Lib/test/test_sys.py | 3 ++- Python/pystate.c | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 37c16cd1047885..f6f23b0afc34c6 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -562,7 +562,8 @@ def g456(): # And the next record must be for g456(). filename, lineno, funcname, sourceline = stack[i+1] self.assertEqual(funcname, "g456") - self.assertTrue(sourceline.startswith("if leave_g.wait(")) + self.assertTrue((sourceline.startswith("if leave_g.wait(") or + sourceline.startswith("g_raised.set()"))) finally: # Reap the spawned thread. leave_g.set() diff --git a/Python/pystate.c b/Python/pystate.c index 921e74ed5a9826..02b604304f5054 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -2406,6 +2406,7 @@ _PyThread_CurrentFrames(void) * Because these lists can mutate even when the GIL is held, we * need to grab head_mutex for the duration. */ + _PyEval_StopTheWorldAll(runtime); HEAD_LOCK(runtime); PyInterpreterState *i; for (i = runtime->interpreters.head; i != NULL; i = i->next) { @@ -2439,6 +2440,7 @@ _PyThread_CurrentFrames(void) done: HEAD_UNLOCK(runtime); + _PyEval_StartTheWorldAll(runtime); return result; } @@ -2470,6 +2472,7 @@ _PyThread_CurrentExceptions(void) * Because these lists can mutate even when the GIL is held, we * need to grab head_mutex for the duration. */ + _PyEval_StopTheWorldAll(runtime); HEAD_LOCK(runtime); PyInterpreterState *i; for (i = runtime->interpreters.head; i != NULL; i = i->next) { @@ -2502,6 +2505,7 @@ _PyThread_CurrentExceptions(void) done: HEAD_UNLOCK(runtime); + _PyEval_StartTheWorldAll(runtime); return result; }