From 1c4cbdf94dbb4a6ac1093d2fa7a75efa802b25bc Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 13 Apr 2020 11:45:21 +0200 Subject: bpo-40268: Add pycore_runtime.h header file (GH-19493) Move PyRuntimeState from pycore_pystate.h to pycore_runtime.h. Remove _PyGILState_check_enabled macro: access directly _PyRuntime.gilstate.check_enabled. --- Include/internal/pycore_pystate.h | 122 +------------------------------ Include/internal/pycore_runtime.h | 143 +++++++++++++++++++++++++++++++++++++ Makefile.pre.in | 1 + PCbuild/pythoncore.vcxproj | 1 + PCbuild/pythoncore.vcxproj.filters | 3 + Python/pylifecycle.c | 2 +- Python/pystate.c | 5 +- 7 files changed, 152 insertions(+), 125 deletions(-) create mode 100644 Include/internal/pycore_runtime.h diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index c28df89..c9275a7 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -11,6 +11,7 @@ extern "C" { #include "pycore_gil.h" /* struct _gil_runtime_state */ #include "pycore_pymem.h" /* struct _gc_runtime_state */ #include "pycore_warnings.h" /* struct _warnings_runtime_state */ +#include "pycore_runtime.h" /* PyRuntimestate */ /* ceval state */ @@ -32,15 +33,6 @@ struct _pending_calls { int last; }; -struct _ceval_runtime_state { - int recursion_limit; - /* Request for dropping the GIL */ - _Py_atomic_int gil_drop_request; - /* Request for checking signals. */ - _Py_atomic_int signals_pending; - struct _gil_runtime_state gil; -}; - struct _ceval_state { /* Records whether tracing is on for any thread. Counts the number of threads for which tstate->c_tracefunc is non-NULL, so if the @@ -176,118 +168,6 @@ struct _xidregitem { struct _xidregitem *next; }; -/* runtime audit hook state */ - -typedef struct _Py_AuditHookEntry { - struct _Py_AuditHookEntry *next; - Py_AuditHookFunction hookCFunction; - void *userData; -} _Py_AuditHookEntry; - -/* GIL state */ - -struct _gilstate_runtime_state { - int check_enabled; - /* Assuming the current thread holds the GIL, this is the - PyThreadState for the current thread. */ - _Py_atomic_address tstate_current; - /* The single PyInterpreterState used by this process' - GILState implementation - */ - /* TODO: Given interp_main, it may be possible to kill this ref */ - PyInterpreterState *autoInterpreterState; - Py_tss_t autoTSSkey; -}; - -/* Issue #26558: Flag to disable PyGILState_Check(). - If set to non-zero, PyGILState_Check() always return 1. */ -#define _PyGILState_check_enabled _PyRuntime.gilstate.check_enabled - - -/* Full Python runtime state */ - -typedef struct pyruntimestate { - /* Is running Py_PreInitialize()? */ - int preinitializing; - - /* Is Python preinitialized? Set to 1 by Py_PreInitialize() */ - int preinitialized; - - /* Is Python core initialized? Set to 1 by _Py_InitializeCore() */ - int core_initialized; - - /* Is Python fully initialized? Set to 1 by Py_Initialize() */ - int initialized; - - /* Set by Py_FinalizeEx(). Only reset to NULL if Py_Initialize() - is called again. - - Use _PyRuntimeState_GetFinalizing() and _PyRuntimeState_SetFinalizing() - to access it, don't access it directly. */ - _Py_atomic_address _finalizing; - - struct pyinterpreters { - PyThread_type_lock mutex; - PyInterpreterState *head; - PyInterpreterState *main; - /* _next_interp_id is an auto-numbered sequence of small - integers. It gets initialized in _PyInterpreterState_Init(), - which is called in Py_Initialize(), and used in - PyInterpreterState_New(). A negative interpreter ID - indicates an error occurred. The main interpreter will - always have an ID of 0. Overflow results in a RuntimeError. - If that becomes a problem later then we can adjust, e.g. by - using a Python int. */ - int64_t next_id; - } interpreters; - // XXX Remove this field once we have a tp_* slot. - struct _xidregistry { - PyThread_type_lock mutex; - struct _xidregitem *head; - } xidregistry; - - unsigned long main_thread; - -#define NEXITFUNCS 32 - void (*exitfuncs[NEXITFUNCS])(void); - int nexitfuncs; - - struct _ceval_runtime_state ceval; - struct _gilstate_runtime_state gilstate; - - PyPreConfig preconfig; - - Py_OpenCodeHookFunction open_code_hook; - void *open_code_userdata; - _Py_AuditHookEntry *audit_hook_head; - - // XXX Consolidate globals found via the check-c-globals script. -} _PyRuntimeState; - -#define _PyRuntimeState_INIT \ - {.preinitialized = 0, .core_initialized = 0, .initialized = 0} -/* Note: _PyRuntimeState_INIT sets other fields to 0/NULL */ - -PyAPI_DATA(_PyRuntimeState) _PyRuntime; -PyAPI_FUNC(PyStatus) _PyRuntimeState_Init(_PyRuntimeState *runtime); -PyAPI_FUNC(void) _PyRuntimeState_Fini(_PyRuntimeState *runtime); -PyAPI_FUNC(void) _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime); - -/* Initialize _PyRuntimeState. - Return NULL on success, or return an error message on failure. */ -PyAPI_FUNC(PyStatus) _PyRuntime_Initialize(void); - -PyAPI_FUNC(void) _PyRuntime_Finalize(void); - -static inline PyThreadState* -_PyRuntimeState_GetFinalizing(_PyRuntimeState *runtime) { - return (PyThreadState*)_Py_atomic_load_relaxed(&runtime->_finalizing); -} - -static inline void -_PyRuntimeState_SetFinalizing(_PyRuntimeState *runtime, PyThreadState *tstate) { - _Py_atomic_store_relaxed(&runtime->_finalizing, (uintptr_t)tstate); -} /* Check if the current thread is the main thread. Use _Py_IsMainInterpreter() to check if it's the main interpreter. */ diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h new file mode 100644 index 0000000..54dbaeb --- /dev/null +++ b/Include/internal/pycore_runtime.h @@ -0,0 +1,143 @@ +#ifndef Py_INTERNAL_RUNTIME_H +#define Py_INTERNAL_RUNTIME_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + +#include "pycore_atomic.h" /* _Py_atomic_address */ +#include "pycore_gil.h" // struct _gil_runtime_state + +/* ceval state */ + +struct _ceval_runtime_state { + int recursion_limit; + /* Request for dropping the GIL */ + _Py_atomic_int gil_drop_request; + /* Request for checking signals. */ + _Py_atomic_int signals_pending; + struct _gil_runtime_state gil; +}; + +/* GIL state */ + +struct _gilstate_runtime_state { + /* bpo-26558: Flag to disable PyGILState_Check(). + If set to non-zero, PyGILState_Check() always return 1. */ + int check_enabled; + /* Assuming the current thread holds the GIL, this is the + PyThreadState for the current thread. */ + _Py_atomic_address tstate_current; + /* The single PyInterpreterState used by this process' + GILState implementation + */ + /* TODO: Given interp_main, it may be possible to kill this ref */ + PyInterpreterState *autoInterpreterState; + Py_tss_t autoTSSkey; +}; + +/* Runtime audit hook state */ + +typedef struct _Py_AuditHookEntry { + struct _Py_AuditHookEntry *next; + Py_AuditHookFunction hookCFunction; + void *userData; +} _Py_AuditHookEntry; + +/* Full Python runtime state */ + +typedef struct pyruntimestate { + /* Is running Py_PreInitialize()? */ + int preinitializing; + + /* Is Python preinitialized? Set to 1 by Py_PreInitialize() */ + int preinitialized; + + /* Is Python core initialized? Set to 1 by _Py_InitializeCore() */ + int core_initialized; + + /* Is Python fully initialized? Set to 1 by Py_Initialize() */ + int initialized; + + /* Set by Py_FinalizeEx(). Only reset to NULL if Py_Initialize() + is called again. + + Use _PyRuntimeState_GetFinalizing() and _PyRuntimeState_SetFinalizing() + to access it, don't access it directly. */ + _Py_atomic_address _finalizing; + + struct pyinterpreters { + PyThread_type_lock mutex; + PyInterpreterState *head; + PyInterpreterState *main; + /* _next_interp_id is an auto-numbered sequence of small + integers. It gets initialized in _PyInterpreterState_Init(), + which is called in Py_Initialize(), and used in + PyInterpreterState_New(). A negative interpreter ID + indicates an error occurred. The main interpreter will + always have an ID of 0. Overflow results in a RuntimeError. + If that becomes a problem later then we can adjust, e.g. by + using a Python int. */ + int64_t next_id; + } interpreters; + // XXX Remove this field once we have a tp_* slot. + struct _xidregistry { + PyThread_type_lock mutex; + struct _xidregitem *head; + } xidregistry; + + unsigned long main_thread; + +#define NEXITFUNCS 32 + void (*exitfuncs[NEXITFUNCS])(void); + int nexitfuncs; + + struct _ceval_runtime_state ceval; + struct _gilstate_runtime_state gilstate; + + PyPreConfig preconfig; + + Py_OpenCodeHookFunction open_code_hook; + void *open_code_userdata; + _Py_AuditHookEntry *audit_hook_head; + + // XXX Consolidate globals found via the check-c-globals script. +} _PyRuntimeState; + +#define _PyRuntimeState_INIT \ + {.preinitialized = 0, .core_initialized = 0, .initialized = 0} +/* Note: _PyRuntimeState_INIT sets other fields to 0/NULL */ + + +PyAPI_DATA(_PyRuntimeState) _PyRuntime; + +PyAPI_FUNC(PyStatus) _PyRuntimeState_Init(_PyRuntimeState *runtime); +PyAPI_FUNC(void) _PyRuntimeState_Fini(_PyRuntimeState *runtime); + +PyAPI_FUNC(void) _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime); + + +/* Initialize _PyRuntimeState. + Return NULL on success, or return an error message on failure. */ +PyAPI_FUNC(PyStatus) _PyRuntime_Initialize(void); + +PyAPI_FUNC(void) _PyRuntime_Finalize(void); + + +static inline PyThreadState* +_PyRuntimeState_GetFinalizing(_PyRuntimeState *runtime) { + return (PyThreadState*)_Py_atomic_load_relaxed(&runtime->_finalizing); +} + +static inline void +_PyRuntimeState_SetFinalizing(_PyRuntimeState *runtime, PyThreadState *tstate) { + _Py_atomic_store_relaxed(&runtime->_finalizing, (uintptr_t)tstate); +} + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_RUNTIME_H */ diff --git a/Makefile.pre.in b/Makefile.pre.in index ac6c2b1..45e7a83 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1103,6 +1103,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_pylifecycle.h \ $(srcdir)/Include/internal/pycore_pymem.h \ $(srcdir)/Include/internal/pycore_pystate.h \ + $(srcdir)/Include/internal/pycore_runtime.h \ $(srcdir)/Include/internal/pycore_sysmodule.h \ $(srcdir)/Include/internal/pycore_traceback.h \ $(srcdir)/Include/internal/pycore_tupleobject.h \ diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 95f9e9b..df0eb3a 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -184,6 +184,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 32da365..8c605c8 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -255,6 +255,9 @@ Include + + Include + Include diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 1bc7d77..c2a0781 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1553,7 +1553,7 @@ new_interpreter(PyThreadState **tstate_p) /* Issue #10915, #15751: The GIL API doesn't work with multiple interpreters: disable PyGILState_Check(). */ - _PyGILState_check_enabled = 0; + runtime->gilstate.check_enabled = 0; PyInterpreterState *interp = PyInterpreterState_New(); if (interp == NULL) { diff --git a/Python/pystate.c b/Python/pystate.c index 19beaf0..3636dc9 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1329,12 +1329,11 @@ PyGILState_GetThisThreadState(void) int PyGILState_Check(void) { - - if (!_PyGILState_check_enabled) { + struct _gilstate_runtime_state *gilstate = &_PyRuntime.gilstate; + if (!gilstate->check_enabled) { return 1; } - struct _gilstate_runtime_state *gilstate = &_PyRuntime.gilstate; if (!PyThread_tss_is_created(&gilstate->autoTSSkey)) { return 1; } -- cgit v0.12