summaryrefslogtreecommitdiffstats
path: root/Include/internal/pycore_runtime.h
diff options
context:
space:
mode:
authorEric Snow <ericsnowcurrently@gmail.com>2022-01-12 23:28:46 (GMT)
committerGitHub <noreply@github.com>2022-01-12 23:28:46 (GMT)
commited57b36c32e521162dbb97199e64a340d3bff827 (patch)
treefab825ae903723e4dc748e7b89cb78f3b226c816 /Include/internal/pycore_runtime.h
parent0bbf30e2b910bc9c5899134ae9d73a8df968da35 (diff)
downloadcpython-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.h48
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;