From 01b1cc12e7c6a3d6a3d27ba7c731687d57aae92a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 20 Nov 2019 02:27:56 +0100 Subject: [PATCH] bpo-36710: Add PyInterpreterState.runtime field (GH-17270) Add PyInterpreterState.runtime field: reference to the _PyRuntime global variable. This field exists to not have to pass runtime in addition to tstate to a function. Get runtime from tstate: tstate->interp->runtime. Remove "_PyRuntimeState *runtime" parameter from functions already taking a "PyThreadState *tstate" parameter. _PyGC_Init() first parameter becomes "PyThreadState *tstate". --- Include/internal/pycore_pylifecycle.h | 11 ++-- Include/internal/pycore_pystate.h | 6 ++- Modules/_threadmodule.c | 2 +- Modules/gcmodule.c | 4 +- Python/ceval.c | 28 ++++++----- Python/pylifecycle.c | 23 +++++---- Python/pystate.c | 72 +++++++++++---------------- Python/sysmodule.c | 29 ++++++----- 8 files changed, 81 insertions(+), 94 deletions(-) diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h index 16baf10061b..f269ffe7868 100644 --- a/Include/internal/pycore_pylifecycle.h +++ b/Include/internal/pycore_pylifecycle.h @@ -38,15 +38,12 @@ extern PyStatus _PyFaulthandler_Init(int enable); extern int _PyTraceMalloc_Init(int enable); extern PyObject * _PyBuiltin_Init(PyThreadState *tstate); extern PyStatus _PySys_Create( - struct pyruntimestate *runtime, PyThreadState *tstate, PyObject **sysmod_p); extern PyStatus _PySys_SetPreliminaryStderr(PyObject *sysdict); extern PyStatus _PySys_ReadPreinitWarnOptions(PyWideStringList *options); extern PyStatus _PySys_ReadPreinitXOptions(PyConfig *config); -extern int _PySys_InitMain( - struct pyruntimestate *runtime, - PyThreadState *tstate); +extern int _PySys_InitMain(PyThreadState *tstate); extern PyStatus _PyImport_Init(PyThreadState *tstate); extern PyStatus _PyExc_Init(void); extern PyStatus _PyErr_Init(void); @@ -57,7 +54,7 @@ extern PyStatus _Py_HashRandomization_Init(const PyConfig *); extern PyStatus _PyTypes_Init(void); extern PyStatus _PyImportZip_Init(PyThreadState *tstate); -extern PyStatus _PyGC_Init(struct pyruntimestate *runtime); +extern PyStatus _PyGC_Init(PyThreadState *tstate); /* Various internal finalizers */ @@ -89,9 +86,7 @@ extern void _PyHash_Fini(void); extern void _PyTraceMalloc_Fini(void); extern void _PyWarnings_Fini(PyInterpreterState *interp); -extern void _PyGILState_Init( - struct pyruntimestate *runtime, - PyThreadState *tstate); +extern void _PyGILState_Init(PyThreadState *tstate); extern void _PyGILState_Fini(struct pyruntimestate *runtime); PyAPI_FUNC(void) _PyGC_DumpShutdownStats(struct pyruntimestate *runtime); diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index eb44ae93fc4..fec64a7badb 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -62,6 +62,11 @@ struct _is { struct _is *next; struct _ts *tstate_head; + /* Reference to the _PyRuntime global variable. This field exists + to not have to pass runtime in addition to tstate to a function. + Get runtime from tstate: tstate->interp->runtime. */ + struct pyruntimestate *runtime; + int64_t id; int64_t id_refcount; int requires_idref; @@ -301,7 +306,6 @@ PyAPI_FUNC(void) _PyRuntime_Finalize(void); /* Other */ PyAPI_FUNC(void) _PyThreadState_Init( - _PyRuntimeState *runtime, PyThreadState *tstate); PyAPI_FUNC(void) _PyThreadState_DeleteExcept( _PyRuntimeState *runtime, diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index 1c7df3f8741..befd213bfeb 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -1007,7 +1007,7 @@ t_bootstrap(void *boot_raw) runtime = boot->runtime; tstate = boot->tstate; tstate->thread_id = PyThread_get_thread_ident(); - _PyThreadState_Init(runtime, tstate); + _PyThreadState_Init(tstate); PyEval_AcquireThread(tstate); tstate->interp->num_threads++; res = PyObject_Call(boot->func, boot->args, boot->keyw); diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 78f6631866a..05ca026189b 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -155,9 +155,9 @@ _PyGC_InitializeRuntime(struct _gc_runtime_state *state) PyStatus -_PyGC_Init(_PyRuntimeState *runtime) +_PyGC_Init(PyThreadState *tstate) { - struct _gc_runtime_state *state = &runtime->gc; + struct _gc_runtime_state *state = &tstate->interp->runtime->gc; if (state->garbage == NULL) { state->garbage = PyList_New(0); if (state->garbage == NULL) { diff --git a/Python/ceval.c b/Python/ceval.c index 9f4b43615e2..ee13fd1ad70 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -191,7 +191,8 @@ static size_t opcache_global_misses = 0; int PyEval_ThreadsInitialized(void) { - return gil_created(&_PyRuntime.ceval.gil); + _PyRuntimeState *runtime = &_PyRuntime; + return gil_created(&runtime->ceval.gil); } void @@ -235,8 +236,9 @@ _PyEval_FiniThreads(struct _ceval_runtime_state *ceval) } static inline void -exit_thread_if_finalizing(_PyRuntimeState *runtime, PyThreadState *tstate) +exit_thread_if_finalizing(PyThreadState *tstate) { + _PyRuntimeState *runtime = tstate->interp->runtime; /* _Py_Finalizing is protected by the GIL */ if (runtime->finalizing != NULL && !_Py_CURRENTLY_FINALIZING(runtime, tstate)) { drop_gil(&runtime->ceval, tstate); @@ -283,7 +285,7 @@ PyEval_AcquireLock(void) Py_FatalError("PyEval_AcquireLock: current thread state is NULL"); } take_gil(ceval, tstate); - exit_thread_if_finalizing(runtime, tstate); + exit_thread_if_finalizing(tstate); } void @@ -305,13 +307,13 @@ PyEval_AcquireThread(PyThreadState *tstate) Py_FatalError("PyEval_AcquireThread: NULL new thread state"); } - _PyRuntimeState *runtime = &_PyRuntime; + _PyRuntimeState *runtime = tstate->interp->runtime; struct _ceval_runtime_state *ceval = &runtime->ceval; /* Check someone has called PyEval_InitThreads() to create the lock */ assert(gil_created(&ceval->gil)); take_gil(ceval, tstate); - exit_thread_if_finalizing(runtime, tstate); + exit_thread_if_finalizing(tstate); if (_PyThreadState_Swap(&runtime->gilstate, tstate) != NULL) { Py_FatalError("PyEval_AcquireThread: non-NULL old thread state"); } @@ -324,7 +326,7 @@ PyEval_ReleaseThread(PyThreadState *tstate) Py_FatalError("PyEval_ReleaseThread: NULL thread state"); } - _PyRuntimeState *runtime = &_PyRuntime; + _PyRuntimeState *runtime = tstate->interp->runtime; PyThreadState *new_tstate = _PyThreadState_Swap(&runtime->gilstate, NULL); if (new_tstate != tstate) { Py_FatalError("PyEval_ReleaseThread: wrong thread state"); @@ -384,7 +386,7 @@ PyEval_SaveThread(void) void PyEval_RestoreThread(PyThreadState *tstate) { - _PyRuntimeState *runtime = &_PyRuntime; + _PyRuntimeState *runtime = tstate->interp->runtime; struct _ceval_runtime_state *ceval = &runtime->ceval; if (tstate == NULL) { @@ -394,7 +396,7 @@ PyEval_RestoreThread(PyThreadState *tstate) int err = errno; take_gil(ceval, tstate); - exit_thread_if_finalizing(runtime, tstate); + exit_thread_if_finalizing(tstate); errno = err; _PyThreadState_Swap(&runtime->gilstate, tstate); @@ -649,7 +651,8 @@ _PyEval_Initialize(struct _ceval_runtime_state *state) int Py_GetRecursionLimit(void) { - return _PyRuntime.ceval.recursion_limit; + struct _ceval_runtime_state *ceval = &_PyRuntime.ceval; + return ceval->recursion_limit; } void @@ -668,7 +671,7 @@ Py_SetRecursionLimit(int new_limit) int _Py_CheckRecursiveCall(PyThreadState *tstate, const char *where) { - _PyRuntimeState *runtime = &_PyRuntime; + _PyRuntimeState *runtime = tstate->interp->runtime; int recursion_limit = runtime->ceval.recursion_limit; #ifdef USE_STACKCHECK @@ -1245,7 +1248,7 @@ main_loop: take_gil(ceval, tstate); /* Check if we should make a quick exit. */ - exit_thread_if_finalizing(runtime, tstate); + exit_thread_if_finalizing(tstate); if (_PyThreadState_Swap(&runtime->gilstate, tstate) != NULL) { Py_FatalError("ceval: orphan tstate"); @@ -4806,7 +4809,8 @@ _PyEval_GetAsyncGenFinalizer(void) static PyFrameObject * _PyEval_GetFrame(PyThreadState *tstate) { - return _PyRuntime.gilstate.getframe(tstate); + _PyRuntimeState *runtime = tstate->interp->runtime; + return runtime->gilstate.getframe(tstate); } PyFrameObject * diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 9739bb15418..edff7f8f5e2 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -547,7 +547,7 @@ pycore_create_interpreter(_PyRuntimeState *runtime, _PyEval_FiniThreads(&runtime->ceval); /* Auto-thread-state API */ - _PyGILState_Init(runtime, tstate); + _PyGILState_Init(tstate); /* Create the GIL */ PyEval_InitThreads(); @@ -558,11 +558,11 @@ pycore_create_interpreter(_PyRuntimeState *runtime, static PyStatus -pycore_init_types(_PyRuntimeState *runtime) +pycore_init_types(PyThreadState *tstate) { PyStatus status; - status = _PyGC_Init(runtime); + status = _PyGC_Init(tstate); if (_PyStatus_EXCEPTION(status)) { return status; } @@ -690,13 +690,13 @@ pyinit_config(_PyRuntimeState *runtime, config = &tstate->interp->config; *tstate_p = tstate; - status = pycore_init_types(runtime); + status = pycore_init_types(tstate); if (_PyStatus_EXCEPTION(status)) { return status; } PyObject *sysmod; - status = _PySys_Create(runtime, tstate, &sysmod); + status = _PySys_Create(tstate, &sysmod); if (_PyStatus_EXCEPTION(status)) { return status; } @@ -915,8 +915,9 @@ _Py_ReconfigureMainInterpreter(PyInterpreterState *interp) * non-zero return code. */ static PyStatus -pyinit_main(_PyRuntimeState *runtime, PyThreadState *tstate) +pyinit_main(PyThreadState *tstate) { + _PyRuntimeState *runtime = tstate->interp->runtime; if (!runtime->core_initialized) { return _PyStatus_ERR("runtime core not initialized"); } @@ -943,7 +944,7 @@ pyinit_main(_PyRuntimeState *runtime, PyThreadState *tstate) return _PyStatus_ERR("can't initialize time"); } - if (_PySys_InitMain(runtime, tstate) < 0) { + if (_PySys_InitMain(tstate) < 0) { return _PyStatus_ERR("can't finish initializing sys"); } @@ -1022,7 +1023,7 @@ _Py_InitializeMain(void) } _PyRuntimeState *runtime = &_PyRuntime; PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime); - return pyinit_main(runtime, tstate); + return pyinit_main(tstate); } @@ -1049,7 +1050,7 @@ Py_InitializeFromConfig(const PyConfig *config) config = &tstate->interp->config; if (config->_init_main) { - status = pyinit_main(runtime, tstate); + status = pyinit_main(tstate); if (_PyStatus_EXCEPTION(status)) { return status; } @@ -1454,7 +1455,7 @@ new_interpreter(PyThreadState **tstate_p) } config = &interp->config; - status = pycore_init_types(runtime); + status = pycore_init_types(tstate); /* XXX The following is lax in error checking */ PyObject *modules = PyDict_New(); @@ -1471,7 +1472,7 @@ new_interpreter(PyThreadState **tstate_p) } Py_INCREF(interp->sysdict); PyDict_SetItemString(interp->sysdict, "modules", modules); - if (_PySys_InitMain(runtime, tstate) < 0) { + if (_PySys_InitMain(tstate) < 0) { return _PyStatus_ERR("can't finish initializing sys"); } } diff --git a/Python/pystate.c b/Python/pystate.c index 06cc9a8fb44..99f93bb77c7 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -39,7 +39,6 @@ extern "C" { /* Forward declarations */ static PyThreadState *_PyGILState_GetThisThreadState(struct _gilstate_runtime_state *gilstate); -static void _PyThreadState_Delete(_PyRuntimeState *runtime, PyThreadState *tstate); static PyStatus @@ -205,6 +204,9 @@ PyInterpreterState_New(void) memset(interp, 0, sizeof(*interp)); interp->id_refcount = -1; + _PyRuntimeState *runtime = &_PyRuntime; + interp->runtime = runtime; + PyConfig_InitPythonConfig(&interp->config); interp->eval_frame = _PyEval_EvalFrameDefault; @@ -216,7 +218,6 @@ PyInterpreterState_New(void) #endif #endif - _PyRuntimeState *runtime = &_PyRuntime; struct pyinterpreters *interpreters = &runtime->interpreters; HEAD_LOCK(runtime); @@ -250,9 +251,11 @@ PyInterpreterState_New(void) } -static void -_PyInterpreterState_Clear(_PyRuntimeState *runtime, PyInterpreterState *interp) +void +PyInterpreterState_Clear(PyInterpreterState *interp) { + _PyRuntimeState *runtime = interp->runtime; + if (PySys_Audit("cpython.PyInterpreterState_Clear", NULL) < 0) { PyErr_Clear(); } @@ -290,31 +293,25 @@ _PyInterpreterState_Clear(_PyRuntimeState *runtime, PyInterpreterState *interp) // objects have been cleaned up at the point. } -void -PyInterpreterState_Clear(PyInterpreterState *interp) -{ - _PyInterpreterState_Clear(&_PyRuntime, interp); -} - static void -zapthreads(_PyRuntimeState *runtime, PyInterpreterState *interp) +zapthreads(PyInterpreterState *interp) { PyThreadState *p; /* No need to lock the mutex here because this should only happen when the threads are all really dead (XXX famous last words). */ while ((p = interp->tstate_head) != NULL) { - _PyThreadState_Delete(runtime, p); + PyThreadState_Delete(p); } } -static void -_PyInterpreterState_Delete(_PyRuntimeState *runtime, - PyInterpreterState *interp) +void +PyInterpreterState_Delete(PyInterpreterState *interp) { + _PyRuntimeState *runtime = interp->runtime; struct pyinterpreters *interpreters = &runtime->interpreters; - zapthreads(runtime, interp); + zapthreads(interp); HEAD_LOCK(runtime); PyInterpreterState **p; for (p = &interpreters->head; ; p = &(*p)->next) { @@ -343,13 +340,6 @@ _PyInterpreterState_Delete(_PyRuntimeState *runtime, } -void -PyInterpreterState_Delete(PyInterpreterState *interp) -{ - _PyInterpreterState_Delete(&_PyRuntime, interp); -} - - /* * Delete all interpreter states except the main interpreter. If there * is a current interpreter state, it *must* be the main interpreter. @@ -376,8 +366,8 @@ _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime) continue; } - _PyInterpreterState_Clear(runtime, interp); // XXX must activate? - zapthreads(runtime, interp); + PyInterpreterState_Clear(interp); // XXX must activate? + zapthreads(interp); if (interp->id_mutex != NULL) { PyThread_free_lock(interp->id_mutex); } @@ -552,7 +542,7 @@ threadstate_getframe(PyThreadState *self) static PyThreadState * new_threadstate(PyInterpreterState *interp, int init) { - _PyRuntimeState *runtime = &_PyRuntime; + _PyRuntimeState *runtime = interp->runtime; PyThreadState *tstate = (PyThreadState *)PyMem_RawMalloc(sizeof(PyThreadState)); if (tstate == NULL) { return NULL; @@ -608,7 +598,7 @@ new_threadstate(PyInterpreterState *interp, int init) tstate->id = ++interp->tstate_next_unique_id; if (init) { - _PyThreadState_Init(runtime, tstate); + _PyThreadState_Init(tstate); } HEAD_LOCK(runtime); @@ -635,9 +625,9 @@ _PyThreadState_Prealloc(PyInterpreterState *interp) } void -_PyThreadState_Init(_PyRuntimeState *runtime, PyThreadState *tstate) +_PyThreadState_Init(PyThreadState *tstate) { - _PyGILState_NoteThreadState(&runtime->gilstate, tstate); + _PyGILState_NoteThreadState(&tstate->interp->runtime->gilstate, tstate); } PyObject* @@ -803,8 +793,9 @@ PyThreadState_Clear(PyThreadState *tstate) /* Common code for PyThreadState_Delete() and PyThreadState_DeleteCurrent() */ static void -tstate_delete_common(_PyRuntimeState *runtime, PyThreadState *tstate) +tstate_delete_common(PyThreadState *tstate) { + _PyRuntimeState *runtime = tstate->interp->runtime; if (tstate == NULL) { Py_FatalError("PyThreadState_Delete: NULL tstate"); } @@ -827,10 +818,10 @@ tstate_delete_common(_PyRuntimeState *runtime, PyThreadState *tstate) } -static void -_PyThreadState_Delete(_PyRuntimeState *runtime, PyThreadState *tstate) +void +PyThreadState_Delete(PyThreadState *tstate) { - struct _gilstate_runtime_state *gilstate = &runtime->gilstate; + struct _gilstate_runtime_state *gilstate = &tstate->interp->runtime->gilstate; if (tstate == _PyRuntimeGILState_GetThreadState(gilstate)) { Py_FatalError("PyThreadState_Delete: tstate is still current"); } @@ -839,14 +830,7 @@ _PyThreadState_Delete(_PyRuntimeState *runtime, PyThreadState *tstate) { PyThread_tss_set(&gilstate->autoTSSkey, NULL); } - tstate_delete_common(runtime, tstate); -} - - -void -PyThreadState_Delete(PyThreadState *tstate) -{ - _PyThreadState_Delete(&_PyRuntime, tstate); + tstate_delete_common(tstate); } @@ -858,7 +842,7 @@ _PyThreadState_DeleteCurrent(_PyRuntimeState *runtime) if (tstate == NULL) Py_FatalError( "PyThreadState_DeleteCurrent: no current tstate"); - tstate_delete_common(runtime, tstate); + tstate_delete_common(tstate); if (gilstate->autoInterpreterState && PyThread_tss_get(&gilstate->autoTSSkey) == tstate) { @@ -1134,13 +1118,13 @@ PyThreadState_IsCurrent(PyThreadState *tstate) Py_Initialize/Py_FinalizeEx */ void -_PyGILState_Init(_PyRuntimeState *runtime, PyThreadState *tstate) +_PyGILState_Init(PyThreadState *tstate) { /* must init with valid states */ assert(tstate != NULL); assert(tstate->interp != NULL); - struct _gilstate_runtime_state *gilstate = &runtime->gilstate; + struct _gilstate_runtime_state *gilstate = &tstate->interp->runtime->gilstate; if (PyThread_tss_create(&gilstate->autoTSSkey) != 0) { Py_FatalError("Could not allocate TSS entry"); diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 92935408a58..30c7e987461 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2387,17 +2387,18 @@ static PyStructSequence_Desc flags_desc = { }; static PyObject* -make_flags(_PyRuntimeState *runtime, PyThreadState *tstate) +make_flags(PyThreadState *tstate) { - int pos = 0; - PyObject *seq; - const PyPreConfig *preconfig = &runtime->preconfig; - const PyConfig *config = &tstate->interp->config; + PyInterpreterState *interp = tstate->interp; + const PyPreConfig *preconfig = &interp->runtime->preconfig; + const PyConfig *config = &interp->config; - seq = PyStructSequence_New(&FlagsType); - if (seq == NULL) + PyObject *seq = PyStructSequence_New(&FlagsType); + if (seq == NULL) { return NULL; + } + int pos = 0; #define SetFlag(flag) \ PyStructSequence_SET_ITEM(seq, pos++, PyLong_FromLong(flag)) @@ -2607,8 +2608,7 @@ static struct PyModuleDef sysmodule = { } while (0) static PyStatus -_PySys_InitCore(_PyRuntimeState *runtime, PyThreadState *tstate, - PyObject *sysdict) +_PySys_InitCore(PyThreadState *tstate, PyObject *sysdict) { PyObject *version_info; int res; @@ -2703,7 +2703,7 @@ _PySys_InitCore(_PyRuntimeState *runtime, PyThreadState *tstate, } } /* Set flags to their default values (updated by _PySys_InitMain()) */ - SET_SYS_FROM_STRING("flags", make_flags(runtime, tstate)); + SET_SYS_FROM_STRING("flags", make_flags(tstate)); #if defined(MS_WINDOWS) /* getwindowsversion */ @@ -2824,7 +2824,7 @@ sys_create_xoptions_dict(const PyConfig *config) int -_PySys_InitMain(_PyRuntimeState *runtime, PyThreadState *tstate) +_PySys_InitMain(PyThreadState *tstate) { PyObject *sysdict = tstate->interp->sysdict; const PyConfig *config = &tstate->interp->config; @@ -2879,7 +2879,7 @@ _PySys_InitMain(_PyRuntimeState *runtime, PyThreadState *tstate) #undef SET_SYS_FROM_WSTR /* Set flags to their final values */ - SET_SYS_FROM_STRING_INT_RESULT("flags", make_flags(runtime, tstate)); + SET_SYS_FROM_STRING_INT_RESULT("flags", make_flags(tstate)); /* prevent user from creating new instances */ FlagsType.tp_init = NULL; FlagsType.tp_new = NULL; @@ -2944,8 +2944,7 @@ error: /* Create sys module without all attributes: _PySys_InitMain() should be called later to add remaining attributes. */ PyStatus -_PySys_Create(_PyRuntimeState *runtime, PyThreadState *tstate, - PyObject **sysmod_p) +_PySys_Create(PyThreadState *tstate, PyObject **sysmod_p) { PyInterpreterState *interp = tstate->interp; @@ -2976,7 +2975,7 @@ _PySys_Create(_PyRuntimeState *runtime, PyThreadState *tstate, return status; } - status = _PySys_InitCore(runtime, tstate, sysdict); + status = _PySys_InitCore(tstate, sysdict); if (_PyStatus_EXCEPTION(status)) { return status; }