]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-117300: Use stop the world to make `sys._current_frames` and `sys._current_excepti...
authorSam Gross <colesbury@gmail.com>
Fri, 29 Mar 2024 19:33:06 +0000 (15:33 -0400)
committerGitHub <noreply@github.com>
Fri, 29 Mar 2024 19:33:06 +0000 (15:33 -0400)
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
Python/pystate.c

index 37c16cd1047885006c4d8924c40d45356eda242c..f6f23b0afc34c67f9e4e740694eff271132af709 100644 (file)
@@ -562,7 +562,8 @@ class SysModuleTest(unittest.TestCase):
             # 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()
index 8489f53c6e3e34d1fff119bc58461a06bb080a6f..8bec72779b2c24ae87f81cc45220c083b5129a78 100644 (file)
@@ -2408,6 +2408,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) {
@@ -2441,6 +2442,7 @@ fail:
 
 done:
     HEAD_UNLOCK(runtime);
+    _PyEval_StartTheWorldAll(runtime);
     return result;
 }
 
@@ -2472,6 +2474,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) {
@@ -2504,6 +2507,7 @@ fail:
 
 done:
     HEAD_UNLOCK(runtime);
+    _PyEval_StartTheWorldAll(runtime);
     return result;
 }