gh-111964: Implement stop-the-world pauses (gh-112471)

The `--disable-gil` builds occasionally need to pause all but one thread.  Some
examples include:

* Cyclic garbage collection, where this is often called a "stop the world event"
* Before calling `fork()`, to ensure a consistent state for internal data structures
* During interpreter shutdown, to ensure that daemon threads aren't accessing Python objects

This adds the following functions to implement global and per-interpreter pauses:

* `_PyEval_StopTheWorldAll()` and `_PyEval_StartTheWorldAll()` (for the global runtime)
* `_PyEval_StopTheWorld()` and `_PyEval_StartTheWorld()` (per-interpreter)

(The function names may change.)

These functions are no-ops outside of the `--disable-gil` build.
This commit is contained in:
Sam Gross 2024-01-23 13:08:23 -05:00 committed by GitHub
parent 5f1997896d
commit 441affc9e7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 336 additions and 29 deletions

View file

@ -949,6 +949,15 @@ _Py_HandlePending(PyThreadState *tstate)
{
PyInterpreterState *interp = tstate->interp;
/* Stop-the-world */
if (_Py_eval_breaker_bit_is_set(interp, _PY_EVAL_PLEASE_STOP_BIT)) {
_Py_set_eval_breaker_bit(interp, _PY_EVAL_PLEASE_STOP_BIT, 0);
_PyThreadState_Suspend(tstate);
/* The attach blocks until the stop-the-world event is complete. */
_PyThreadState_Attach(tstate);
}
/* Pending signals */
if (_Py_eval_breaker_bit_is_set(interp, _PY_SIGNALS_PENDING_BIT)) {
if (handle_signals(tstate) != 0) {