diff options
| author | Eric Snow <ericsnowcurrently@gmail.com> | 2022-01-12 23:28:46 (GMT) |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-01-12 23:28:46 (GMT) |
| commit | ed57b36c32e521162dbb97199e64a340d3bff827 (patch) | |
| tree | fab825ae903723e4dc748e7b89cb78f3b226c816 /Include/internal/pycore_runtime.h | |
| parent | 0bbf30e2b910bc9c5899134ae9d73a8df968da35 (diff) | |
| download | cpython-ed57b36c32e521162dbb97199e64a340d3bff827.zip cpython-ed57b36c32e521162dbb97199e64a340d3bff827.tar.gz cpython-ed57b36c32e521162dbb97199e64a340d3bff827.tar.bz2 | |
bpo-45953: Statically allocate the main interpreter (and initial thread state). (gh-29883)
Previously, the main interpreter was allocated on the heap during runtime initialization. Here we instead embed it into _PyRuntimeState, which means it is statically allocated as part of the _PyRuntime global. The same goes for the initial thread state (of each interpreter, including the main one). Consequently there are fewer allocations during runtime/interpreter init, fewer possible failures, and better memory locality.
FYI, this also helps efforts to consolidate globals, which in turns helps work on subinterpreter isolation.
https://bugs.python.org/issue45953
Diffstat (limited to 'Include/internal/pycore_runtime.h')
| -rw-r--r-- | Include/internal/pycore_runtime.h | 48 |
1 files changed, 38 insertions, 10 deletions
diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h index 725c859..a66a3cf 100644 --- a/Include/internal/pycore_runtime.h +++ b/Include/internal/pycore_runtime.h @@ -11,8 +11,10 @@ extern "C" { #include "pycore_atomic.h" /* _Py_atomic_address */ #include "pycore_gil.h" // struct _gil_runtime_state #include "pycore_global_objects.h" // struct _Py_global_objects +#include "pycore_interp.h" // struct _is #include "pycore_unicodeobject.h" // struct _Py_unicode_runtime_ids + /* ceval state */ struct _ceval_runtime_state { @@ -53,6 +55,9 @@ typedef struct _Py_AuditHookEntry { /* Full Python runtime state */ +/* _PyRuntimeState holds the global state for the CPython runtime. + That data is exposed in the internal API as a static variable (_PyRuntime). + */ typedef struct pyruntimestate { /* Has been initialized to a safe state. @@ -81,7 +86,11 @@ typedef struct pyruntimestate { struct pyinterpreters { PyThread_type_lock mutex; + /* The linked list of interpreters, newest first. */ PyInterpreterState *head; + /* The runtime's initial interpreter, which has a special role + in the operation of the runtime. It is also often the only + interpreter. */ PyInterpreterState *main; /* _next_interp_id is an auto-numbered sequence of small integers. It gets initialized in _PyInterpreterState_Init(), @@ -118,25 +127,44 @@ typedef struct pyruntimestate { struct _Py_unicode_runtime_ids unicode_ids; + /* All the objects that are shared by the runtime's interpreters. */ struct _Py_global_objects global_objects; - // If anything gets added after global_objects then - // _PyRuntimeState_reset() needs to get updated to clear it. + + /* The following fields are here to avoid allocation during init. + The data is exposed through _PyRuntimeState pointer fields. + These fields should not be accessed directly outside of init. + + All other _PyRuntimeState pointer fields are populated when + needed and default to NULL. + + For now there are some exceptions to that rule, which require + allocation during init. These will be addressed on a case-by-case + basis. Most notably, we don't pre-allocated the several mutex + (PyThread_type_lock) fields, because on Windows we only ever get + a pointer type. + */ + + /* PyInterpreterState.interpreters.main */ + PyInterpreterState _main_interpreter; } _PyRuntimeState; +#define _PyThreadState_INIT \ + { \ + ._static = 1, \ + } +#define _PyInterpreterState_INIT \ + { \ + ._static = 1, \ + ._initial_thread = _PyThreadState_INIT, \ + } #define _PyRuntimeState_INIT \ { \ .global_objects = _Py_global_objects_INIT, \ + ._main_interpreter = _PyInterpreterState_INIT, \ } -/* Note: _PyRuntimeState_INIT sets other fields to 0/NULL */ -static inline void -_PyRuntimeState_reset(_PyRuntimeState *runtime) -{ - /* Make it match _PyRuntimeState_INIT. */ - memset(runtime, 0, (size_t)&runtime->global_objects - (size_t)runtime); - _Py_global_objects_reset(&runtime->global_objects); -} +/* other API */ PyAPI_DATA(_PyRuntimeState) _PyRuntime; |
