Skip to content

Commit

Permalink
pythongh-117300: Use stop the world to make sys._current_frames and…
Browse files Browse the repository at this point in the history
… `sys._current_exceptions` thread-safe. (python#117301)

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.
  • Loading branch information
colesbury authored and diegorusso committed Apr 17, 2024
1 parent d9bd4ef commit 1a45d0b
Show file tree
Hide file tree
Showing 2 changed files with 6 additions and 1 deletion.
3 changes: 2 additions & 1 deletion Lib/test/test_sys.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
4 changes: 4 additions & 0 deletions Python/pystate.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -2441,6 +2442,7 @@ _PyThread_CurrentFrames(void)

done:
HEAD_UNLOCK(runtime);
_PyEval_StartTheWorldAll(runtime);
return result;
}

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -2504,6 +2507,7 @@ _PyThread_CurrentExceptions(void)

done:
HEAD_UNLOCK(runtime);
_PyEval_StartTheWorldAll(runtime);
return result;
}

Expand Down

0 comments on commit 1a45d0b

Please sign in to comment.