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
This commit is contained in:
Eric Snow 2022-01-12 16:28:46 -07:00 committed by GitHub
parent 0bbf30e2b9
commit ed57b36c32
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 115 additions and 34 deletions

View file

@ -8,6 +8,8 @@ extern "C" {
# error "this header requires Py_BUILD_CORE define"
#endif
#include <stdbool.h>
#include "pycore_atomic.h" // _Py_atomic_address
#include "pycore_ast_state.h" // struct ast_state
#include "pycore_context.h" // struct _Py_context_state
@ -70,13 +72,18 @@ struct atexit_state {
/* interpreter state */
// The PyInterpreterState typedef is in Include/pystate.h.
/* PyInterpreterState holds the global state for one of the runtime's
interpreters. Typically the initial (main) interpreter is the only one.
The PyInterpreterState typedef is in Include/pystate.h.
*/
struct _is {
struct _is *next;
struct pythreads {
uint64_t next_unique_id;
/* The linked list of threads, newest first. */
struct _ts *head;
/* Used in Modules/_threadmodule.c. */
long count;
@ -104,6 +111,9 @@ struct _is {
int _initialized;
int finalizing;
/* Was this interpreter statically allocated? */
bool _static;
struct _ceval_state ceval;
struct _gc_runtime_state gc;
@ -166,8 +176,26 @@ struct _is {
struct ast_state ast;
struct type_cache type_cache;
/* The following fields are here to avoid allocation during init.
The data is exposed through PyInterpreterState pointer fields.
These fields should not be accessed directly outside of init.
All other PyInterpreterState 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. Also see _PyRuntimeState regarding the various mutex fields.
*/
/* the initial PyInterpreterState.threads.head */
struct _ts _initial_thread;
};
/* other API */
extern void _PyInterpreterState_ClearModules(PyInterpreterState *interp);
extern void _PyInterpreterState_Clear(PyThreadState *tstate);