diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index 9a570b08bc5839..7e91e87a70a673 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" /* Thread local storage */ #include "pycore_runtime.h" /* PyRuntimeState */ @@ -20,16 +21,14 @@ _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); + return interp == _PyRuntime.interpreters.main; } - static inline const PyConfig * _Py_GetMainConfig(void) { @@ -40,6 +39,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 +109,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 +117,31 @@ _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 - 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 8e6e553554de12..98ec16b8003e72 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1577,6 +1577,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/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. 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 b505676636d384..6fcbccf87aac66 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 b9bcea393abe3c..6ea13ff039d168 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,8 +534,8 @@ pymain_repl(PyConfig *config, int *exitcode) static void pymain_run_python(int *exitcode) { + PyInterpreterState *interp = PyInterpreterState_Get(); PyObject *main_importer_path = NULL; - 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 b1c2914fb0f1fb..ce52c6546a3a13 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 @@ -555,7 +555,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(); } @@ -566,7 +566,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 @@ -6665,7 +6665,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; @@ -6695,8 +6695,7 @@ os_fork1_impl(PyObject *module) /*[clinic end generated code: output=0de8e67ce2a310bc input=12db02167893926e]*/ { pid_t pid; - - if (_PyInterpreterState_GET() != PyInterpreterState_Main()) { + if (PyInterpreterState_Get() != PyInterpreterState_Main()) { PyErr_SetString(PyExc_RuntimeError, "fork not supported for subinterpreters"); return NULL; } @@ -6730,7 +6729,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"); @@ -7348,7 +7347,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 bc891e8af3c0b2..a453f2f96a674a 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -1662,8 +1662,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; } @@ -2039,8 +2039,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/floatobject.c b/Objects/floatobject.c index 7fc192e7201171..7be2d3f389cb04 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 diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 926a32a5100bdd..84ec87e5371543 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -21,7 +21,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/unicodeobject.c b/Objects/unicodeobject.c index 532c48ad4d4aad..284ec482df170f 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/pystate.c b/Python/pystate.c index ba14c9d8af9fb7..f94e7cb0c4364b 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -467,9 +467,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"); } @@ -1066,6 +1064,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. @@ -2118,6 +2121,9 @@ _PyThreadState_PopFrame(PyThreadState *tstate, InterpreterFrame * frame) } } +#ifdef _Py_THREAD_LOCAL +_Py_THREAD_LOCAL PyInterpreterState *_py_current_interpreter = NULL; +#endif #ifdef __cplusplus }