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

@ -41,6 +41,22 @@ struct _Py_long_state {
int max_str_digits;
};
// Support for stop-the-world events. This exists in both the PyRuntime struct
// for global pauses and in each PyInterpreterState for per-interpreter pauses.
struct _stoptheworld_state {
PyMutex mutex; // Serializes stop-the-world attempts.
// NOTE: The below fields are protected by HEAD_LOCK(runtime), not by the
// above mutex.
bool requested; // Set when a pause is requested.
bool world_stopped; // Set when the world is stopped.
bool is_global; // Set when contained in PyRuntime struct.
PyEvent stop_event; // Set when thread_countdown reaches zero.
Py_ssize_t thread_countdown; // Number of threads that must pause.
PyThreadState *requester; // Thread that requested the pause (may be NULL).
};
/* cross-interpreter data registry */
@ -166,6 +182,7 @@ struct _is {
struct _warnings_runtime_state warnings;
struct atexit_state atexit;
struct _stoptheworld_state stoptheworld;
#if defined(Py_GIL_DISABLED)
struct _mimalloc_interp_state mimalloc;