From 7c7e2b22e851e698155df9e91bed19886637b5c7 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 25 Oct 2021 16:12:14 +0100 Subject: [PATCH 1/7] Use a thread-local variable to store a pointer to the interpreter-state. --- Include/internal/pycore_long.h | 9 +++++---- Include/internal/pycore_pystate.h | 29 +++++++++++++++-------------- Include/internal/pycore_tls.h | 18 ++++++++++++++++++ Makefile.pre.in | 1 + Modules/_functoolsmodule.c | 2 +- Modules/_io/_iomodule.c | 8 ++++---- Modules/_io/textio.c | 6 +++--- Modules/_threadmodule.c | 8 ++++---- Modules/atexitmodule.c | 4 ++-- Modules/gcmodule.c | 2 +- Modules/main.c | 4 ++-- Modules/posixmodule.c | 16 ++++++++-------- Modules/signalmodule.c | 7 +++---- Objects/complexobject.c | 2 +- Objects/floatobject.c | 7 +++---- Objects/frameobject.c | 2 +- Objects/longobject.c | 10 +++++++++- Objects/rangeobject.c | 14 +++++++------- Objects/sliceobject.c | 2 +- Objects/unicodeobject.c | 2 +- Parser/asdl_c.py | 4 ++-- Python/Python-ast.c | 4 ++-- Python/_warnings.c | 4 ++-- Python/ceval.c | 4 ++-- Python/compile.c | 4 ++-- Python/pystate.c | 21 ++++++++++++++++++--- 26 files changed, 118 insertions(+), 76 deletions(-) create mode 100644 Include/internal/pycore_tls.h diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index 8bdf8e5736d20b..964b3cab148f61 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -26,13 +26,14 @@ static inline PyObject* __PyLong_GetSmallInt_internal(int value) // Return a borrowed reference to the zero singleton. // The function cannot return NULL. -static inline PyObject* _PyLong_GetZero(void) -{ return __PyLong_GetSmallInt_internal(0); } +PyAPI_FUNC(PyObject*) _PyLong_GetZero(void); // Return a borrowed reference to the one singleton. // The function cannot return NULL. -static inline PyObject* _PyLong_GetOne(void) -{ return __PyLong_GetSmallInt_internal(1); } +PyAPI_FUNC(PyObject*) _PyLong_GetOne(void); + +#define PY_ZERO() ((PyObject *)_PyInterpreterState_GET()->small_ints[_PY_NSMALLNEGINTS]) +#define PY_ONE() ((PyObject *)_PyInterpreterState_GET()->small_ints[_PY_NSMALLNEGINTS+1]) PyObject *_PyLong_Add(PyLongObject *left, PyLongObject *right); PyObject *_PyLong_Multiply(PyLongObject *left, PyLongObject *right); diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index 9a570b08bc5839..be6657405d2760 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -8,6 +8,7 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif +#include "pycore_tls.h" /* PyRuntimeState */ #include "pycore_runtime.h" /* PyRuntimeState */ @@ -20,15 +21,8 @@ _Py_IsMainThread(void) return (thread == _PyRuntime.main_thread); } - -static inline int -_Py_IsMainInterpreter(PyInterpreterState *interp) -{ - /* Use directly _PyRuntime rather than tstate->interp->runtime, since - this function is used in performance critical code path (ceval) */ - return (interp == _PyRuntime.interpreters.main); -} - +extern int +_Py_IsMainInterpreter(PyInterpreterState *interp); static inline const PyConfig * _Py_GetMainConfig(void) @@ -40,6 +34,9 @@ _Py_GetMainConfig(void) return _PyInterpreterState_GetConfig(interp); } +#ifdef _Py_THREAD_LOCAL +extern _Py_THREAD_LOCAL PyInterpreterState *_py_current_interpreter; +#endif /* Only handle signals on the main thread of the main interpreter. */ static inline int @@ -107,7 +104,6 @@ _Py_EnsureFuncTstateNotNULL(const char *func, PyThreadState *tstate) #define _Py_EnsureTstateNotNULL(tstate) \ _Py_EnsureFuncTstateNotNULL(__func__, tstate) - /* Get the current interpreter state. The macro is unsafe: it does not check for error and it can return NULL. @@ -116,14 +112,19 @@ _Py_EnsureFuncTstateNotNULL(const char *func, PyThreadState *tstate) See also _PyInterpreterState_Get() and _PyGILState_GetInterpreterStateUnsafe(). */ +#ifdef _Py_THREAD_LOCAL +#define _PyInterpreterState_GET() _py_current_interpreter +#else static inline PyInterpreterState* _PyInterpreterState_GET(void) { PyThreadState *tstate = _PyThreadState_GET(); -#ifdef Py_DEBUG _Py_EnsureTstateNotNULL(tstate); -#endif - return tstate->interp; + PyInterpreterState *interp = tstate->interp; + if (interp == NULL) { + Py_FatalError("no current interpreter"); + } + return interp; } - +#endif // PyThreadState functions diff --git a/Include/internal/pycore_tls.h b/Include/internal/pycore_tls.h new file mode 100644 index 00000000000000..eba3733ee6d896 --- /dev/null +++ b/Include/internal/pycore_tls.h @@ -0,0 +1,18 @@ + +#ifndef Py_CORE_TLS_H +#define Py_CORE_TLS_H + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE to be defined" +#endif + +#ifndef _Py_THREAD_LOCAL +#if defined(__GNUC__) +#define _Py_THREAD_LOCAL __thread +#endif +#if defined(_MSC_VER) +#define _Py_THREAD_LOCAL __declspec(thread) +#endif +#endif + +#endif /* Py_CORE_TLS_H */ diff --git a/Makefile.pre.in b/Makefile.pre.in index 4ee8fddbe14eef..c9b9e30afe9c43 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1273,6 +1273,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_structseq.h \ $(srcdir)/Include/internal/pycore_symtable.h \ $(srcdir)/Include/internal/pycore_sysmodule.h \ + $(srcdir)/Include/internal/pycore_tls.h \ $(srcdir)/Include/internal/pycore_traceback.h \ $(srcdir)/Include/internal/pycore_tuple.h \ $(srcdir)/Include/internal/pycore_ucnhash.h \ diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index 1f6b852f6d99b5..1a485ed11f8266 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -703,7 +703,7 @@ functools_reduce(PyObject *self, PyObject *args) // bpo-42536: The GC may have untracked this args tuple. Since we're // recycling it, make sure it's tracked again: if (!_PyObject_GC_IS_TRACKED(args)) { - _PyObject_GC_TRACK(args); + PyObject_GC_Track(args); } } } diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index b4743fbd5e04f0..00bcc571c95b03 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -10,7 +10,7 @@ #define PY_SSIZE_T_CLEAN #include "Python.h" #include "_iomodule.h" -#include "pycore_pystate.h" // _PyInterpreterState_GET() +#include "pycore_pystate.h" // PyInterpreterState_Get() #ifdef HAVE_SYS_TYPES_H #include @@ -91,7 +91,7 @@ PyDoc_STRVAR(module_doc, " I/O classes. open() uses the file's blksize (as obtained by os.stat) if\n" " possible.\n" ); - + /* * The main open() function @@ -509,7 +509,7 @@ _io_text_encoding_impl(PyObject *module, PyObject *encoding, int stacklevel) /*[clinic end generated code: output=91b2cfea6934cc0c input=bf70231213e2a7b4]*/ { if (encoding == NULL || encoding == Py_None) { - PyInterpreterState *interp = _PyInterpreterState_GET(); + PyInterpreterState *interp = PyInterpreterState_Get(); if (_PyInterpreterState_GetConfig(interp)->warn_default_encoding) { if (PyErr_WarnEx(PyExc_EncodingWarning, "'encoding' argument not specified", stacklevel)) { @@ -542,7 +542,7 @@ _io_open_code_impl(PyObject *module, PyObject *path) { return PyFile_OpenCodeObject(path); } - + /* * Private helpers for the io module. */ diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index eb05ae1a16eb03..edf252414fa922 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -12,7 +12,7 @@ #include "pycore_long.h" // _PyLong_GetZero() #include "pycore_fileutils.h" // _Py_GetLocaleEncoding() #include "pycore_object.h" -#include "pycore_pystate.h" // _PyInterpreterState_GET() +#include "pycore_pystate.h" // PyInterpreterState_Get() #include "structmember.h" // PyMemberDef #include "_iomodule.h" @@ -996,7 +996,7 @@ io_check_errors(PyObject *errors) { assert(errors != NULL && errors != Py_None); - PyInterpreterState *interp = _PyInterpreterState_GET(); + PyInterpreterState *interp = PyInterpreterState_Get(); #ifndef Py_DEBUG /* In release mode, only check in development mode (-X dev) */ if (!_PyInterpreterState_GetConfig(interp)->dev_mode) { @@ -1086,7 +1086,7 @@ _io_TextIOWrapper___init___impl(textio *self, PyObject *buffer, self->detached = 0; if (encoding == NULL) { - PyInterpreterState *interp = _PyInterpreterState_GET(); + PyInterpreterState *interp = PyInterpreterState_Get(); if (_PyInterpreterState_GetConfig(interp)->warn_default_encoding) { if (PyErr_WarnEx(PyExc_EncodingWarning, "'encoding' argument not specified", 1)) { diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index 39b116afcaa3e1..5cb61bfc03e288 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -850,7 +850,7 @@ local_clear(localobject *self) Py_CLEAR(self->wr_callback); /* Remove all strong references to dummies from the thread states */ if (self->key) { - PyInterpreterState *interp = _PyInterpreterState_GET(); + PyInterpreterState *interp = PyInterpreterState_Get(); PyThreadState *tstate = PyInterpreterState_ThreadHead(interp); for(; tstate; tstate = PyThreadState_Next(tstate)) { if (tstate->dict == NULL) { @@ -1139,7 +1139,7 @@ thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs) return NULL; } - PyInterpreterState *interp = _PyInterpreterState_GET(); + PyInterpreterState *interp = PyInterpreterState_Get(); if (interp->config._isolated_interpreter) { PyErr_SetString(PyExc_RuntimeError, "thread is not supported for isolated subinterpreters"); @@ -1150,7 +1150,7 @@ thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs) if (boot == NULL) { return PyErr_NoMemory(); } - boot->interp = _PyInterpreterState_GET(); + boot->interp = PyInterpreterState_Get(); boot->tstate = _PyThreadState_Prealloc(boot->interp); if (boot->tstate == NULL) { PyMem_Free(boot); @@ -1278,7 +1278,7 @@ particular thread within a system."); static PyObject * thread__count(PyObject *self, PyObject *Py_UNUSED(ignored)) { - PyInterpreterState *interp = _PyInterpreterState_GET(); + PyInterpreterState *interp = PyInterpreterState_Get(); return PyLong_FromLong(interp->num_threads); } diff --git a/Modules/atexitmodule.c b/Modules/atexitmodule.c index e536b4abe295f0..7fd5d9b08ec322 100644 --- a/Modules/atexitmodule.c +++ b/Modules/atexitmodule.c @@ -9,7 +9,7 @@ #include "Python.h" #include "pycore_initconfig.h" // _PyStatus_NO_MEMORY #include "pycore_interp.h" // PyInterpreterState.atexit -#include "pycore_pystate.h" // _PyInterpreterState_GET +#include "pycore_pystate.h" // PyInterpreterState_Get /* ===================================================================== */ /* Callback machinery. */ @@ -17,7 +17,7 @@ static inline struct atexit_state* get_atexit_state(void) { - PyInterpreterState *interp = _PyInterpreterState_GET(); + PyInterpreterState *interp = PyInterpreterState_Get(); return &interp->atexit; } diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 7d1a45bcaeabf8..f7104e1cbda8e8 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -131,7 +131,7 @@ gc_decref(PyGC_Head *g) static GCState * get_gc_state(void) { - PyInterpreterState *interp = _PyInterpreterState_GET(); + PyInterpreterState *interp = PyInterpreterState_Get(); return &interp->gc; } diff --git a/Modules/main.c b/Modules/main.c index c537e6b678515e..001a7ab74b605a 100644 --- a/Modules/main.c +++ b/Modules/main.c @@ -6,7 +6,7 @@ #include "pycore_interp.h" // _PyInterpreterState.sysdict #include "pycore_pathconfig.h" // _PyPathConfig_ComputeSysPath0() #include "pycore_pylifecycle.h" // _Py_PreInitializeFromPyArgv() -#include "pycore_pystate.h" // _PyInterpreterState_GET() +#include "pycore_pystate.h" // PyInterpreterState_Get() /* Includes for exit_sigint() */ #include // perror() @@ -534,7 +534,7 @@ pymain_repl(PyConfig *config, int *exitcode) static void pymain_run_python(int *exitcode) { - PyInterpreterState *interp = _PyInterpreterState_GET(); + PyInterpreterState *interp = PyInterpreterState_Get(); /* pymain_run_stdin() modify the config */ PyConfig *config = (PyConfig*)_PyInterpreterState_GetConfig(interp); diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 667a3339f5ba8e..ebad9970dfec24 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -27,7 +27,7 @@ #include "pycore_ceval.h" // _PyEval_ReInitThreads() #include "pycore_import.h" // _PyImport_ReInitLock() #include "pycore_initconfig.h" // _PyStatus_EXCEPTION() -#include "pycore_pystate.h" // _PyInterpreterState_GET() +#include "pycore_pystate.h" // PyInterpreterState_Get() #include "structmember.h" // PyMemberDef #ifndef MS_WINDOWS @@ -575,7 +575,7 @@ run_at_forkers(PyObject *lst, int reverse) void PyOS_BeforeFork(void) { - run_at_forkers(_PyInterpreterState_GET()->before_forkers, 1); + run_at_forkers(PyInterpreterState_Get()->before_forkers, 1); _PyImport_AcquireLock(); } @@ -586,7 +586,7 @@ PyOS_AfterFork_Parent(void) if (_PyImport_ReleaseLock() <= 0) Py_FatalError("failed releasing import lock after fork"); - run_at_forkers(_PyInterpreterState_GET()->after_forkers_parent, 0); + run_at_forkers(PyInterpreterState_Get()->after_forkers_parent, 0); } void @@ -6650,7 +6650,7 @@ os_register_at_fork_impl(PyObject *module, PyObject *before, check_null_or_callable(after_in_parent, "after_in_parent")) { return NULL; } - interp = _PyInterpreterState_GET(); + interp = PyInterpreterState_Get(); if (register_at_forker(&interp->before_forkers, before)) { return NULL; @@ -6680,8 +6680,8 @@ os_fork1_impl(PyObject *module) /*[clinic end generated code: output=0de8e67ce2a310bc input=12db02167893926e]*/ { pid_t pid; - - if (_PyInterpreterState_GET() != PyInterpreterState_Main()) { + PyInterpreterState *interp = PyInterpreterState_Get(); + if (_Py_IsMainInterpreter(interp)) { PyErr_SetString(PyExc_RuntimeError, "fork not supported for subinterpreters"); return NULL; } @@ -6715,7 +6715,7 @@ os_fork_impl(PyObject *module) /*[clinic end generated code: output=3626c81f98985d49 input=13c956413110eeaa]*/ { pid_t pid; - PyInterpreterState *interp = _PyInterpreterState_GET(); + PyInterpreterState *interp = PyInterpreterState_Get(); if (interp->config._isolated_interpreter) { PyErr_SetString(PyExc_RuntimeError, "fork not supported for isolated subinterpreters"); @@ -7333,7 +7333,7 @@ os_forkpty_impl(PyObject *module) int master_fd = -1; pid_t pid; - if (_PyInterpreterState_GET() != PyInterpreterState_Main()) { + if (PyInterpreterState_Get() != PyInterpreterState_Main()) { PyErr_SetString(PyExc_RuntimeError, "fork not supported for subinterpreters"); return NULL; } diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index 09f4aed9d5ca9a..f668f5c9554768 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -1655,8 +1655,8 @@ signal_module_exec(PyObject *m) } #endif - PyThreadState *tstate = _PyThreadState_GET(); - if (_Py_IsMainInterpreter(tstate->interp)) { + PyInterpreterState *interp = PyInterpreterState_Get(); + if (_Py_IsMainInterpreter(interp)) { if (signal_get_set_handlers(state, d) < 0) { return -1; } @@ -2032,8 +2032,7 @@ _PySignal_AfterFork(void) int _PyOS_IsMainThread(void) { - PyInterpreterState *interp = _PyInterpreterState_GET(); - return _Py_ThreadCanHandleSignals(interp); + return _Py_ThreadCanHandleSignals(PyInterpreterState_Get()); } #ifdef MS_WINDOWS diff --git a/Objects/complexobject.c b/Objects/complexobject.c index f658dbf336dbf5..3eaa3b7ee5e3b4 100644 --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -907,7 +907,7 @@ complex_new_impl(PyTypeObject *type, PyObject *r, PyObject *i) int ci_is_complex = 0; if (r == NULL) { - r = _PyLong_GetZero(); + r = PY_ZERO(); } /* Special-case for a single argument when type(arg) is complex. */ diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 7fc192e7201171..c1c2c158c0a9ac 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -29,11 +29,10 @@ class float "PyObject *" "&PyFloat_Type" #if PyFloat_MAXFREELIST > 0 -static struct _Py_float_state * +static inline struct _Py_float_state * get_float_state(void) { - PyInterpreterState *interp = _PyInterpreterState_GET(); - return &interp->float_state; + return &_PyInterpreterState_GET()->float_state; } #endif @@ -1630,7 +1629,7 @@ float_new_impl(PyTypeObject *type, PyObject *x) { if (type != &PyFloat_Type) { if (x == NULL) { - x = _PyLong_GetZero(); + x = PY_ZERO(); } return float_subtype_new(type, x); /* Wimp out */ } diff --git a/Objects/frameobject.c b/Objects/frameobject.c index ffe19b3d994007..f5288ae1eeaa43 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -20,7 +20,7 @@ static PyMemberDef frame_memberlist[] = { }; #if PyFrame_MAXFREELIST > 0 -static struct _Py_frame_state * +static inline struct _Py_frame_state * get_frame_state(void) { PyInterpreterState *interp = _PyInterpreterState_GET(); diff --git a/Objects/longobject.c b/Objects/longobject.c index 5325d1852bc029..0ac07f863a8e0e 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -2608,7 +2608,7 @@ long_divrem(PyLongObject *a, PyLongObject *b, if (*prem == NULL) { return -1; } - PyObject *zero = _PyLong_GetZero(); + PyObject *zero = PY_ZERO(); Py_INCREF(zero); *pdiv = (PyLongObject*)zero; return 0; @@ -5867,3 +5867,11 @@ _PyLong_Fini(PyInterpreterState *interp) Py_CLEAR(interp->small_ints[i]); } } + +PyObject* _PyLong_GetZero(void) { + return PY_ZERO(); +} + +PyObject* _PyLong_GetOne(void) { + return PY_ONE(); +} diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index a848d67a65152e..1a99fa3fff9fef 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -191,8 +191,8 @@ compute_range_length(PyObject *start, PyObject *stop, PyObject *step) PyObject *tmp1 = NULL, *tmp2 = NULL, *result; /* holds sub-expression evaluations */ - PyObject *zero = _PyLong_GetZero(); // borrowed reference - PyObject *one = _PyLong_GetOne(); // borrowed reference + PyObject *zero = PY_ZERO(); // borrowed reference + PyObject *one = PY_ONE(); // borrowed reference cmp_result = PyObject_RichCompareBool(step, zero, Py_GT); if (cmp_result == -1) @@ -277,7 +277,7 @@ compute_item(rangeobject *r, PyObject *i) static PyObject * compute_range_item(rangeobject *r, PyObject *arg) { - PyObject *zero = _PyLong_GetZero(); // borrowed reference + PyObject *zero = PY_ZERO(); // borrowed reference int cmp_result; PyObject *i, *result; @@ -382,7 +382,7 @@ compute_slice(rangeobject *r, PyObject *_slice) static int range_contains_long(rangeobject *r, PyObject *ob) { - PyObject *zero = _PyLong_GetZero(); // borrowed reference + PyObject *zero = PY_ZERO(); // borrowed reference int cmp1, cmp2, cmp3; PyObject *tmp1 = NULL; PyObject *tmp2 = NULL; @@ -974,7 +974,7 @@ longrangeiter_reduce(longrangeiterobject *r, PyObject *Py_UNUSED(ignored)) static PyObject * longrangeiter_setstate(longrangeiterobject *r, PyObject *state) { - PyObject *zero = _PyLong_GetZero(); // borrowed reference + PyObject *zero = PY_ZERO(); // borrowed reference int cmp; /* clip the value */ @@ -1130,7 +1130,7 @@ range_iter(PyObject *seq) it->start = r->start; it->step = r->step; it->len = r->length; - it->index = _PyLong_GetZero(); + it->index = PY_ZERO(); Py_INCREF(it->start); Py_INCREF(it->step); Py_INCREF(it->len); @@ -1237,7 +1237,7 @@ range_reverse(PyObject *seq, PyObject *Py_UNUSED(ignored)) if (!it->step) goto create_failure; - it->index = _PyLong_GetZero(); + it->index = PY_ZERO(); Py_INCREF(it->index); return (PyObject *)it; diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c index 22fb7c61c354f9..10e31599800dad 100644 --- a/Objects/sliceobject.c +++ b/Objects/sliceobject.c @@ -417,7 +417,7 @@ _PySlice_GetLongIndices(PySliceObject *self, PyObject *length, goto error; } else { - lower = _PyLong_GetZero(); + lower = PY_ZERO(); Py_INCREF(lower); upper = length; Py_INCREF(upper); diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 61fc34d71da3ce..f75f87ce8c3b46 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -232,7 +232,7 @@ static int unicode_is_singleton(PyObject *unicode); #endif -static struct _Py_unicode_state* +static inline struct _Py_unicode_state* get_unicode_state(void) { PyInterpreterState *interp = _PyInterpreterState_GET(); diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py index 37925a5783d6d0..178301f334d868 100755 --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -1484,7 +1484,7 @@ def generate_module_def(mod, metadata, f, internal_h): #include "pycore_ast.h" #include "pycore_ast_state.h" // struct ast_state #include "pycore_interp.h" // _PyInterpreterState.ast - #include "pycore_pystate.h" // _PyInterpreterState_GET() + #include "pystate.h" // PyInterpreterState_Get() #include "structmember.h" #include @@ -1494,7 +1494,7 @@ def generate_module_def(mod, metadata, f, internal_h): static struct ast_state* get_ast_state(void) { - PyInterpreterState *interp = _PyInterpreterState_GET(); + PyInterpreterState *interp = PyInterpreterState_Get(); struct ast_state *state = &interp->ast; if (!init_types(state)) { return NULL; diff --git a/Python/Python-ast.c b/Python/Python-ast.c index ce6e6a93ea70f0..673859034a26ad 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -4,7 +4,7 @@ #include "pycore_ast.h" #include "pycore_ast_state.h" // struct ast_state #include "pycore_interp.h" // _PyInterpreterState.ast -#include "pycore_pystate.h" // _PyInterpreterState_GET() +#include "pystate.h" // PyInterpreterState_Get() #include "structmember.h" #include @@ -14,7 +14,7 @@ static int init_types(struct ast_state *state); static struct ast_state* get_ast_state(void) { - PyInterpreterState *interp = _PyInterpreterState_GET(); + PyInterpreterState *interp = PyInterpreterState_Get(); struct ast_state *state = &interp->ast; if (!init_types(state)) { return NULL; diff --git a/Python/_warnings.c b/Python/_warnings.c index cf2110d31c3b5e..0d52f88c37767d 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -72,7 +72,7 @@ create_filter(PyObject *category, _Py_Identifier *id, const char *modname) /* This assumes the line number is zero for now. */ PyObject *filter = PyTuple_Pack(5, action_str, Py_None, - category, modname_obj, _PyLong_GetZero()); + category, modname_obj, PY_ZERO()); Py_DECREF(modname_obj); return filter; } @@ -470,7 +470,7 @@ update_registry(PyObject *registry, PyObject *text, PyObject *category, int rc; if (add_zero) - altkey = PyTuple_Pack(3, text, category, _PyLong_GetZero()); + altkey = PyTuple_Pack(3, text, category, PY_ZERO()); else altkey = PyTuple_Pack(2, text, category); diff --git a/Python/ceval.c b/Python/ceval.c index adc7b536247b2e..6fcc49f9b72d8e 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2226,7 +2226,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr // Deopt unless 0 <= sub < PyList_Size(list) Py_ssize_t signed_magnitude = Py_SIZE(sub); DEOPT_IF(((size_t)signed_magnitude) > 1, BINARY_SUBSCR); - assert(((PyLongObject *)_PyLong_GetZero())->ob_digit[0] == 0); + assert(((PyLongObject *)PY_ZERO())->ob_digit[0] == 0); Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0]; DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -2249,7 +2249,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr // Deopt unless 0 <= sub < PyTuple_Size(list) Py_ssize_t signed_magnitude = Py_SIZE(sub); DEOPT_IF(((size_t)signed_magnitude) > 1, BINARY_SUBSCR); - assert(((PyLongObject *)_PyLong_GetZero())->ob_digit[0] == 0); + assert(((PyLongObject *)PY_ZERO())->ob_digit[0] == 0); Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0]; DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); diff --git a/Python/compile.c b/Python/compile.c index 0c025acec14914..70bb2c9c3951c6 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -672,7 +672,7 @@ compiler_enter_scope(struct compiler *c, identifier name, compiler_unit_free(u); return 0; } - res = PyDict_SetItem(u->u_cellvars, name, _PyLong_GetZero()); + res = PyDict_SetItem(u->u_cellvars, name, PY_ZERO()); if (res < 0) { compiler_unit_free(u); return 0; @@ -3436,7 +3436,7 @@ compiler_import(struct compiler *c, stmt_ty s) */ Py_ssize_t i, n = asdl_seq_LEN(s->v.Import.names); - PyObject *zero = _PyLong_GetZero(); // borrowed reference + PyObject *zero = PY_ZERO(); // borrowed reference for (i = 0; i < n; i++) { alias_ty alias = (alias_ty)asdl_seq_GET(s->v.Import.names, i); int r; diff --git a/Python/pystate.c b/Python/pystate.c index 7804e17a064e15..62d72d54a4b97f 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -464,9 +464,7 @@ _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime) PyInterpreterState * PyInterpreterState_Get(void) { - PyThreadState *tstate = _PyThreadState_GET(); - _Py_EnsureTstateNotNULL(tstate); - PyInterpreterState *interp = tstate->interp; + PyInterpreterState *interp = _PyInterpreterState_GET(); if (interp == NULL) { Py_FatalError("no current interpreter"); } @@ -1063,6 +1061,11 @@ _PyThreadState_Swap(struct _gilstate_runtime_state *gilstate, PyThreadState *new #endif _PyRuntimeGILState_SetThreadState(gilstate, newts); +#ifdef _Py_THREAD_LOCAL + if (newts != NULL) { + _py_current_interpreter = newts->interp; + } +#endif /* It should not be possible for more than one thread state to be used for a thread. Check this the best we can in debug builds. @@ -2109,6 +2112,18 @@ _PyThreadState_PopFrame(PyThreadState *tstate, InterpreterFrame * frame) } } +#ifdef _Py_THREAD_LOCAL +_Py_THREAD_LOCAL PyInterpreterState *_py_current_interpreter = NULL; +#endif + +int +_Py_IsMainInterpreter(PyInterpreterState *interp) +{ + /* Use directly _PyRuntime rather than tstate->interp->runtime, since + this function is used in performance critical code path (ceval) */ + return interp == _PyRuntime.interpreters.main; +} + #ifdef __cplusplus } From 73c410b801020992afbb94136ebcb3c52b9f2292 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 26 Oct 2021 13:39:34 +0100 Subject: [PATCH 2/7] Add NEWS --- .../Core and Builtins/2021-10-26-13-38-13.bpo-40512.ZUQPPC.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2021-10-26-13-38-13.bpo-40512.ZUQPPC.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-10-26-13-38-13.bpo-40512.ZUQPPC.rst b/Misc/NEWS.d/next/Core and Builtins/2021-10-26-13-38-13.bpo-40512.ZUQPPC.rst new file mode 100644 index 00000000000000..39708808660bbd --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2021-10-26-13-38-13.bpo-40512.ZUQPPC.rst @@ -0,0 +1,2 @@ +A pointer to the interpreter state is stored in a thread local variable +on platforms that support it. From f33f4a4e4b05a0ffeb214b71bda1c8a8b0bf3b08 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 28 Oct 2021 14:25:45 +0100 Subject: [PATCH 3/7] Revert erroneous change. --- Modules/posixmodule.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index ebad9970dfec24..c37691834ce1c2 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -6680,8 +6680,7 @@ os_fork1_impl(PyObject *module) /*[clinic end generated code: output=0de8e67ce2a310bc input=12db02167893926e]*/ { pid_t pid; - PyInterpreterState *interp = PyInterpreterState_Get(); - if (_Py_IsMainInterpreter(interp)) { + if (PyInterpreterState_Get() != PyInterpreterState_Main()) { PyErr_SetString(PyExc_RuntimeError, "fork not supported for subinterpreters"); return NULL; } From 55cc2e4868f702fdc43f807614e5fec47c0b6e92 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 28 Oct 2021 14:28:41 +0100 Subject: [PATCH 4/7] Fix misleading comment and formatting. --- Include/internal/pycore_pystate.h | 2 +- Objects/longobject.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index be6657405d2760..83c3cd43b4b41c 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -8,7 +8,7 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif -#include "pycore_tls.h" /* PyRuntimeState */ +#include "pycore_tls.h" /* Thread local storage */ #include "pycore_runtime.h" /* PyRuntimeState */ diff --git a/Objects/longobject.c b/Objects/longobject.c index 0ac07f863a8e0e..8640359c30af2b 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -5868,10 +5868,12 @@ _PyLong_Fini(PyInterpreterState *interp) } } -PyObject* _PyLong_GetZero(void) { +PyObject *_PyLong_GetZero(void) +{ return PY_ZERO(); } -PyObject* _PyLong_GetOne(void) { +PyObject *_PyLong_GetOne(void) +{ return PY_ONE(); } From 4b8335643fe7bf26f6d19f0ee85b4cbbb0e88eca Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 1 Nov 2021 12:24:40 +0000 Subject: [PATCH 5/7] Ensure that FatalError is raised for NULL interpreter state in debug builds. --- Include/internal/pycore_pystate.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index 83c3cd43b4b41c..9e0112637d17a5 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -113,11 +113,23 @@ _Py_EnsureFuncTstateNotNULL(const char *func, PyThreadState *tstate) See also _PyInterpreterState_Get() and _PyGILState_GetInterpreterStateUnsafe(). */ #ifdef _Py_THREAD_LOCAL +#ifdef Py_DEBUG +static inline PyInterpreterState* _PyInterpreterState_GET(void) { + PyInterpreterState *interp = _py_current_interpreter; + if (interp == NULL) { + Py_FatalError("no current interpreter"); + } + return interp; +} +#else #define _PyInterpreterState_GET() _py_current_interpreter +#endif #else static inline PyInterpreterState* _PyInterpreterState_GET(void) { PyThreadState *tstate = _PyThreadState_GET(); +#ifdef Py_DEBUG _Py_EnsureTstateNotNULL(tstate); +#endif PyInterpreterState *interp = tstate->interp; if (interp == NULL) { Py_FatalError("no current interpreter"); From 28bc0429ffb2e180b9a00a26ef79c4d551e06403 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 1 Nov 2021 12:34:19 +0000 Subject: [PATCH 6/7] Fixup PY_ZERO and PY_ONE macros. --- Include/internal/pycore_long.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index 659ac891c770f7..6697fcbdcd6df1 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -32,8 +32,8 @@ PyAPI_FUNC(PyObject*) _PyLong_GetZero(void); // The function cannot return NULL. PyAPI_FUNC(PyObject*) _PyLong_GetOne(void); -#define PY_ZERO() ((PyObject *)_PyInterpreterState_GET()->small_ints[_PY_NSMALLNEGINTS]) -#define PY_ONE() ((PyObject *)_PyInterpreterState_GET()->small_ints[_PY_NSMALLNEGINTS+1]) +#define PY_ZERO() ((PyObject *)&_PyInterpreterState_GET()->small_ints[_PY_NSMALLNEGINTS]) +#define PY_ONE() ((PyObject *)&_PyInterpreterState_GET()->small_ints[_PY_NSMALLNEGINTS+1]) PyObject *_PyLong_Add(PyLongObject *left, PyLongObject *right); PyObject *_PyLong_Multiply(PyLongObject *left, PyLongObject *right); From 3982884a299baf93984e98bcfeb607042569383a Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 7 Dec 2021 11:23:54 +0000 Subject: [PATCH 7/7] Make _Py_IsMainInterpreter inline again. --- Include/internal/pycore_pystate.h | 9 +++++++-- Python/pystate.c | 9 --------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index 9e0112637d17a5..7e91e87a70a673 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -21,8 +21,13 @@ _Py_IsMainThread(void) return (thread == _PyRuntime.main_thread); } -extern int -_Py_IsMainInterpreter(PyInterpreterState *interp); +static inline int +_Py_IsMainInterpreter(PyInterpreterState *interp) +{ + /* Use directly _PyRuntime rather than tstate->interp->runtime, since + this function is used in performance critical code path (ceval) */ + return interp == _PyRuntime.interpreters.main; +} static inline const PyConfig * _Py_GetMainConfig(void) diff --git a/Python/pystate.c b/Python/pystate.c index eeb074179a8f30..f94e7cb0c4364b 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -2125,15 +2125,6 @@ _PyThreadState_PopFrame(PyThreadState *tstate, InterpreterFrame * frame) _Py_THREAD_LOCAL PyInterpreterState *_py_current_interpreter = NULL; #endif -int -_Py_IsMainInterpreter(PyInterpreterState *interp) -{ - /* Use directly _PyRuntime rather than tstate->interp->runtime, since - this function is used in performance critical code path (ceval) */ - return interp == _PyRuntime.interpreters.main; -} - - #ifdef __cplusplus } #endif