From fa92cb44e86cf8cf4bb8ce28d60c99560f88519e Mon Sep 17 00:00:00 2001 From: Brett Simmers Date: Tue, 12 Mar 2024 15:50:21 -0400 Subject: [PATCH 01/18] Add Py_mod_gil module slot --- Doc/c-api/module.rst | 25 +++++++++++ Include/internal/pycore_ceval.h | 9 ++++ Include/moduleobject.h | 12 ++++- ...-03-12-13-51-09.gh-issue-116322.q8TcDQ.rst | 5 +++ Objects/moduleobject.c | 37 +++++++++++++++ Python/ceval_gil.c | 45 +++++++++++++++++++ 6 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-03-12-13-51-09.gh-issue-116322.q8TcDQ.rst diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index 979b22261efa3b..3764b0b6e3cf56 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -411,6 +411,31 @@ The available slot types are: .. versionadded:: 3.12 +.. c:macro: Py_mod_gil + + Specifies one of the following values: + + .. c:macro:: Py_MOD_GIL_USED + + The module assumes the presence of the global interpreter lock (GIL), and + may access global state without synchronization. + + .. c:macro:: Py_MOD_GIL_NOT_USED + + The module is safe to run without an active GIL. + + This slot is only used by Python builds configured with + :option:`--disable-gil`, and determines whether or not importing this module + will cause the GIL to be automatically enabled. See :envvar:`PYTHON_GIL` and + :option:`-X gil <-X>` for more detail. + + Multiple ``Py_mod_gil`` slots may not be specified in one module definition. + + If ``Py_mod_gil`` is not specified, the import machinery defaults to + ``Py_MOD_GIL_USED``. + + .. versionadded: 3.13 + See :PEP:`489` for more details on multi-phase initialization. Low-level module creation functions diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 946f82ae3c20e3..ea24628c4d1ca5 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -129,6 +129,15 @@ extern void _PyEval_FiniGIL(PyInterpreterState *interp); extern void _PyEval_AcquireLock(PyThreadState *tstate); extern void _PyEval_ReleaseLock(PyInterpreterState *, PyThreadState *); +#ifdef Py_GIL_DISABLED +// Enable the GIL for the given thread's interpreter. This may affect other +// interpreters, if the GIL is shared. +// +// Returns 1 if this call enabled the GIL, or 0 if it was already enabled. The +// caller will hold the GIL upon return. +extern int _PyEval_EnableGIL(PyThreadState *tstate); +#endif + extern void _PyEval_DeactivateOpCache(void); diff --git a/Include/moduleobject.h b/Include/moduleobject.h index 42b87cc4e91012..c7d542c661f546 100644 --- a/Include/moduleobject.h +++ b/Include/moduleobject.h @@ -76,9 +76,13 @@ struct PyModuleDef_Slot { #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030c0000 # define Py_mod_multiple_interpreters 3 #endif +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030e0000 +# define Py_mod_gil 4 +#endif + #ifndef Py_LIMITED_API -#define _Py_mod_LAST_SLOT 3 +#define _Py_mod_LAST_SLOT 4 #endif #endif /* New in 3.5 */ @@ -90,6 +94,12 @@ struct PyModuleDef_Slot { # define Py_MOD_PER_INTERPRETER_GIL_SUPPORTED ((void *)2) #endif +/* for Py_mod_gil: */ +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030e0000 +# define Py_MOD_GIL_USED ((void *)0) +# define Py_MOD_GIL_NOT_USED ((void *)1) +#endif + struct PyModuleDef { PyModuleDef_Base m_base; const char* m_name; diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-03-12-13-51-09.gh-issue-116322.q8TcDQ.rst b/Misc/NEWS.d/next/Core and Builtins/2024-03-12-13-51-09.gh-issue-116322.q8TcDQ.rst new file mode 100644 index 00000000000000..acaecd11967319 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2024-03-12-13-51-09.gh-issue-116322.q8TcDQ.rst @@ -0,0 +1,5 @@ +Multi-phase init extension modules may indicate to the runtime that they can +run without the GIL by providing ``Py_MOD_GIL_NOT_USED`` for the ``Py_mod_gil`` +slot. In ``--disable-gil`` builds, loading extensions that do not provide this +slot will enable the GIL for the remainder of the current interpreter, unless +the GIL was explicitly disabled by ``PYTHON_GIL=0`` or ``-Xgil=0``. diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index 9cd98fb4345fdd..7f3c90f9caf570 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -3,6 +3,8 @@ #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() +#include "pycore_ceval.h" // _PyEval_EnableGIL() +#include "pycore_initconfig.h" // _PyConfig_GIL_DEFAULT #include "pycore_interp.h" // PyInterpreterState.importlib #include "pycore_modsupport.h" // _PyModule_CreateInitialized() #include "pycore_moduleobject.h" // _PyModule_GetDef() @@ -249,6 +251,8 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio PyObject *m = NULL; int has_multiple_interpreters_slot = 0; void *multiple_interpreters = (void *)0; + int has_gil_slot = 0; + void *gil_slot = (void *)Py_MOD_GIL_USED; int has_execution_slots = 0; const char *name; int ret; @@ -303,6 +307,17 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio multiple_interpreters = cur_slot->value; has_multiple_interpreters_slot = 1; break; + case Py_mod_gil: + if (has_gil_slot) { + PyErr_Format( + PyExc_SystemError, + "module %s has more than one 'gil' slot", + name); + goto error; + } + gil_slot = cur_slot->value; + has_gil_slot = 1; + break; default: assert(cur_slot->slot < 0 || cur_slot->slot > _Py_mod_LAST_SLOT); PyErr_Format( @@ -333,6 +348,27 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio goto error; } +#ifdef Py_GIL_DISABLED + PyThreadState *tstate = _PyThreadState_GET(); + const PyConfig *config = _PyInterpreterState_GetConfig(interp); + if (gil_slot == Py_MOD_GIL_USED && config->enable_gil == _PyConfig_GIL_DEFAULT) { + if (_PyEval_EnableGIL(tstate)) { + PyErr_WarnFormat( + PyExc_RuntimeWarning, + 1, + "The global interpreter lock (GIL) has been enabled to load " + "module '%s', which has not declared that it can run safely " + "without the GIL. To override this behavior and keep the GIL " + "disabled (at your own risk), run with PYTHON_GIL=0 or -Xgil=0.", + name + ); + } + if (config->verbose) { + PySys_FormatStderr("# loading module '%s', which requires the GIL\n", name); + } + } +#endif + if (create) { m = create(spec, def); if (m == NULL) { @@ -458,6 +494,7 @@ PyModule_ExecDef(PyObject *module, PyModuleDef *def) } break; case Py_mod_multiple_interpreters: + case Py_mod_gil: /* handled in PyModule_FromDefAndSpec2 */ break; default: diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index d2cd35dfa86833..0cd0a22861d95c 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -969,6 +969,51 @@ _PyEval_InitState(PyInterpreterState *interp) _gil_initialize(&interp->_gil); } +#ifdef Py_GIL_DISABLED +int +_PyEval_EnableGIL(PyThreadState *tstate) +{ + struct _gil_runtime_state *gil = tstate->interp->ceval.gil; + + // gil->enabled only transitions from 0 to 1, and only while the world is + // stopped, so this can be read without any synchronization. + if (gil->enabled) { + return 0; + } + + // Enabling the GIL changes what it means to be an "attached" thread. To + // safely make this transition, we: + // 1. Detach the current thread. + // 2. Stop the world to detach (and suspend) all other threads. + // 3. Enable the GIL, if nobody else did between our check above and when + // our stop-the-world begins. + // 4. Start the world. + // 5. Attach the current thread. Other threads may attach and hold the GIL + // before this thread, which is harmless. + _PyThreadState_Detach(tstate); + + // This could be an interpreter-local stop-the-world in situations where we + // know that this interpreter's GIL is not shared (and that it won't become + // shared before the stop-the-world begins). This operation will happen at + // most once per interpreter, though, so we always stop the whole world to + // keep things simpler. + _PyEval_StopTheWorldAll(&_PyRuntime); + + int this_thread_enabled = 1; + if (gil->enabled) { + // A different thread enabled the GIL since our check above. + this_thread_enabled = 0; + } else { + gil->enabled = 1; + } + + _PyEval_StartTheWorldAll(&_PyRuntime); + _PyThreadState_Attach(tstate); + + return this_thread_enabled; +} +#endif + /* Do periodic things, like check for signals and async I/0. * We need to do reasonably frequently, but not too frequently. From 450aa41f7d5dd54975f0ff379676a3d58e638870 Mon Sep 17 00:00:00 2001 From: Brett Simmers Date: Wed, 27 Mar 2024 09:33:33 -0700 Subject: [PATCH 02/18] Some review comments from Eric --- Doc/c-api/module.rst | 12 ++++++------ Objects/moduleobject.c | 6 +++++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index 3764b0b6e3cf56..5cfb9c6ecd5eae 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -417,17 +417,17 @@ The available slot types are: .. c:macro:: Py_MOD_GIL_USED - The module assumes the presence of the global interpreter lock (GIL), and - may access global state without synchronization. + The module depends on the presence of the global interpreter lock (GIL), + and may access global state without synchronization. .. c:macro:: Py_MOD_GIL_NOT_USED The module is safe to run without an active GIL. - This slot is only used by Python builds configured with - :option:`--disable-gil`, and determines whether or not importing this module - will cause the GIL to be automatically enabled. See :envvar:`PYTHON_GIL` and - :option:`-X gil <-X>` for more detail. + This slot is ignored by Python builds not configured with + :option:`--disable-gil`. Otherwise, it determines whether or not importing + this module will cause the GIL to be automatically enabled. See + :envvar:`PYTHON_GIL` and :option:`-X gil <-X>` for more detail. Multiple ``Py_mod_gil`` slots may not be specified in one module definition. diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index 7f3c90f9caf570..7be50317e55638 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -252,7 +252,7 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio int has_multiple_interpreters_slot = 0; void *multiple_interpreters = (void *)0; int has_gil_slot = 0; - void *gil_slot = (void *)Py_MOD_GIL_USED; + void *gil_slot = Py_MOD_GIL_USED; int has_execution_slots = 0; const char *name; int ret; @@ -349,6 +349,8 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio } #ifdef Py_GIL_DISABLED + // TODO: We should figure out a way to fit this logic somewhere that it + // more naturally fits, like import.c or importdl.c. PyThreadState *tstate = _PyThreadState_GET(); const PyConfig *config = _PyInterpreterState_GetConfig(interp); if (gil_slot == Py_MOD_GIL_USED && config->enable_gil == _PyConfig_GIL_DEFAULT) { @@ -367,6 +369,8 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio PySys_FormatStderr("# loading module '%s', which requires the GIL\n", name); } } +#else + (void)gil_slot; #endif if (create) { From 47b9e266f6dd4efc2aaa6f955201f678289e1d23 Mon Sep 17 00:00:00 2001 From: Brett Simmers Date: Mon, 15 Apr 2024 14:11:12 -0700 Subject: [PATCH 03/18] Fix enabling the GIL, also support disabling the GIL More details: - Fix a race while enabling the GIL by checking if the GIL was enabled between a no-op call to `_PyEval_AcquireLock()` and the thread attaching, and trying again if it was. - Enable the GIL before running a module init function, since we can't know if it's a single-phase init module that doesn't support free-threading. Look at the state of the module after initialization to determine if it's safe to disable the GIL again. - Add `PyModule_SetGIL()`, which can be used by single-phase init modules to declare that they support running without the GIL. - Change `gil->enabled` from a simple on/off switch to a count of active requests to enable the GIL. This allows us to support multiple interleaved imports that each independently track whether the GIL should remain enabled. See the big comment in `pycore_ceval.h` for more details. --- Doc/c-api/module.rst | 13 +++ Include/internal/pycore_ceval.h | 37 +++++-- Include/internal/pycore_gil.h | 16 ++- Include/internal/pycore_import.h | 11 ++ Include/internal/pycore_moduleobject.h | 3 + Include/moduleobject.h | 1 + Objects/moduleobject.c | 43 ++++---- Python/ceval_gil.c | 143 ++++++++++++++++++++----- Python/import.c | 50 ++++++++- Python/importdl.c | 11 ++ Python/pystate.c | 33 ++++-- 11 files changed, 291 insertions(+), 70 deletions(-) diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index 5cfb9c6ecd5eae..16fd2b84d8b2b8 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -634,6 +634,19 @@ state: .. versionadded:: 3.9 +.. c:function:: int PyModule_SetGIL(PyObject *module, void *gil) + + In Python builds not configured with :option:`--disable-gil`, do + nothing. Otherwise, indicate that *module* does or does not support running + without the global interpreter lock (GIL), using one of the values from + :c:macro:`Py_mod_gil`. It must be called during *module*'s initialization + function. If this function is not called during module initialization, the + import machinery assumes the module does not support running without the + GIL. + Return ``-1`` on error, ``0`` on success. + + .. versionadded:: 3.13 + Module lookup ^^^^^^^^^^^^^ diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index ea24628c4d1ca5..2f82e788950d66 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -126,16 +126,41 @@ extern int _PyEval_ThreadsInitialized(void); extern void _PyEval_InitGIL(PyThreadState *tstate, int own_gil); extern void _PyEval_FiniGIL(PyInterpreterState *interp); -extern void _PyEval_AcquireLock(PyThreadState *tstate); +// Acquire the GIL and return 1. In free-threaded builds, this function may +// return 0 to indicate that the GIL was disabled and therefore not acquired. +extern int _PyEval_AcquireLock(PyThreadState *tstate); + extern void _PyEval_ReleaseLock(PyInterpreterState *, PyThreadState *); #ifdef Py_GIL_DISABLED -// Enable the GIL for the given thread's interpreter. This may affect other -// interpreters, if the GIL is shared. +// Enable or disable the GIL used by the interpreter that owns tstate, which +// must be the current thread. This may affect other interpreters, if the GIL +// is shared. All three functions will be no-ops (and return 0) if the +// interpreter's `enable_gil' config is not _PyConfig_GIL_DEFAULT. +// +// Every call to _PyEval_EnableGILTransient() must be paired with exactly one +// call to either _PyEval_EnableGILPermanent() or +// _PyEval_DisableGIL(). _PyEval_EnableGILPermanent() and _PyEval_DisableGIL() +// must only be called while the GIL is enabled from a call to +// _PyEval_EnableGILTransient(). +// +// _PyEval_EnableGILTransient() returns 1 if it enabled the GIL, or 0 if the +// GIL was already enabled, whether transiently or permanently. The caller will +// hold the GIL upon return. +// +// _PyEval_EnableGILPermanent() returns 1 if it permanently enabled the GIL +// (which must already be enabled), or 0 if it was already permanently +// enabled. Once _PyEval_EnableGILPermanent() has been called once, all +// subsequent calls to any of the three functions will be no-ops. +// +// _PyEval_DisableGIL() returns 1 if it disabled the GIL, or 0 if the GIL was +// kept enabled because of another request, whether transient or permanent. // -// Returns 1 if this call enabled the GIL, or 0 if it was already enabled. The -// caller will hold the GIL upon return. -extern int _PyEval_EnableGIL(PyThreadState *tstate); +// All three functions must be called by an attached thread (this implies that +// if the GIL is enabled, the current thread must hold it). +extern int _PyEval_EnableGILTransient(PyThreadState *tstate); +extern int _PyEval_EnableGILPermanent(PyThreadState *tstate); +extern int _PyEval_DisableGIL(PyThreadState *state); #endif extern void _PyEval_DeactivateOpCache(void); diff --git a/Include/internal/pycore_gil.h b/Include/internal/pycore_gil.h index d36b4c0db010b2..a2de5077371eba 100644 --- a/Include/internal/pycore_gil.h +++ b/Include/internal/pycore_gil.h @@ -21,8 +21,20 @@ extern "C" { struct _gil_runtime_state { #ifdef Py_GIL_DISABLED - /* Whether or not this GIL is being used. Can change from 0 to 1 at runtime - if, for example, a module that requires the GIL is loaded. */ + /* If this GIL is disabled, enabled == 0. + + If this GIL is enabled transiently (most likely to initialize a module + of unknown safety), enabled indicates the number of active transient + requests. + + If this GIL is enabled permanently, enabled == INT_MAX. + + It must not be modified directly; use _PyEval_EnableGILTransiently(), + _PyEval_EnableGILPermanently(), and _PyEval_DisableGIL() + + It is always read and written atomically, but a thread can assume its + value will be stable as long as that thread is attached or knows that no + other threads are attached (e.g., during a stop-the-world.). */ int enabled; #endif /* microseconds (the Python API uses seconds, though) */ diff --git a/Include/internal/pycore_import.h b/Include/internal/pycore_import.h index eb8a9a0db46c22..e3ce305454c228 100644 --- a/Include/internal/pycore_import.h +++ b/Include/internal/pycore_import.h @@ -206,6 +206,17 @@ extern int _PyImport_CheckSubinterpIncompatibleExtensionAllowed( // Export for '_testinternalcapi' shared extension PyAPI_FUNC(int) _PyImport_ClearExtension(PyObject *name, PyObject *filename); +#ifdef Py_GIL_DISABLED +// Assuming that the GIL is enabled from a call to +// _PyEval_EnableGILTransient(), either enable the GIL permanently or disable +// the GIL, depending on the value of the gil argument, which should be one of +// the values of the Py_mod_gil slot. +// +// If the GIL is enabled permanently, a warning will be issued referencing the +// module's name. +extern void _PyImport_CheckGILForModule(void *gil, PyObject *module_name); +#endif + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_moduleobject.h b/Include/internal/pycore_moduleobject.h index 5644bbe5e0552b..049677b292e235 100644 --- a/Include/internal/pycore_moduleobject.h +++ b/Include/internal/pycore_moduleobject.h @@ -22,6 +22,9 @@ typedef struct { PyObject *md_weaklist; // for logging purposes after md_dict is cleared PyObject *md_name; +#ifdef Py_GIL_DISABLED + void *md_gil; +#endif } PyModuleObject; static inline PyModuleDef* _PyModule_GetDef(PyObject *mod) { diff --git a/Include/moduleobject.h b/Include/moduleobject.h index c7d542c661f546..df1d401dc134c9 100644 --- a/Include/moduleobject.h +++ b/Include/moduleobject.h @@ -98,6 +98,7 @@ struct PyModuleDef_Slot { #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030e0000 # define Py_MOD_GIL_USED ((void *)0) # define Py_MOD_GIL_NOT_USED ((void *)1) +PyAPI_FUNC(int) PyModule_SetGIL(PyObject *module, void *gil); #endif struct PyModuleDef { diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index 7be50317e55638..c9a53b100db636 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -239,6 +239,9 @@ _PyModule_CreateInitialized(PyModuleDef* module, int module_api_version) } } m->md_def = module; +#ifdef Py_GIL_DISABLE + m->md_gil = Py_MOD_GIL_USED; +#endif return (PyObject*)m; } @@ -247,7 +250,7 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio { PyModuleDef_Slot* cur_slot; PyObject *(*create)(PyObject *, PyModuleDef*) = NULL; - PyObject *nameobj; + PyObject *nameobj = NULL; PyObject *m = NULL; int has_multiple_interpreters_slot = 0; void *multiple_interpreters = (void *)0; @@ -262,7 +265,7 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio nameobj = PyObject_GetAttrString(spec, "name"); if (nameobj == NULL) { - return NULL; + goto error; } name = PyUnicode_AsUTF8(nameobj); if (name == NULL) { @@ -349,26 +352,7 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio } #ifdef Py_GIL_DISABLED - // TODO: We should figure out a way to fit this logic somewhere that it - // more naturally fits, like import.c or importdl.c. - PyThreadState *tstate = _PyThreadState_GET(); - const PyConfig *config = _PyInterpreterState_GetConfig(interp); - if (gil_slot == Py_MOD_GIL_USED && config->enable_gil == _PyConfig_GIL_DEFAULT) { - if (_PyEval_EnableGIL(tstate)) { - PyErr_WarnFormat( - PyExc_RuntimeWarning, - 1, - "The global interpreter lock (GIL) has been enabled to load " - "module '%s', which has not declared that it can run safely " - "without the GIL. To override this behavior and keep the GIL " - "disabled (at your own risk), run with PYTHON_GIL=0 or -Xgil=0.", - name - ); - } - if (config->verbose) { - PySys_FormatStderr("# loading module '%s', which requires the GIL\n", name); - } - } + _PyImport_CheckGILForModule(gil_slot, nameobj); #else (void)gil_slot; #endif @@ -438,11 +422,24 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio return m; error: - Py_DECREF(nameobj); + Py_XDECREF(nameobj); Py_XDECREF(m); return NULL; } +int +PyModule_SetGIL(PyObject *module, void *gil) +{ + if (!PyModule_Check(module)) { + PyErr_BadInternalCall(); + return -1; + } +#ifdef Py_GIL_DISABLED + ((PyModuleObject *)module)->md_gil = gil; +#endif + return 0; +} + int PyModule_ExecDef(PyObject *module, PyModuleDef *def) { diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index f6dd22e7976df6..ad42dc04457031 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -205,6 +205,16 @@ static void recreate_gil(struct _gil_runtime_state *gil) } #endif +static void +drop_gil_impl(struct _gil_runtime_state *gil) +{ + MUTEX_LOCK(gil->mutex); + _Py_ANNOTATE_RWLOCK_RELEASED(&gil->locked, /*is_write=*/1); + _Py_atomic_store_int_relaxed(&gil->locked, 0); + COND_SIGNAL(gil->cond); + MUTEX_UNLOCK(gil->mutex); +} + static void drop_gil(PyInterpreterState *interp, PyThreadState *tstate) { @@ -220,7 +230,7 @@ drop_gil(PyInterpreterState *interp, PyThreadState *tstate) struct _gil_runtime_state *gil = ceval->gil; #ifdef Py_GIL_DISABLED - if (!gil->enabled) { + if (!_Py_atomic_load_int_relaxed(&gil->enabled)) { return; } #endif @@ -236,11 +246,7 @@ drop_gil(PyInterpreterState *interp, PyThreadState *tstate) _Py_atomic_store_ptr_relaxed(&gil->last_holder, tstate); } - MUTEX_LOCK(gil->mutex); - _Py_ANNOTATE_RWLOCK_RELEASED(&gil->locked, /*is_write=*/1); - _Py_atomic_store_int_relaxed(&gil->locked, 0); - COND_SIGNAL(gil->cond); - MUTEX_UNLOCK(gil->mutex); + drop_gil_impl(gil); #ifdef FORCE_SWITCHING /* We check tstate first in case we might be releasing the GIL for @@ -275,8 +281,10 @@ drop_gil(PyInterpreterState *interp, PyThreadState *tstate) The function saves errno at entry and restores its value at exit. - tstate must be non-NULL. */ -static void + tstate must be non-NULL. + + Returns 1 if the GIL was acquired, and 0 if not. */ +static int take_gil(PyThreadState *tstate) { int err = errno; @@ -300,8 +308,8 @@ take_gil(PyThreadState *tstate) PyInterpreterState *interp = tstate->interp; struct _gil_runtime_state *gil = interp->ceval.gil; #ifdef Py_GIL_DISABLED - if (!gil->enabled) { - return; + if (!_Py_atomic_load_int_relaxed(&gil->enabled)) { + return 0; } #endif @@ -346,6 +354,17 @@ take_gil(PyThreadState *tstate) } } +#ifdef Py_GIL_DISABLED + if (!_Py_atomic_load_int_relaxed(&gil->enabled)) { + // Another thread disabled the GIL between our check above and + // now. Don't take the GIL, signal any other waiting threads, and + // return 0. + COND_SIGNAL(gil->cond); + MUTEX_UNLOCK(gil->mutex); + return 0; + } +#endif + #ifdef FORCE_SWITCHING /* This mutex must be taken before modifying gil->last_holder: see drop_gil(). */ @@ -387,6 +406,7 @@ take_gil(PyThreadState *tstate) MUTEX_UNLOCK(gil->mutex); errno = err; + return 1; } void _PyEval_SetSwitchInterval(unsigned long microseconds) @@ -453,7 +473,8 @@ init_own_gil(PyInterpreterState *interp, struct _gil_runtime_state *gil) #ifdef Py_GIL_DISABLED // gh-116329: Once it is safe to do so, change this condition to // (enable_gil == _PyConfig_GIL_ENABLE), so the GIL is disabled by default. - gil->enabled = _PyInterpreterState_GetConfig(interp)->enable_gil != _PyConfig_GIL_DISABLE; + const PyConfig *config = _PyInterpreterState_GetConfig(interp); + gil->enabled = config->enable_gil != _PyConfig_GIL_DISABLE ? INT_MAX : 0; #endif create_gil(gil); assert(gil_created(gil)); @@ -548,11 +569,11 @@ PyEval_ReleaseLock(void) drop_gil(tstate->interp, tstate); } -void +int _PyEval_AcquireLock(PyThreadState *tstate) { _Py_EnsureTstateNotNULL(tstate); - take_gil(tstate); + return take_gil(tstate); } void @@ -968,13 +989,27 @@ _PyEval_InitState(PyInterpreterState *interp) #ifdef Py_GIL_DISABLED int -_PyEval_EnableGIL(PyThreadState *tstate) +_PyEval_EnableGILTransient(PyThreadState *tstate) { + if (_PyInterpreterState_GetConfig(tstate->interp)->enable_gil != + _PyConfig_GIL_DEFAULT) { + return 0; + } struct _gil_runtime_state *gil = tstate->interp->ceval.gil; - // gil->enabled only transitions from 0 to 1, and only while the world is - // stopped, so this can be read without any synchronization. - if (gil->enabled) { + int enabled = _Py_atomic_load_int_relaxed(&gil->enabled); + if (enabled == INT_MAX) { + // The GIL is already enabled permanently. + return 0; + } + if (enabled == INT_MAX - 1) { + Py_FatalError("Too many transient requests to enable the GIL"); + } + if (enabled > 0) { + // If enabled is nonzero, we know we hold the GIL. This means that no + // other threads are attached, and nobody else can be concurrently + // mutating it. + _Py_atomic_store_int_relaxed(&gil->enabled, enabled + 1); return 0; } @@ -990,25 +1025,77 @@ _PyEval_EnableGIL(PyThreadState *tstate) _PyThreadState_Detach(tstate); // This could be an interpreter-local stop-the-world in situations where we - // know that this interpreter's GIL is not shared (and that it won't become - // shared before the stop-the-world begins). This operation will happen at - // most once per interpreter, though, so we always stop the whole world to - // keep things simpler. + // know that this interpreter's GIL is not shared, and that it won't become + // shared before the stop-the-world begins. For now, we always stop all + // interpreters for simplicity. _PyEval_StopTheWorldAll(&_PyRuntime); - int this_thread_enabled = 1; - if (gil->enabled) { - // A different thread enabled the GIL since our check above. - this_thread_enabled = 0; - } else { - gil->enabled = 1; - } + enabled = _Py_atomic_load_int_relaxed(&gil->enabled); + int this_thread_enabled = enabled == 0; + _Py_atomic_store_int_relaxed(&gil->enabled, enabled + 1); _PyEval_StartTheWorldAll(&_PyRuntime); _PyThreadState_Attach(tstate); return this_thread_enabled; } + +int +_PyEval_EnableGILPermanent(PyThreadState *tstate) +{ + if (_PyInterpreterState_GetConfig(tstate->interp)->enable_gil != + _PyConfig_GIL_DEFAULT) { + return 0; + } + + struct _gil_runtime_state *gil = tstate->interp->ceval.gil; + assert(current_thread_holds_gil(gil, tstate)); + + int enabled = _Py_atomic_load_int_relaxed(&gil->enabled); + if (enabled == INT_MAX) { + return 0; + } + + _Py_atomic_store_int_relaxed(&gil->enabled, INT_MAX); + return 1; +} + +int +_PyEval_DisableGIL(PyThreadState *tstate) +{ + if (_PyInterpreterState_GetConfig(tstate->interp)->enable_gil != + _PyConfig_GIL_DEFAULT) { + return 0; + } + + struct _gil_runtime_state *gil = tstate->interp->ceval.gil; + assert(current_thread_holds_gil(gil, tstate)); + + int enabled = _Py_atomic_load_int_relaxed(&gil->enabled); + if (enabled == INT_MAX) { + return 0; + } + + assert(enabled >= 1); + enabled--; + + // Disabling the GIL is much simpler than enabling it, since we know we are + // the only attached thread. Other threads may start free-threading as soon + // as this store is complete, if it sets gil->enabled to 0. + _Py_atomic_store_int_relaxed(&gil->enabled, enabled); + + if (enabled == 0) { + // We're attached, so we know the GIL will remain disabled until at + // least the next time we detach, which must be after this function + // returns. + // + // Drop the GIL, which will wake up any threads waiting in take_gil() + // and let them resume execution without the GIL. + drop_gil_impl(gil); + return 1; + } + return 0; +} #endif diff --git a/Python/import.c b/Python/import.c index 6544a84d895d4a..128a09e084f332 100644 --- a/Python/import.c +++ b/Python/import.c @@ -1,6 +1,7 @@ /* Module definition and import implementation */ #include "Python.h" +#include "pycore_ceval.h" #include "pycore_hashtable.h" // _Py_hashtable_new_full() #include "pycore_import.h" // _PyImport_BootstrapImp() #include "pycore_initconfig.h" // _PyStatus_OK() @@ -1388,9 +1389,12 @@ create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec) /* Cannot re-init internal module ("sys" or "builtins") */ return import_add_module(tstate, name); } +#ifdef Py_GIL_DISABLED + _PyEval_EnableGILTransient(tstate); +#endif mod = (*p->initfunc)(); if (mod == NULL) { - return NULL; + goto error; } if (PyObject_TypeCheck(mod, &PyModuleDef_Type)) { @@ -1400,16 +1404,25 @@ create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec) /* Remember pointer to module init function. */ PyModuleDef *def = PyModule_GetDef(mod); if (def == NULL) { - return NULL; + goto error; } def->m_base.m_init = p->initfunc; if (_PyImport_FixupExtensionObject(mod, name, name, modules) < 0) { - return NULL; + goto error; } +#ifdef Py_GIL_DISABLE + _PyImport_CheckGILForModule(((PyModuleObject*)mod)->md_gil, name); +#endif return mod; } + + error: +#ifdef Py_GIL_DISABLE + _PyEval_DisableGIL(tstate); +#endif + return NULL; } } @@ -1417,6 +1430,37 @@ create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec) Py_RETURN_NONE; } +#ifdef Py_GIL_DISABLED +void +_PyImport_CheckGILForModule(void *gil, PyObject *module_name) +{ + PyThreadState *tstate = _PyThreadState_GET(); + + if (gil == Py_MOD_GIL_USED) { + if (_PyEval_EnableGILPermanent(tstate)) { + PyErr_WarnFormat( + PyExc_RuntimeWarning, + 1, + "The global interpreter lock (GIL) has been enabled to load " + "module '%U', which has not declared that it can run safely " + "without the GIL. To override this behavior and keep the GIL " + "disabled (at your own risk), run with PYTHON_GIL=0 or -Xgil=0.", + module_name + ); + } + + const PyConfig *config = _PyInterpreterState_GetConfig(tstate->interp); + if (config->enable_gil == _PyConfig_GIL_DEFAULT && config->verbose) { + PySys_FormatStderr("# loading module '%U', which requires the GIL\n", + module_name); + } + } + else { + assert(gil == Py_MOD_GIL_NOT_USED); + _PyEval_DisableGIL(tstate); + } +} +#endif /*****************************/ /* the builtin modules table */ diff --git a/Python/importdl.c b/Python/importdl.c index 7dfd301d77efb4..077f44d336cef6 100644 --- a/Python/importdl.c +++ b/Python/importdl.c @@ -3,6 +3,7 @@ #include "Python.h" #include "pycore_call.h" +#include "pycore_ceval.h" #include "pycore_import.h" #include "pycore_pyerrors.h" // _PyErr_FormatFromCause() #include "pycore_pystate.h" @@ -165,6 +166,10 @@ _PyImport_LoadDynamicModuleWithSpec(PyObject *spec, FILE *fp) p0 = (PyModInitFunction)exportfunc; +#ifdef Py_GIL_DISABLED + _PyEval_EnableGILTransient(_PyThreadState_GET()); +#endif + /* Package context is needed for single-phase init */ oldcontext = _PyImport_SwapPackageContext(newcontext); m = p0(); @@ -241,9 +246,15 @@ _PyImport_LoadDynamicModuleWithSpec(PyObject *spec, FILE *fp) Py_DECREF(name); Py_DECREF(path); +#ifdef Py_GIL_DISABLED + _PyImport_CheckGILForModule(((PyModuleObject*)m)->md_gil, name_unicode); +#endif return m; error: +#ifdef Py_GIL_DISABLED + _PyEval_DisableGIL(_PyThreadState_GET()); +#endif Py_DECREF(name_unicode); Py_XDECREF(name); Py_XDECREF(path); diff --git a/Python/pystate.c b/Python/pystate.c index 892e740493cdfd..459c47f5937f96 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1964,19 +1964,36 @@ _PyThreadState_Attach(PyThreadState *tstate) Py_FatalError("non-NULL old thread state"); } - _PyEval_AcquireLock(tstate); - // XXX assert(tstate_is_alive(tstate)); - current_fast_set(&_PyRuntime, tstate); - tstate_activate(tstate); + while (1) { + int acquired_gil = _PyEval_AcquireLock(tstate); - if (!tstate_try_attach(tstate)) { - tstate_wait_attach(tstate); - } + // XXX assert(tstate_is_alive(tstate)); + current_fast_set(&_PyRuntime, tstate); + tstate_activate(tstate); + + if (!tstate_try_attach(tstate)) { + tstate_wait_attach(tstate); + } #ifdef Py_GIL_DISABLED - _Py_qsbr_attach(((_PyThreadStateImpl *)tstate)->qsbr); + if (!!tstate->interp->ceval.gil->enabled != acquired_gil) { + // The GIL was enabled between our call to _PyEval_AcquireLock() + // and when we attached (the GIL can't go from enabled to disabled + // here because only a thread holding the GIL can disable + // it). Detach and try again. + assert(!acquired_gil); + tstate_set_detached(tstate, _Py_THREAD_DETACHED); + tstate_deactivate(tstate); + current_fast_clear(&_PyRuntime); + continue; + } + _Py_qsbr_attach(((_PyThreadStateImpl *)tstate)->qsbr); +#else + (void)acquired_gil; #endif + break; + } // Resume previous critical section. This acquires the lock(s) from the // top-most critical section. From 6c198e44c1ba4e488c75ff905e079aba27db3589 Mon Sep 17 00:00:00 2001 From: Brett Simmers Date: Mon, 15 Apr 2024 15:53:10 -0700 Subject: [PATCH 04/18] Fix module size in test_objecttypes Also fix the module format string for normal builds, since it only contains pointers (no `size_t`). --- Lib/test/test_sys.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index ab26bf56d9ced9..17d0e7ab5325b7 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1595,7 +1595,10 @@ def get_gen(): yield 1 check(int(PyLong_BASE**2-1), vsize('') + 2*self.longdigit) check(int(PyLong_BASE**2), vsize('') + 3*self.longdigit) # module - check(unittest, size('PnPPP')) + if support.Py_GIL_DISABLED: + check(unittest, size('PPPPPP')) + else: + check(unittest, size('PPPPP')) # None check(None, size('')) # NotImplementedType From 554c5b4bedd76420989f294409bf774b073e93f8 Mon Sep 17 00:00:00 2001 From: Brett Simmers Date: Mon, 15 Apr 2024 15:59:35 -0700 Subject: [PATCH 05/18] Add missing : in Py_mod_gil documentation --- Doc/c-api/module.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index 16fd2b84d8b2b8..2a288163c1d810 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -411,7 +411,7 @@ The available slot types are: .. versionadded:: 3.12 -.. c:macro: Py_mod_gil +.. c:macro:: Py_mod_gil Specifies one of the following values: From 80574781e72513885659d1fba78069cc2e8e5f02 Mon Sep 17 00:00:00 2001 From: Brett Simmers Date: Tue, 23 Apr 2024 11:53:28 -0700 Subject: [PATCH 06/18] From Eric: better loop, move _PyImport_CheckGILForModule --- Python/import.c | 64 ++++++++++++++++++++++++------------------------ Python/pystate.c | 5 ++-- 2 files changed, 34 insertions(+), 35 deletions(-) diff --git a/Python/import.c b/Python/import.c index d6bfc03c29eae8..334dcb2bd2fb18 100644 --- a/Python/import.c +++ b/Python/import.c @@ -1124,6 +1124,38 @@ _PyImport_CheckSubinterpIncompatibleExtensionAllowed(const char *name) return 0; } +#ifdef Py_GIL_DISABLED +void +_PyImport_CheckGILForModule(void *gil, PyObject *module_name) +{ + PyThreadState *tstate = _PyThreadState_GET(); + + if (gil == Py_MOD_GIL_USED) { + if (_PyEval_EnableGILPermanent(tstate)) { + PyErr_WarnFormat( + PyExc_RuntimeWarning, + 1, + "The global interpreter lock (GIL) has been enabled to load " + "module '%U', which has not declared that it can run safely " + "without the GIL. To override this behavior and keep the GIL " + "disabled (at your own risk), run with PYTHON_GIL=0 or -Xgil=0.", + module_name + ); + } + + const PyConfig *config = _PyInterpreterState_GetConfig(tstate->interp); + if (config->enable_gil == _PyConfig_GIL_DEFAULT && config->verbose) { + PySys_FormatStderr("# loading module '%U', which requires the GIL\n", + module_name); + } + } + else { + assert(gil == Py_MOD_GIL_NOT_USED); + _PyEval_DisableGIL(tstate); + } +} +#endif + static PyObject * get_core_module_dict(PyInterpreterState *interp, PyObject *name, PyObject *path) @@ -1445,38 +1477,6 @@ create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec) return NULL; } -#ifdef Py_GIL_DISABLED -void -_PyImport_CheckGILForModule(void *gil, PyObject *module_name) -{ - PyThreadState *tstate = _PyThreadState_GET(); - - if (gil == Py_MOD_GIL_USED) { - if (_PyEval_EnableGILPermanent(tstate)) { - PyErr_WarnFormat( - PyExc_RuntimeWarning, - 1, - "The global interpreter lock (GIL) has been enabled to load " - "module '%U', which has not declared that it can run safely " - "without the GIL. To override this behavior and keep the GIL " - "disabled (at your own risk), run with PYTHON_GIL=0 or -Xgil=0.", - module_name - ); - } - - const PyConfig *config = _PyInterpreterState_GetConfig(tstate->interp); - if (config->enable_gil == _PyConfig_GIL_DEFAULT && config->verbose) { - PySys_FormatStderr("# loading module '%U', which requires the GIL\n", - module_name); - } - } - else { - assert(gil == Py_MOD_GIL_NOT_USED); - _PyEval_DisableGIL(tstate); - } -} -#endif - /*****************************/ /* the builtin modules table */ /*****************************/ diff --git a/Python/pystate.c b/Python/pystate.c index 04e1b1bb63aaa4..e5356709335bab 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -2043,7 +2043,7 @@ _PyThreadState_Attach(PyThreadState *tstate) } - while (1) { + do { int acquired_gil = _PyEval_AcquireLock(tstate); // XXX assert(tstate_is_alive(tstate)); @@ -2070,8 +2070,7 @@ _PyThreadState_Attach(PyThreadState *tstate) #else (void)acquired_gil; #endif - break; - } + } while (0); // Resume previous critical section. This acquires the lock(s) from the // top-most critical section. From bbb949ec09ea8f85f5a63232408c4fc83ae404e2 Mon Sep 17 00:00:00 2001 From: Brett Simmers Date: Tue, 30 Apr 2024 13:42:32 -0700 Subject: [PATCH 07/18] Remove code to enable/disable the GIL (it will go in a different PR) --- Include/internal/pycore_ceval.h | 36 +------ Include/internal/pycore_gil.h | 16 +--- Include/internal/pycore_import.h | 11 --- Objects/moduleobject.c | 14 +-- Python/ceval_gil.c | 158 +++---------------------------- Python/import.c | 44 --------- Python/importdl.c | 10 -- Python/pystate.c | 32 ++----- 8 files changed, 27 insertions(+), 294 deletions(-) diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index d4ac36a709ad26..cfb88c3f4c8e15 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -130,43 +130,9 @@ extern int _PyEval_ThreadsInitialized(void); extern void _PyEval_InitGIL(PyThreadState *tstate, int own_gil); extern void _PyEval_FiniGIL(PyInterpreterState *interp); -// Acquire the GIL and return 1. In free-threaded builds, this function may -// return 0 to indicate that the GIL was disabled and therefore not acquired. -extern int _PyEval_AcquireLock(PyThreadState *tstate); - +extern void _PyEval_AcquireLock(PyThreadState *tstate); extern void _PyEval_ReleaseLock(PyInterpreterState *, PyThreadState *); -#ifdef Py_GIL_DISABLED -// Enable or disable the GIL used by the interpreter that owns tstate, which -// must be the current thread. This may affect other interpreters, if the GIL -// is shared. All three functions will be no-ops (and return 0) if the -// interpreter's `enable_gil' config is not _PyConfig_GIL_DEFAULT. -// -// Every call to _PyEval_EnableGILTransient() must be paired with exactly one -// call to either _PyEval_EnableGILPermanent() or -// _PyEval_DisableGIL(). _PyEval_EnableGILPermanent() and _PyEval_DisableGIL() -// must only be called while the GIL is enabled from a call to -// _PyEval_EnableGILTransient(). -// -// _PyEval_EnableGILTransient() returns 1 if it enabled the GIL, or 0 if the -// GIL was already enabled, whether transiently or permanently. The caller will -// hold the GIL upon return. -// -// _PyEval_EnableGILPermanent() returns 1 if it permanently enabled the GIL -// (which must already be enabled), or 0 if it was already permanently -// enabled. Once _PyEval_EnableGILPermanent() has been called once, all -// subsequent calls to any of the three functions will be no-ops. -// -// _PyEval_DisableGIL() returns 1 if it disabled the GIL, or 0 if the GIL was -// kept enabled because of another request, whether transient or permanent. -// -// All three functions must be called by an attached thread (this implies that -// if the GIL is enabled, the current thread must hold it). -extern int _PyEval_EnableGILTransient(PyThreadState *tstate); -extern int _PyEval_EnableGILPermanent(PyThreadState *tstate); -extern int _PyEval_DisableGIL(PyThreadState *state); -#endif - extern void _PyEval_DeactivateOpCache(void); diff --git a/Include/internal/pycore_gil.h b/Include/internal/pycore_gil.h index a2de5077371eba..d36b4c0db010b2 100644 --- a/Include/internal/pycore_gil.h +++ b/Include/internal/pycore_gil.h @@ -21,20 +21,8 @@ extern "C" { struct _gil_runtime_state { #ifdef Py_GIL_DISABLED - /* If this GIL is disabled, enabled == 0. - - If this GIL is enabled transiently (most likely to initialize a module - of unknown safety), enabled indicates the number of active transient - requests. - - If this GIL is enabled permanently, enabled == INT_MAX. - - It must not be modified directly; use _PyEval_EnableGILTransiently(), - _PyEval_EnableGILPermanently(), and _PyEval_DisableGIL() - - It is always read and written atomically, but a thread can assume its - value will be stable as long as that thread is attached or knows that no - other threads are attached (e.g., during a stop-the-world.). */ + /* Whether or not this GIL is being used. Can change from 0 to 1 at runtime + if, for example, a module that requires the GIL is loaded. */ int enabled; #endif /* microseconds (the Python API uses seconds, though) */ diff --git a/Include/internal/pycore_import.h b/Include/internal/pycore_import.h index 5e7d9e766adcfa..8d7f0543f8d315 100644 --- a/Include/internal/pycore_import.h +++ b/Include/internal/pycore_import.h @@ -209,17 +209,6 @@ extern int _PyImport_CheckSubinterpIncompatibleExtensionAllowed( // Export for '_testinternalcapi' shared extension PyAPI_FUNC(int) _PyImport_ClearExtension(PyObject *name, PyObject *filename); -#ifdef Py_GIL_DISABLED -// Assuming that the GIL is enabled from a call to -// _PyEval_EnableGILTransient(), either enable the GIL permanently or disable -// the GIL, depending on the value of the gil argument, which should be one of -// the values of the Py_mod_gil slot. -// -// If the GIL is enabled permanently, a warning will be issued referencing the -// module's name. -extern void _PyImport_CheckGILForModule(void *gil, PyObject *module_name); -#endif - #ifdef __cplusplus } #endif diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index 81b725aab83c8f..9e5130cfc10e3e 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -3,9 +3,7 @@ #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() -#include "pycore_ceval.h" // _PyEval_EnableGIL() #include "pycore_fileutils.h" // _Py_wgetcwd -#include "pycore_initconfig.h" // _PyConfig_GIL_DEFAULT #include "pycore_interp.h" // PyInterpreterState.importlib #include "pycore_modsupport.h" // _PyModule_CreateInitialized() #include "pycore_moduleobject.h" // _PyModule_GetDef() @@ -262,7 +260,7 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio { PyModuleDef_Slot* cur_slot; PyObject *(*create)(PyObject *, PyModuleDef*) = NULL; - PyObject *nameobj = NULL; + PyObject *nameobj; PyObject *m = NULL; int has_multiple_interpreters_slot = 0; void *multiple_interpreters = (void *)0; @@ -277,7 +275,7 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio nameobj = PyObject_GetAttrString(spec, "name"); if (nameobj == NULL) { - goto error; + return NULL; } name = PyUnicode_AsUTF8(nameobj); if (name == NULL) { @@ -363,12 +361,6 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio goto error; } -#ifdef Py_GIL_DISABLED - _PyImport_CheckGILForModule(gil_slot, nameobj); -#else - (void)gil_slot; -#endif - if (create) { m = create(spec, def); if (m == NULL) { @@ -434,7 +426,7 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio return m; error: - Py_XDECREF(nameobj); + Py_DECREF(nameobj); Py_XDECREF(m); return NULL; } diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index c1b49e28cbaaa5..fdbb4882c3d711 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -205,16 +205,6 @@ static void recreate_gil(struct _gil_runtime_state *gil) } #endif -static void -drop_gil_impl(struct _gil_runtime_state *gil) -{ - MUTEX_LOCK(gil->mutex); - _Py_ANNOTATE_RWLOCK_RELEASED(&gil->locked, /*is_write=*/1); - _Py_atomic_store_int_relaxed(&gil->locked, 0); - COND_SIGNAL(gil->cond); - MUTEX_UNLOCK(gil->mutex); -} - static void drop_gil(PyInterpreterState *interp, PyThreadState *tstate) { @@ -230,7 +220,7 @@ drop_gil(PyInterpreterState *interp, PyThreadState *tstate) struct _gil_runtime_state *gil = ceval->gil; #ifdef Py_GIL_DISABLED - if (!_Py_atomic_load_int_relaxed(&gil->enabled)) { + if (!gil->enabled) { return; } #endif @@ -246,7 +236,11 @@ drop_gil(PyInterpreterState *interp, PyThreadState *tstate) _Py_atomic_store_ptr_relaxed(&gil->last_holder, tstate); } - drop_gil_impl(gil); + MUTEX_LOCK(gil->mutex); + _Py_ANNOTATE_RWLOCK_RELEASED(&gil->locked, /*is_write=*/1); + _Py_atomic_store_int_relaxed(&gil->locked, 0); + COND_SIGNAL(gil->cond); + MUTEX_UNLOCK(gil->mutex); #ifdef FORCE_SWITCHING /* We check tstate first in case we might be releasing the GIL for @@ -281,10 +275,8 @@ drop_gil(PyInterpreterState *interp, PyThreadState *tstate) The function saves errno at entry and restores its value at exit. - tstate must be non-NULL. - - Returns 1 if the GIL was acquired, and 0 if not. */ -static int + tstate must be non-NULL. */ +static void take_gil(PyThreadState *tstate) { int err = errno; @@ -308,8 +300,8 @@ take_gil(PyThreadState *tstate) PyInterpreterState *interp = tstate->interp; struct _gil_runtime_state *gil = interp->ceval.gil; #ifdef Py_GIL_DISABLED - if (!_Py_atomic_load_int_relaxed(&gil->enabled)) { - return 0; + if (!gil->enabled) { + return; } #endif @@ -354,17 +346,6 @@ take_gil(PyThreadState *tstate) } } -#ifdef Py_GIL_DISABLED - if (!_Py_atomic_load_int_relaxed(&gil->enabled)) { - // Another thread disabled the GIL between our check above and - // now. Don't take the GIL, signal any other waiting threads, and - // return 0. - COND_SIGNAL(gil->cond); - MUTEX_UNLOCK(gil->mutex); - return 0; - } -#endif - #ifdef FORCE_SWITCHING /* This mutex must be taken before modifying gil->last_holder: see drop_gil(). */ @@ -406,7 +387,6 @@ take_gil(PyThreadState *tstate) MUTEX_UNLOCK(gil->mutex); errno = err; - return 1; } void _PyEval_SetSwitchInterval(unsigned long microseconds) @@ -471,8 +451,7 @@ init_own_gil(PyInterpreterState *interp, struct _gil_runtime_state *gil) { assert(!gil_created(gil)); #ifdef Py_GIL_DISABLED - const PyConfig *config = _PyInterpreterState_GetConfig(interp); - gil->enabled = config->enable_gil == _PyConfig_GIL_ENABLE ? INT_MAX : 0; + gil->enabled = _PyInterpreterState_GetConfig(interp)->enable_gil == _PyConfig_GIL_ENABLE; #endif create_gil(gil); assert(gil_created(gil)); @@ -566,11 +545,11 @@ PyEval_ReleaseLock(void) drop_gil(tstate->interp, tstate); } -int +void _PyEval_AcquireLock(PyThreadState *tstate) { _Py_EnsureTstateNotNULL(tstate); - return take_gil(tstate); + take_gil(tstate); } void @@ -1033,117 +1012,6 @@ _PyEval_InitState(PyInterpreterState *interp) _gil_initialize(&interp->_gil); } -#ifdef Py_GIL_DISABLED -int -_PyEval_EnableGILTransient(PyThreadState *tstate) -{ - if (_PyInterpreterState_GetConfig(tstate->interp)->enable_gil != - _PyConfig_GIL_DEFAULT) { - return 0; - } - struct _gil_runtime_state *gil = tstate->interp->ceval.gil; - - int enabled = _Py_atomic_load_int_relaxed(&gil->enabled); - if (enabled == INT_MAX) { - // The GIL is already enabled permanently. - return 0; - } - if (enabled == INT_MAX - 1) { - Py_FatalError("Too many transient requests to enable the GIL"); - } - if (enabled > 0) { - // If enabled is nonzero, we know we hold the GIL. This means that no - // other threads are attached, and nobody else can be concurrently - // mutating it. - _Py_atomic_store_int_relaxed(&gil->enabled, enabled + 1); - return 0; - } - - // Enabling the GIL changes what it means to be an "attached" thread. To - // safely make this transition, we: - // 1. Detach the current thread. - // 2. Stop the world to detach (and suspend) all other threads. - // 3. Enable the GIL, if nobody else did between our check above and when - // our stop-the-world begins. - // 4. Start the world. - // 5. Attach the current thread. Other threads may attach and hold the GIL - // before this thread, which is harmless. - _PyThreadState_Detach(tstate); - - // This could be an interpreter-local stop-the-world in situations where we - // know that this interpreter's GIL is not shared, and that it won't become - // shared before the stop-the-world begins. For now, we always stop all - // interpreters for simplicity. - _PyEval_StopTheWorldAll(&_PyRuntime); - - enabled = _Py_atomic_load_int_relaxed(&gil->enabled); - int this_thread_enabled = enabled == 0; - _Py_atomic_store_int_relaxed(&gil->enabled, enabled + 1); - - _PyEval_StartTheWorldAll(&_PyRuntime); - _PyThreadState_Attach(tstate); - - return this_thread_enabled; -} - -int -_PyEval_EnableGILPermanent(PyThreadState *tstate) -{ - if (_PyInterpreterState_GetConfig(tstate->interp)->enable_gil != - _PyConfig_GIL_DEFAULT) { - return 0; - } - - struct _gil_runtime_state *gil = tstate->interp->ceval.gil; - assert(current_thread_holds_gil(gil, tstate)); - - int enabled = _Py_atomic_load_int_relaxed(&gil->enabled); - if (enabled == INT_MAX) { - return 0; - } - - _Py_atomic_store_int_relaxed(&gil->enabled, INT_MAX); - return 1; -} - -int -_PyEval_DisableGIL(PyThreadState *tstate) -{ - if (_PyInterpreterState_GetConfig(tstate->interp)->enable_gil != - _PyConfig_GIL_DEFAULT) { - return 0; - } - - struct _gil_runtime_state *gil = tstate->interp->ceval.gil; - assert(current_thread_holds_gil(gil, tstate)); - - int enabled = _Py_atomic_load_int_relaxed(&gil->enabled); - if (enabled == INT_MAX) { - return 0; - } - - assert(enabled >= 1); - enabled--; - - // Disabling the GIL is much simpler than enabling it, since we know we are - // the only attached thread. Other threads may start free-threading as soon - // as this store is complete, if it sets gil->enabled to 0. - _Py_atomic_store_int_relaxed(&gil->enabled, enabled); - - if (enabled == 0) { - // We're attached, so we know the GIL will remain disabled until at - // least the next time we detach, which must be after this function - // returns. - // - // Drop the GIL, which will wake up any threads waiting in take_gil() - // and let them resume execution without the GIL. - drop_gil_impl(gil); - return 1; - } - return 0; -} -#endif - /* Do periodic things, like check for signals and async I/0. * We need to do reasonably frequently, but not too frequently. diff --git a/Python/import.c b/Python/import.c index e700c7da23c09f..56011295f95190 100644 --- a/Python/import.c +++ b/Python/import.c @@ -1,7 +1,6 @@ /* Module definition and import implementation */ #include "Python.h" -#include "pycore_ceval.h" #include "pycore_hashtable.h" // _Py_hashtable_new_full() #include "pycore_import.h" // _PyImport_BootstrapImp() #include "pycore_initconfig.h" // _PyStatus_OK() @@ -1151,38 +1150,6 @@ _PyImport_CheckSubinterpIncompatibleExtensionAllowed(const char *name) return 0; } -#ifdef Py_GIL_DISABLED -void -_PyImport_CheckGILForModule(void *gil, PyObject *module_name) -{ - PyThreadState *tstate = _PyThreadState_GET(); - - if (gil == Py_MOD_GIL_USED) { - if (_PyEval_EnableGILPermanent(tstate)) { - PyErr_WarnFormat( - PyExc_RuntimeWarning, - 1, - "The global interpreter lock (GIL) has been enabled to load " - "module '%U', which has not declared that it can run safely " - "without the GIL. To override this behavior and keep the GIL " - "disabled (at your own risk), run with PYTHON_GIL=0 or -Xgil=0.", - module_name - ); - } - - const PyConfig *config = _PyInterpreterState_GetConfig(tstate->interp); - if (config->enable_gil == _PyConfig_GIL_DEFAULT && config->verbose) { - PySys_FormatStderr("# loading module '%U', which requires the GIL\n", - module_name); - } - } - else { - assert(gil == Py_MOD_GIL_NOT_USED); - _PyEval_DisableGIL(tstate); - } -} -#endif - static PyObject * get_core_module_dict(PyInterpreterState *interp, PyObject *name, PyObject *path) @@ -1571,9 +1538,6 @@ create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec) goto finally; } -#ifdef Py_GIL_DISABLED - _PyEval_EnableGILTransient(tstate); -#endif mod = p0(); if (mod == NULL) { goto finally; @@ -1624,14 +1588,6 @@ create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec) } finally: -#ifdef Py_GIL_DISABLE - if (mod != NULL) { - _PyImport_CheckGILForModule(((PyModuleObject*)mod)->md_gil, name); - } - else { - _PyEval_DisableGIL(tstate); - } -#endif _Py_ext_module_loader_info_clear(&info); return mod; } diff --git a/Python/importdl.c b/Python/importdl.c index 609fdac0ec207f..f2ad95fbbb507d 100644 --- a/Python/importdl.c +++ b/Python/importdl.c @@ -3,7 +3,6 @@ #include "Python.h" #include "pycore_call.h" -#include "pycore_ceval.h" #include "pycore_import.h" #include "pycore_pyerrors.h" // _PyErr_FormatFromCause() #include "pycore_pystate.h" @@ -219,9 +218,6 @@ _PyImport_LoadDynamicModuleWithSpec(struct _Py_ext_module_loader_info *info, p0 = (PyModInitFunction)exportfunc; -#ifdef Py_GIL_DISABLED - _PyEval_EnableGILTransient(_PyThreadState_GET()); -#endif /* Package context is needed for single-phase init */ oldcontext = _PyImport_SwapPackageContext(info->newcontext); m = p0(); @@ -294,15 +290,9 @@ _PyImport_LoadDynamicModuleWithSpec(struct _Py_ext_module_loader_info *info, goto error; } -#ifdef Py_GIL_DISABLED - _PyImport_CheckGILForModule(((PyModuleObject*)m)->md_gil, name_unicode); -#endif return m; error: -#ifdef Py_GIL_DISABLED - _PyEval_DisableGIL(_PyThreadState_GET()); -#endif Py_XDECREF(m); return NULL; } diff --git a/Python/pystate.c b/Python/pystate.c index e5356709335bab..bca28cebcc9059 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -2042,35 +2042,19 @@ _PyThreadState_Attach(PyThreadState *tstate) Py_FatalError("non-NULL old thread state"); } + _PyEval_AcquireLock(tstate); - do { - int acquired_gil = _PyEval_AcquireLock(tstate); - - // XXX assert(tstate_is_alive(tstate)); - current_fast_set(&_PyRuntime, tstate); - tstate_activate(tstate); + // XXX assert(tstate_is_alive(tstate)); + current_fast_set(&_PyRuntime, tstate); + tstate_activate(tstate); - if (!tstate_try_attach(tstate)) { - tstate_wait_attach(tstate); - } + if (!tstate_try_attach(tstate)) { + tstate_wait_attach(tstate); + } #ifdef Py_GIL_DISABLED - if (!!tstate->interp->ceval.gil->enabled != acquired_gil) { - // The GIL was enabled between our call to _PyEval_AcquireLock() - // and when we attached (the GIL can't go from enabled to disabled - // here because only a thread holding the GIL can disable - // it). Detach and try again. - assert(!acquired_gil); - tstate_set_detached(tstate, _Py_THREAD_DETACHED); - tstate_deactivate(tstate); - current_fast_clear(&_PyRuntime); - continue; - } - _Py_qsbr_attach(((_PyThreadStateImpl *)tstate)->qsbr); -#else - (void)acquired_gil; + _Py_qsbr_attach(((_PyThreadStateImpl *)tstate)->qsbr); #endif - } while (0); // Resume previous critical section. This acquires the lock(s) from the // top-most critical section. From 7f1205e3101d544d9175c70db3eae50b48bcfdb2 Mon Sep 17 00:00:00 2001 From: Brett Simmers Date: Fri, 26 Apr 2024 12:51:23 -0700 Subject: [PATCH 08/18] Don't put PyModule_SetGIL() in the limited API --- Include/moduleobject.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Include/moduleobject.h b/Include/moduleobject.h index df1d401dc134c9..20fc074449b32b 100644 --- a/Include/moduleobject.h +++ b/Include/moduleobject.h @@ -98,6 +98,9 @@ struct PyModuleDef_Slot { #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030e0000 # define Py_MOD_GIL_USED ((void *)0) # define Py_MOD_GIL_NOT_USED ((void *)1) +#endif + +#ifndef Py_LIMITED_API PyAPI_FUNC(int) PyModule_SetGIL(PyObject *module, void *gil); #endif From f8b02b33feaf93e915192e437d2f04a4e8568cc0 Mon Sep 17 00:00:00 2001 From: Brett Simmers Date: Wed, 1 May 2024 14:03:31 -0700 Subject: [PATCH 09/18] Set m->md_gil in PyModule_FromDefAndSpec2, rename/guard PyModule_SetGIL() --- Doc/c-api/module.rst | 10 +++++----- Include/moduleobject.h | 4 ++-- Objects/moduleobject.c | 9 ++++++--- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index 2a288163c1d810..86308d921f47f2 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -634,15 +634,15 @@ state: .. versionadded:: 3.9 -.. c:function:: int PyModule_SetGIL(PyObject *module, void *gil) +.. c:function:: int PyModule_ExperimentalSetGIL(PyObject *module, void *gil) - In Python builds not configured with :option:`--disable-gil`, do - nothing. Otherwise, indicate that *module* does or does not support running - without the global interpreter lock (GIL), using one of the values from + Indicate that *module* does or does not support running without the global + interpreter lock (GIL), using one of the values from :c:macro:`Py_mod_gil`. It must be called during *module*'s initialization function. If this function is not called during module initialization, the import machinery assumes the module does not support running without the - GIL. + GIL. This function is only available in Python builds configured with + :option:`--disable-gil`. Return ``-1`` on error, ``0`` on success. .. versionadded:: 3.13 diff --git a/Include/moduleobject.h b/Include/moduleobject.h index 20fc074449b32b..2571f071e6e748 100644 --- a/Include/moduleobject.h +++ b/Include/moduleobject.h @@ -100,8 +100,8 @@ struct PyModuleDef_Slot { # define Py_MOD_GIL_NOT_USED ((void *)1) #endif -#ifndef Py_LIMITED_API -PyAPI_FUNC(int) PyModule_SetGIL(PyObject *module, void *gil); +#if !defined(Py_LIMITED_API) && defined(Py_GIL_DISABLED) +PyAPI_FUNC(int) PyModule_ExperimentalSetGIL(PyObject *module, void *gil); #endif struct PyModuleDef { diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index 9e5130cfc10e3e..a356c9d3399fcb 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -390,6 +390,9 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio if (PyModule_Check(m)) { ((PyModuleObject*)m)->md_state = NULL; ((PyModuleObject*)m)->md_def = def; +#ifdef Py_GIL_DISABLED + ((PyModuleObject*)m)->md_gil = gil_slot; +#endif } else { if (def->m_size > 0 || def->m_traverse || def->m_clear || def->m_free) { PyErr_Format( @@ -431,18 +434,18 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio return NULL; } +#ifdef Py_GIL_DISABLED int -PyModule_SetGIL(PyObject *module, void *gil) +PyModule_ExperimentalSetGIL(PyObject *module, void *gil) { if (!PyModule_Check(module)) { PyErr_BadInternalCall(); return -1; } -#ifdef Py_GIL_DISABLED ((PyModuleObject *)module)->md_gil = gil; -#endif return 0; } +#endif int PyModule_ExecDef(PyObject *module, PyModuleDef *def) From d2bad05c10d689c220c6cbe20dbad2d5ee918d32 Mon Sep 17 00:00:00 2001 From: Brett Simmers Date: Wed, 1 May 2024 14:28:36 -0700 Subject: [PATCH 10/18] Fix limited API version for Py_mod_gil --- Include/moduleobject.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Include/moduleobject.h b/Include/moduleobject.h index 2571f071e6e748..e5e066b9354f8c 100644 --- a/Include/moduleobject.h +++ b/Include/moduleobject.h @@ -76,7 +76,7 @@ struct PyModuleDef_Slot { #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030c0000 # define Py_mod_multiple_interpreters 3 #endif -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030e0000 +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030d0000 # define Py_mod_gil 4 #endif @@ -95,7 +95,7 @@ struct PyModuleDef_Slot { #endif /* for Py_mod_gil: */ -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030e0000 +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030d0000 # define Py_MOD_GIL_USED ((void *)0) # define Py_MOD_GIL_NOT_USED ((void *)1) #endif From d7d59f053267d752b5dee13607f8b7e7bae04327 Mon Sep 17 00:00:00 2001 From: Brett Simmers Date: Tue, 30 Apr 2024 14:12:15 -0700 Subject: [PATCH 11/18] Update NEWS entry for behavioral changes --- .../2024-03-12-13-51-09.gh-issue-116322.q8TcDQ.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-03-12-13-51-09.gh-issue-116322.q8TcDQ.rst b/Misc/NEWS.d/next/Core and Builtins/2024-03-12-13-51-09.gh-issue-116322.q8TcDQ.rst index acaecd11967319..2d3bf411a5a162 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2024-03-12-13-51-09.gh-issue-116322.q8TcDQ.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2024-03-12-13-51-09.gh-issue-116322.q8TcDQ.rst @@ -1,5 +1,5 @@ -Multi-phase init extension modules may indicate to the runtime that they can -run without the GIL by providing ``Py_MOD_GIL_NOT_USED`` for the ``Py_mod_gil`` -slot. In ``--disable-gil`` builds, loading extensions that do not provide this -slot will enable the GIL for the remainder of the current interpreter, unless -the GIL was explicitly disabled by ``PYTHON_GIL=0`` or ``-Xgil=0``. +Extension modules may indicate to the runtime that they can run without the +GIL. Multi-phase init modules do so by calling providing +``Py_MOD_GIL_NOT_USED`` for the ``Py_mod_gil`` slot, while single-phase init +modules call ``PyModule_ExperimentalSetGIL(mod, Py_MOD_GIL_NOT_USED)`` from +their init function. From ccd6e004dfaf6dbfe20e84d586e192b706b88b83 Mon Sep 17 00:00:00 2001 From: Brett Simmers Date: Wed, 1 May 2024 13:56:18 -0700 Subject: [PATCH 12/18] Mark all modules as not using GIL --- .../extension/_test_nonmodule_cases.py | 44 +++++++++++++++++++ .../test_importlib/extension/test_loader.py | 35 +++++---------- Modules/_abc.c | 1 + Modules/_asynciomodule.c | 1 + Modules/_bisectmodule.c | 1 + Modules/_blake2/blake2module.c | 1 + Modules/_bz2module.c | 1 + Modules/_codecsmodule.c | 1 + Modules/_collectionsmodule.c | 1 + Modules/_contextvarsmodule.c | 1 + Modules/_csv.c | 1 + Modules/_ctypes/_ctypes.c | 1 + Modules/_ctypes/_ctypes_test.c | 5 ++- Modules/_curses_panel.c | 1 + Modules/_cursesmodule.c | 3 ++ Modules/_datetimemodule.c | 3 ++ Modules/_dbmmodule.c | 1 + Modules/_decimal/_decimal.c | 1 + Modules/_elementtree.c | 1 + Modules/_functoolsmodule.c | 1 + Modules/_gdbmmodule.c | 1 + Modules/_hashopenssl.c | 1 + Modules/_heapqmodule.c | 1 + Modules/_interpchannelsmodule.c | 1 + Modules/_interpqueuesmodule.c | 1 + Modules/_interpretersmodule.c | 1 + Modules/_io/_iomodule.c | 1 + Modules/_json.c | 1 + Modules/_localemodule.c | 1 + Modules/_lsprof.c | 1 + Modules/_lzmamodule.c | 1 + Modules/_multiprocessing/multiprocessing.c | 1 + Modules/_multiprocessing/posixshmem.c | 5 ++- Modules/_opcode.c | 1 + Modules/_operator.c | 1 + Modules/_pickle.c | 1 + Modules/_posixsubprocess.c | 1 + Modules/_queuemodule.c | 1 + Modules/_randommodule.c | 1 + Modules/_scproxy.c | 1 + Modules/_sqlite/module.c | 1 + Modules/_sre/sre.c | 1 + Modules/_ssl.c | 1 + Modules/_stat.c | 1 + Modules/_statisticsmodule.c | 5 ++- Modules/_struct.c | 1 + Modules/_sysconfig.c | 1 + Modules/_testbuffer.c | 3 ++ Modules/_testcapimodule.c | 3 ++ Modules/_testclinic.c | 3 ++ Modules/_testclinic_limited.c | 3 ++ Modules/_testexternalinspection.c | 6 +++ Modules/_testimportmultiple.c | 25 ++++++----- Modules/_testinternalcapi.c | 1 + Modules/_testlimitedcapi.c | 3 ++ Modules/_testmultiphase.c | 16 ++++++- Modules/_testsinglephase.c | 3 ++ Modules/_threadmodule.c | 1 + Modules/_tkinter.c | 3 ++ Modules/_typingmodule.c | 1 + Modules/_uuidmodule.c | 5 ++- Modules/_weakref.c | 1 + Modules/_winapi.c | 1 + Modules/_xxtestfuzz/_xxtestfuzz.c | 9 +++- Modules/_zoneinfo.c | 1 + Modules/arraymodule.c | 1 + Modules/atexitmodule.c | 1 + Modules/binascii.c | 1 + Modules/cjkcodecs/cjkcodecs.h | 1 + Modules/cjkcodecs/multibytecodec.c | 1 + Modules/cmathmodule.c | 1 + Modules/errnomodule.c | 5 ++- Modules/faulthandler.c | 1 + Modules/fcntlmodule.c | 1 + Modules/gcmodule.c | 1 + Modules/grpmodule.c | 1 + Modules/itertoolsmodule.c | 1 + Modules/mathmodule.c | 1 + Modules/md5module.c | 1 + Modules/mmapmodule.c | 1 + Modules/overlapped.c | 1 + Modules/posixmodule.c | 1 + Modules/pwdmodule.c | 1 + Modules/pyexpat.c | 1 + Modules/readline.c | 3 ++ Modules/resource.c | 1 + Modules/selectmodule.c | 1 + Modules/sha1module.c | 1 + Modules/sha2module.c | 1 + Modules/sha3module.c | 1 + Modules/signalmodule.c | 1 + Modules/socketmodule.c | 1 + Modules/symtablemodule.c | 1 + Modules/syslogmodule.c | 1 + Modules/termios.c | 1 + Modules/timemodule.c | 1 + Modules/unicodedata.c | 1 + Modules/xxlimited.c | 5 ++- Modules/xxlimited_35.c | 4 ++ Modules/xxmodule.c | 1 + Modules/xxsubtype.c | 1 + Modules/zlibmodule.c | 1 + Objects/unicodeobject.c | 1 + PC/_testconsole.c | 1 + PC/msvcrtmodule.c | 1 + PC/winreg.c | 1 + PC/winsound.c | 1 + Python/Python-ast.c | 1 + Python/Python-tokenize.c | 1 + Python/_warnings.c | 1 + Python/import.c | 1 + Python/marshal.c | 1 + 112 files changed, 238 insertions(+), 50 deletions(-) create mode 100644 Lib/test/test_importlib/extension/_test_nonmodule_cases.py diff --git a/Lib/test/test_importlib/extension/_test_nonmodule_cases.py b/Lib/test/test_importlib/extension/_test_nonmodule_cases.py new file mode 100644 index 00000000000000..8ffd18d221df4f --- /dev/null +++ b/Lib/test/test_importlib/extension/_test_nonmodule_cases.py @@ -0,0 +1,44 @@ +import types +import unittest +from test.test_importlib import util + +machinery = util.import_importlib('importlib.machinery') + +from test.test_importlib.extension.test_loader import MultiPhaseExtensionModuleTests + + +class NonModuleExtensionTests: + setUp = MultiPhaseExtensionModuleTests.setUp + load_module_by_name = MultiPhaseExtensionModuleTests.load_module_by_name + + def _test_nonmodule(self): + # Test returning a non-module object from create works. + name = self.name + '_nonmodule' + mod = self.load_module_by_name(name) + self.assertNotEqual(type(mod), type(unittest)) + self.assertEqual(mod.three, 3) + + # issue 27782 + def test_nonmodule_with_methods(self): + # Test creating a non-module object with methods defined. + name = self.name + '_nonmodule_with_methods' + mod = self.load_module_by_name(name) + self.assertNotEqual(type(mod), type(unittest)) + self.assertEqual(mod.three, 3) + self.assertEqual(mod.bar(10, 1), 9) + + def test_null_slots(self): + # Test that NULL slots aren't a problem. + name = self.name + '_null_slots' + module = self.load_module_by_name(name) + self.assertIsInstance(module, types.ModuleType) + self.assertEqual(module.__name__, name) + + +(Frozen_NonModuleExtensionTests, + Source_NonModuleExtensionTests + ) = util.test_both(NonModuleExtensionTests, machinery=machinery) + + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/test/test_importlib/extension/test_loader.py b/Lib/test/test_importlib/extension/test_loader.py index 7607f0e0857595..0dd21e079eba22 100644 --- a/Lib/test/test_importlib/extension/test_loader.py +++ b/Lib/test/test_importlib/extension/test_loader.py @@ -10,7 +10,8 @@ import warnings import importlib.util import importlib -from test.support import MISSING_C_DOCSTRINGS +from test import support +from test.support import MISSING_C_DOCSTRINGS, script_helper class LoaderTests: @@ -325,29 +326,6 @@ def test_unloadable_nonascii(self): self.load_module_by_name(name) self.assertEqual(cm.exception.name, name) - def test_nonmodule(self): - # Test returning a non-module object from create works. - name = self.name + '_nonmodule' - mod = self.load_module_by_name(name) - self.assertNotEqual(type(mod), type(unittest)) - self.assertEqual(mod.three, 3) - - # issue 27782 - def test_nonmodule_with_methods(self): - # Test creating a non-module object with methods defined. - name = self.name + '_nonmodule_with_methods' - mod = self.load_module_by_name(name) - self.assertNotEqual(type(mod), type(unittest)) - self.assertEqual(mod.three, 3) - self.assertEqual(mod.bar(10, 1), 9) - - def test_null_slots(self): - # Test that NULL slots aren't a problem. - name = self.name + '_null_slots' - module = self.load_module_by_name(name) - self.assertIsInstance(module, types.ModuleType) - self.assertEqual(module.__name__, name) - def test_bad_modules(self): # Test SystemError is raised for misbehaving extensions. for name_base in [ @@ -401,5 +379,14 @@ def test_nonascii(self): ) = util.test_both(MultiPhaseExtensionModuleTests, machinery=machinery) +class NonModuleExtensionTests(unittest.TestCase): + def test_nonmodule_cases(self): + # The test cases in this file cause the GIL to be enabled permanently + # in free-threaded builds, so they are run in a subprocess to isolate + # this effect. + script = support.findfile("test_importlib/extension/_test_nonmodule_cases.py") + script_helper.run_test_script(script) + + if __name__ == '__main__': unittest.main() diff --git a/Modules/_abc.c b/Modules/_abc.c index f2a523e6f2fc27..4f4b24b035db4a 100644 --- a/Modules/_abc.c +++ b/Modules/_abc.c @@ -970,6 +970,7 @@ _abcmodule_free(void *module) static PyModuleDef_Slot _abcmodule_slots[] = { {Py_mod_exec, _abcmodule_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 0873d32a9ec1a5..a26714f9755df5 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -3795,6 +3795,7 @@ module_exec(PyObject *mod) static struct PyModuleDef_Slot module_slots[] = { {Py_mod_exec, module_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL}, }; diff --git a/Modules/_bisectmodule.c b/Modules/_bisectmodule.c index 9e0fd336419b44..56322c48b7cd35 100644 --- a/Modules/_bisectmodule.c +++ b/Modules/_bisectmodule.c @@ -462,6 +462,7 @@ bisect_modexec(PyObject *m) static PyModuleDef_Slot bisect_slots[] = { {Py_mod_exec, bisect_modexec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_blake2/blake2module.c b/Modules/_blake2/blake2module.c index 5df9fd3df493ee..78242214764f2b 100644 --- a/Modules/_blake2/blake2module.c +++ b/Modules/_blake2/blake2module.c @@ -137,6 +137,7 @@ blake2_exec(PyObject *m) static PyModuleDef_Slot _blake2_slots[] = { {Py_mod_exec, blake2_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c index 3d0d4ee5e79c2b..661847ad26702e 100644 --- a/Modules/_bz2module.c +++ b/Modules/_bz2module.c @@ -802,6 +802,7 @@ _bz2_free(void *module) static struct PyModuleDef_Slot _bz2_slots[] = { {Py_mod_exec, _bz2_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_codecsmodule.c b/Modules/_codecsmodule.c index c31c1b6d6f2bbc..32373f0799bfeb 100644 --- a/Modules/_codecsmodule.c +++ b/Modules/_codecsmodule.c @@ -1050,6 +1050,7 @@ static PyMethodDef _codecs_functions[] = { static PyModuleDef_Slot _codecs_slots[] = { {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 309d63c9bf7cbe..b865351c93d2d8 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -2817,6 +2817,7 @@ collections_exec(PyObject *module) { static struct PyModuleDef_Slot collections_slots[] = { {Py_mod_exec, collections_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_contextvarsmodule.c b/Modules/_contextvarsmodule.c index f621c1de6d42d6..3f96f07909b69a 100644 --- a/Modules/_contextvarsmodule.c +++ b/Modules/_contextvarsmodule.c @@ -45,6 +45,7 @@ _contextvars_exec(PyObject *m) static struct PyModuleDef_Slot _contextvars_slots[] = { {Py_mod_exec, _contextvars_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_csv.c b/Modules/_csv.c index ac948f417cebf5..9d6b66d4938687 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -1796,6 +1796,7 @@ csv_exec(PyObject *module) { static PyModuleDef_Slot csv_slots[] = { {Py_mod_exec, csv_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 3cb0b24668eb2a..1b1a0ea549f1e1 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -5948,6 +5948,7 @@ module_free(void *module) static PyModuleDef_Slot module_slots[] = { {Py_mod_exec, _ctypes_mod_exec}, {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c index 1dd3ef19052470..f46f6362ddd03b 100644 --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -1,7 +1,7 @@ -// Need limited C API version 3.12 for Py_MOD_PER_INTERPRETER_GIL_SUPPORTED +// Need limited C API version 3.13 for Py_mod_gil #include "pyconfig.h" // Py_GIL_DISABLED #ifndef Py_GIL_DISABLED -# define Py_LIMITED_API 0x030c0000 +# define Py_LIMITED_API 0x030d0000 #endif // gh-85283: On Windows, Py_LIMITED_API requires Py_BUILD_CORE to not attempt @@ -1167,6 +1167,7 @@ _testfunc_pylist_append(PyObject *list, PyObject *item) static struct PyModuleDef_Slot _ctypes_test_slots[] = { {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_curses_panel.c b/Modules/_curses_panel.c index 2ec8f34c5c220b..125c72dbbe7712 100644 --- a/Modules/_curses_panel.c +++ b/Modules/_curses_panel.c @@ -697,6 +697,7 @@ static PyModuleDef_Slot _curses_slots[] = { // XXX gh-103092: fix isolation. {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED}, //{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index d04d1e973af030..8bf6824b6d83ff 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -4743,6 +4743,9 @@ PyInit__curses(void) m = PyModule_Create(&_cursesmodule); if (m == NULL) return NULL; +#ifdef Py_GIL_DISABLED + PyModule_ExperimentalSetGIL(m, Py_MOD_GIL_NOT_USED); +#endif /* Add some symbolic constants to the module */ d = PyModule_GetDict(m); diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index 06004e258b2eff..00015c5d8c23cb 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -6984,6 +6984,9 @@ PyInit__datetime(void) PyObject *mod = PyModule_Create(&datetimemodule); if (mod == NULL) return NULL; +#ifdef Py_GIL_DISABLED + PyModule_ExperimentalSetGIL(mod, Py_MOD_GIL_NOT_USED); +#endif if (_datetime_exec(mod) < 0) { Py_DECREF(mod); diff --git a/Modules/_dbmmodule.c b/Modules/_dbmmodule.c index ee33fe625be3d7..1be4234aad3291 100644 --- a/Modules/_dbmmodule.c +++ b/Modules/_dbmmodule.c @@ -616,6 +616,7 @@ _dbm_module_free(void *module) static PyModuleDef_Slot _dbmmodule_slots[] = { {Py_mod_exec, _dbm_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index fa425f4f740d31..213faf4df1fbca 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -6145,6 +6145,7 @@ decimal_free(void *module) static struct PyModuleDef_Slot _decimal_slots[] = { {Py_mod_exec, _decimal_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL}, }; diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index aaa0cad76ae5c4..b11983d2caa2d1 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -4463,6 +4463,7 @@ module_exec(PyObject *m) static struct PyModuleDef_Slot elementtree_slots[] = { {Py_mod_exec, module_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL}, }; diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index 406fcf0da2f7e4..261b11477e0d01 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -1547,6 +1547,7 @@ _functools_free(void *module) static struct PyModuleDef_Slot _functools_slots[] = { {Py_mod_exec, _functools_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_gdbmmodule.c b/Modules/_gdbmmodule.c index db868c18160fda..df7fba67810ed0 100644 --- a/Modules/_gdbmmodule.c +++ b/Modules/_gdbmmodule.c @@ -825,6 +825,7 @@ _gdbm_module_free(void *module) static PyModuleDef_Slot _gdbm_module_slots[] = { {Py_mod_exec, _gdbm_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index d0b46810dc1489..14d9c186151232 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -2289,6 +2289,7 @@ static PyModuleDef_Slot hashlib_slots[] = { {Py_mod_exec, hashlib_init_constructors}, {Py_mod_exec, hashlib_exception}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_heapqmodule.c b/Modules/_heapqmodule.c index 9d4ec256ee9e3e..695ce22f8049df 100644 --- a/Modules/_heapqmodule.c +++ b/Modules/_heapqmodule.c @@ -681,6 +681,7 @@ heapq_exec(PyObject *m) static struct PyModuleDef_Slot heapq_slots[] = { {Py_mod_exec, heapq_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_interpchannelsmodule.c b/Modules/_interpchannelsmodule.c index 43c96584790fa0..ff8dacf5bd1ad0 100644 --- a/Modules/_interpchannelsmodule.c +++ b/Modules/_interpchannelsmodule.c @@ -3326,6 +3326,7 @@ module_exec(PyObject *mod) static struct PyModuleDef_Slot module_slots[] = { {Py_mod_exec, module_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL}, }; diff --git a/Modules/_interpqueuesmodule.c b/Modules/_interpqueuesmodule.c index 46801bd416495a..556953db6b8039 100644 --- a/Modules/_interpqueuesmodule.c +++ b/Modules/_interpqueuesmodule.c @@ -1830,6 +1830,7 @@ module_exec(PyObject *mod) static struct PyModuleDef_Slot module_slots[] = { {Py_mod_exec, module_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL}, }; diff --git a/Modules/_interpretersmodule.c b/Modules/_interpretersmodule.c index 8fea56977ef3fe..86a4113dcc16f1 100644 --- a/Modules/_interpretersmodule.c +++ b/Modules/_interpretersmodule.c @@ -1519,6 +1519,7 @@ module_exec(PyObject *mod) static struct PyModuleDef_Slot module_slots[] = { {Py_mod_exec, module_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL}, }; diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 173f5b55e5f732..269070fe2b0a42 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -720,6 +720,7 @@ iomodule_exec(PyObject *m) static struct PyModuleDef_Slot iomodule_slots[] = { {Py_mod_exec, iomodule_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL}, }; diff --git a/Modules/_json.c b/Modules/_json.c index c55299899e77fe..fc39f624b723f5 100644 --- a/Modules/_json.c +++ b/Modules/_json.c @@ -1780,6 +1780,7 @@ _json_exec(PyObject *module) static PyModuleDef_Slot _json_slots[] = { {Py_mod_exec, _json_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_localemodule.c b/Modules/_localemodule.c index fe8e4c5e30035b..d4923442478b3e 100644 --- a/Modules/_localemodule.c +++ b/Modules/_localemodule.c @@ -860,6 +860,7 @@ _locale_exec(PyObject *module) static struct PyModuleDef_Slot _locale_slots[] = { {Py_mod_exec, _locale_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c index a76c3dea555783..18be01df5c1377 100644 --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -1006,6 +1006,7 @@ _lsprof_exec(PyObject *module) static PyModuleDef_Slot _lsprofslots[] = { {Py_mod_exec, _lsprof_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c index f6bfbfa62687b8..97f3a8f03da9a8 100644 --- a/Modules/_lzmamodule.c +++ b/Modules/_lzmamodule.c @@ -1604,6 +1604,7 @@ static PyMethodDef lzma_methods[] = { static PyModuleDef_Slot lzma_slots[] = { {Py_mod_exec, lzma_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_multiprocessing/multiprocessing.c b/Modules/_multiprocessing/multiprocessing.c index 1f6ab718a36984..cee8cf7b9a83c0 100644 --- a/Modules/_multiprocessing/multiprocessing.c +++ b/Modules/_multiprocessing/multiprocessing.c @@ -277,6 +277,7 @@ multiprocessing_exec(PyObject *module) static PyModuleDef_Slot multiprocessing_slots[] = { {Py_mod_exec, multiprocessing_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_multiprocessing/posixshmem.c b/Modules/_multiprocessing/posixshmem.c index d332a4e9d9ea0b..aeb2d79de6f9ed 100644 --- a/Modules/_multiprocessing/posixshmem.c +++ b/Modules/_multiprocessing/posixshmem.c @@ -2,10 +2,10 @@ posixshmem - A Python extension that provides shm_open() and shm_unlink() */ -// Need limited C API version 3.12 for Py_MOD_PER_INTERPRETER_GIL_SUPPORTED +// Need limited C API version 3.13 for Py_mod_gil #include "pyconfig.h" // Py_GIL_DISABLED #ifndef Py_GIL_DISABLED -# define Py_LIMITED_API 0x030c0000 +# define Py_LIMITED_API 0x030d0000 #endif #include @@ -128,6 +128,7 @@ static PyMethodDef module_methods[ ] = { static PyModuleDef_Slot module_slots[] = { {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_opcode.c b/Modules/_opcode.c index 5350adb456b859..dee449cb56f382 100644 --- a/Modules/_opcode.c +++ b/Modules/_opcode.c @@ -400,6 +400,7 @@ _opcode_exec(PyObject *m) { static PyModuleDef_Slot module_slots[] = { {Py_mod_exec, _opcode_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_operator.c b/Modules/_operator.c index 1f6496d381adac..10ca8dce0a86d9 100644 --- a/Modules/_operator.c +++ b/Modules/_operator.c @@ -1913,6 +1913,7 @@ operator_exec(PyObject *module) static struct PyModuleDef_Slot operator_slots[] = { {Py_mod_exec, operator_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_pickle.c b/Modules/_pickle.c index d7ffb04c28c2ac..754a326822e0f0 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -7863,6 +7863,7 @@ _pickle_exec(PyObject *m) static PyModuleDef_Slot pickle_slots[] = { {Py_mod_exec, _pickle_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL}, }; diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index b160cd78177a17..daec4ad708dea4 100644 --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -1317,6 +1317,7 @@ static PyMethodDef module_methods[] = { static PyModuleDef_Slot _posixsubprocess_slots[] = { {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_queuemodule.c b/Modules/_queuemodule.c index 5db9b645849fcd..aee8db802d8c3f 100644 --- a/Modules/_queuemodule.c +++ b/Modules/_queuemodule.c @@ -594,6 +594,7 @@ queuemodule_exec(PyObject *module) static PyModuleDef_Slot queuemodule_slots[] = { {Py_mod_exec, queuemodule_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_randommodule.c b/Modules/_randommodule.c index 56b891dfe0f85f..140640ae8fbf3a 100644 --- a/Modules/_randommodule.c +++ b/Modules/_randommodule.c @@ -642,6 +642,7 @@ _random_exec(PyObject *module) static PyModuleDef_Slot _random_slots[] = { {Py_mod_exec, _random_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_scproxy.c b/Modules/_scproxy.c index 042738b4ab83a2..22df847a882ab2 100644 --- a/Modules/_scproxy.c +++ b/Modules/_scproxy.c @@ -239,6 +239,7 @@ static PyMethodDef mod_methods[] = { static PyModuleDef_Slot _scproxy_slots[] = { {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c index 46fed9f13281f3..2c25ee32e58189 100644 --- a/Modules/_sqlite/module.c +++ b/Modules/_sqlite/module.c @@ -758,6 +758,7 @@ module_exec(PyObject *module) static struct PyModuleDef_Slot module_slots[] = { {Py_mod_exec, module_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL}, }; diff --git a/Modules/_sre/sre.c b/Modules/_sre/sre.c index 00fbd9674b8cdd..c1eff63d921de9 100644 --- a/Modules/_sre/sre.c +++ b/Modules/_sre/sre.c @@ -3272,6 +3272,7 @@ sre_exec(PyObject *m) static PyModuleDef_Slot sre_slots[] = { {Py_mod_exec, sre_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL}, }; diff --git a/Modules/_ssl.c b/Modules/_ssl.c index f7fdbf4b6f90cb..e94abc7a6f9363 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -6511,6 +6511,7 @@ static PyModuleDef_Slot sslmodule_slots[] = { {Py_mod_exec, sslmodule_init_strings}, {Py_mod_exec, sslmodule_init_lock}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_stat.c b/Modules/_stat.c index 8059ec2f1f066d..a4f15e8e65e894 100644 --- a/Modules/_stat.c +++ b/Modules/_stat.c @@ -679,6 +679,7 @@ stat_exec(PyObject *module) static PyModuleDef_Slot stat_slots[] = { {Py_mod_exec, stat_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_statisticsmodule.c b/Modules/_statisticsmodule.c index 78a6552c4c9ec0..b84f731ad6a1da 100644 --- a/Modules/_statisticsmodule.c +++ b/Modules/_statisticsmodule.c @@ -1,9 +1,9 @@ /* statistics accelerator C extension: _statistics module. */ -// Need limited C API version 3.12 for Py_MOD_PER_INTERPRETER_GIL_SUPPORTED +// Need limited C API version 3.13 for Py_mod_gil #include "pyconfig.h" // Py_GIL_DISABLED #ifndef Py_GIL_DISABLED -# define Py_LIMITED_API 0x030c0000 +# define Py_LIMITED_API 0x030d0000 #endif #include "Python.h" @@ -136,6 +136,7 @@ PyDoc_STRVAR(statistics_doc, static struct PyModuleDef_Slot _statisticsmodule_slots[] = { {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_struct.c b/Modules/_struct.c index fa2cd37e003e0a..905dcbdeeddc5a 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -2593,6 +2593,7 @@ _structmodule_exec(PyObject *m) static PyModuleDef_Slot _structmodule_slots[] = { {Py_mod_exec, _structmodule_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_sysconfig.c b/Modules/_sysconfig.c index c76b9e6b3ebafa..c50c5cfabc2f1f 100644 --- a/Modules/_sysconfig.c +++ b/Modules/_sysconfig.c @@ -80,6 +80,7 @@ static struct PyMethodDef sysconfig_methods[] = { static PyModuleDef_Slot sysconfig_slots[] = { {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_testbuffer.c b/Modules/_testbuffer.c index cad21bdb4d85ed..47dd5236c3a62a 100644 --- a/Modules/_testbuffer.c +++ b/Modules/_testbuffer.c @@ -2901,6 +2901,9 @@ PyInit__testbuffer(void) if (mod == NULL) { return NULL; } +#ifdef Py_GIL_DISABLED + PyModule_ExperimentalSetGIL(mod, Py_MOD_GIL_NOT_USED); +#endif if (_testbuffer_exec(mod) < 0) { Py_DECREF(mod); return NULL; diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 0bdd252efdabc7..e1495a552c6cfe 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3851,6 +3851,9 @@ PyInit__testcapi(void) m = PyModule_Create(&_testcapimodule); if (m == NULL) return NULL; +#ifdef Py_GIL_DISABLED + PyModule_ExperimentalSetGIL(m, Py_MOD_GIL_NOT_USED); +#endif Py_SET_TYPE(&_HashInheritanceTester_Type, &PyType_Type); if (PyType_Ready(&_HashInheritanceTester_Type) < 0) { diff --git a/Modules/_testclinic.c b/Modules/_testclinic.c index 454173b434fb6b..badcf58a6ec855 100644 --- a/Modules/_testclinic.c +++ b/Modules/_testclinic.c @@ -1955,6 +1955,9 @@ PyInit__testclinic(void) if (m == NULL) { return NULL; } +#ifdef Py_GIL_DISABLED + PyModule_ExperimentalSetGIL(m, Py_MOD_GIL_NOT_USED); +#endif if (PyModule_AddType(m, &TestClass) < 0) { goto error; } diff --git a/Modules/_testclinic_limited.c b/Modules/_testclinic_limited.c index 29f1b7c13e4c50..d5f98085f84225 100644 --- a/Modules/_testclinic_limited.c +++ b/Modules/_testclinic_limited.c @@ -146,5 +146,8 @@ PyInit__testclinic_limited(void) if (m == NULL) { return NULL; } +#ifdef Py_GIL_DISABLED + PyModule_ExperimentalSetGIL(m, Py_MOD_GIL_NOT_USED); +#endif return m; } diff --git a/Modules/_testexternalinspection.c b/Modules/_testexternalinspection.c index e2f96cdad5c58e..d9c65fe253f8d3 100644 --- a/Modules/_testexternalinspection.c +++ b/Modules/_testexternalinspection.c @@ -627,6 +627,12 @@ PyMODINIT_FUNC PyInit__testexternalinspection(void) { PyObject* mod = PyModule_Create(&module); + if (mod == NULL) { + return NULL; + } +#ifdef Py_GIL_DISABLED + PyModule_ExperimentalSetGIL(mod, Py_MOD_GIL_NOT_USED); +#endif int rc = PyModule_AddIntConstant(mod, "PROCESS_VM_READV_SUPPORTED", HAVE_PROCESS_VM_READV); if (rc < 0) { Py_DECREF(mod); diff --git a/Modules/_testimportmultiple.c b/Modules/_testimportmultiple.c index a65ca513a12516..4c0213a2d90652 100644 --- a/Modules/_testimportmultiple.c +++ b/Modules/_testimportmultiple.c @@ -6,18 +6,23 @@ #include "pyconfig.h" // Py_GIL_DISABLED #ifndef Py_GIL_DISABLED -# define Py_LIMITED_API 0x03020000 +# define Py_LIMITED_API 0x030d0000 #endif #include +static PyModuleDef_Slot shared_slots[] = { + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {0, NULL}, +}; + static struct PyModuleDef _testimportmultiple = { PyModuleDef_HEAD_INIT, "_testimportmultiple", "_testimportmultiple doc", - -1, - NULL, + 0, NULL, + shared_slots, NULL, NULL, NULL @@ -25,16 +30,16 @@ static struct PyModuleDef _testimportmultiple = { PyMODINIT_FUNC PyInit__testimportmultiple(void) { - return PyModule_Create(&_testimportmultiple); + return PyModuleDef_Init(&_testimportmultiple); } static struct PyModuleDef _foomodule = { PyModuleDef_HEAD_INIT, "_testimportmultiple_foo", "_testimportmultiple_foo doc", - -1, - NULL, + 0, NULL, + shared_slots, NULL, NULL, NULL @@ -42,21 +47,21 @@ static struct PyModuleDef _foomodule = { PyMODINIT_FUNC PyInit__testimportmultiple_foo(void) { - return PyModule_Create(&_foomodule); + return PyModuleDef_Init(&_foomodule); } static struct PyModuleDef _barmodule = { PyModuleDef_HEAD_INIT, "_testimportmultiple_bar", "_testimportmultiple_bar doc", - -1, - NULL, + 0, NULL, + shared_slots, NULL, NULL, NULL }; PyMODINIT_FUNC PyInit__testimportmultiple_bar(void){ - return PyModule_Create(&_barmodule); + return PyModuleDef_Init(&_barmodule); } diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index b0bba3422a50a0..9c0a583df64741 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -2109,6 +2109,7 @@ module_exec(PyObject *module) static struct PyModuleDef_Slot module_slots[] = { {Py_mod_exec, module_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL}, }; diff --git a/Modules/_testlimitedcapi.c b/Modules/_testlimitedcapi.c index 598071fe0ddbad..f88476f4be2054 100644 --- a/Modules/_testlimitedcapi.c +++ b/Modules/_testlimitedcapi.c @@ -25,6 +25,9 @@ PyInit__testlimitedcapi(void) if (mod == NULL) { return NULL; } +#ifdef Py_GIL_DISABLED + PyModule_ExperimentalSetGIL(mod, Py_MOD_GIL_NOT_USED); +#endif if (_PyTestLimitedCAPI_Init_Abstract(mod) < 0) { return NULL; diff --git a/Modules/_testmultiphase.c b/Modules/_testmultiphase.c index 21c5f696a4f2ec..693b288477e53e 100644 --- a/Modules/_testmultiphase.c +++ b/Modules/_testmultiphase.c @@ -431,6 +431,7 @@ static int execfunc(PyObject *m) static PyModuleDef_Slot main_slots[] = { {Py_mod_exec, execfunc}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL}, }; @@ -519,13 +520,18 @@ PyInit__testmultiphase_nonmodule_with_methods(void) /**** Non-ASCII-named modules ****/ +static PyModuleDef_Slot nonascii_slots[] = { + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {0, NULL}, +}; + static PyModuleDef def_nonascii_latin = { \ PyModuleDef_HEAD_INIT, /* m_base */ "_testmultiphase_nonascii_latin", /* m_name */ PyDoc_STR("Module named in Czech"), /* m_doc */ 0, /* m_size */ NULL, /* m_methods */ - NULL, /* m_slots */ + nonascii_slots, /* m_slots */ NULL, /* m_traverse */ NULL, /* m_clear */ NULL, /* m_free */ @@ -543,7 +549,7 @@ static PyModuleDef def_nonascii_kana = { \ PyDoc_STR("Module named in Japanese"), /* m_doc */ 0, /* m_size */ NULL, /* m_methods */ - NULL, /* m_slots */ + nonascii_slots, /* m_slots */ NULL, /* m_traverse */ NULL, /* m_clear */ NULL, /* m_free */ @@ -757,6 +763,7 @@ static PyModuleDef_Slot slots_nonmodule_with_exec_slots[] = { {Py_mod_create, createfunc_nonmodule}, {Py_mod_exec, execfunc}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL}, }; @@ -778,6 +785,7 @@ execfunc_err(PyObject *mod) static PyModuleDef_Slot slots_exec_err[] = { {Py_mod_exec, execfunc_err}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL}, }; @@ -800,6 +808,7 @@ execfunc_raise(PyObject *spec) static PyModuleDef_Slot slots_exec_raise[] = { {Py_mod_exec, execfunc_raise}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL}, }; @@ -822,6 +831,7 @@ execfunc_unreported_exception(PyObject *mod) static PyModuleDef_Slot slots_exec_unreported_exception[] = { {Py_mod_exec, execfunc_unreported_exception}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL}, }; @@ -857,6 +867,7 @@ meth_state_access_exec(PyObject *m) static PyModuleDef_Slot meth_state_access_slots[] = { {Py_mod_exec, meth_state_access_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; @@ -903,6 +914,7 @@ PyInit__test_module_state_shared(void) static PyModuleDef_Slot slots_multiple_multiple_interpreters_slots[] = { {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL}, }; diff --git a/Modules/_testsinglephase.c b/Modules/_testsinglephase.c index 092673a9ea43e1..0d8a61b4aed185 100644 --- a/Modules/_testsinglephase.c +++ b/Modules/_testsinglephase.c @@ -305,6 +305,9 @@ init__testsinglephase_basic(PyModuleDef *def) if (module == NULL) { return NULL; } +#ifdef Py_GIL_DISABLED + PyModule_ExperimentalSetGIL(module, Py_MOD_GIL_NOT_USED); +#endif module_state *state = &global_state.module; // It may have been set by a previous run or under a different name. diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index 5aa719c3834e61..a94f3e2f40be3e 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -2543,6 +2543,7 @@ The 'threading' module provides a more convenient interface."); static PyModuleDef_Slot thread_module_slots[] = { {Py_mod_exec, thread_module_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index e3789867dc085f..ecb7ca8de62ef1 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -3205,6 +3205,9 @@ PyInit__tkinter(void) m = PyModule_Create(&_tkintermodule); if (m == NULL) return NULL; +#ifdef Py_GIL_DISABLED + PyModule_ExperimentalSetGIL(m, Py_MOD_GIL_NOT_USED); +#endif Tkinter_TclError = PyErr_NewException("_tkinter.TclError", NULL, NULL); if (PyModule_AddObjectRef(m, "TclError", Tkinter_TclError)) { diff --git a/Modules/_typingmodule.c b/Modules/_typingmodule.c index 9ea72bf89ce0b2..2e8d2a019600b4 100644 --- a/Modules/_typingmodule.c +++ b/Modules/_typingmodule.c @@ -69,6 +69,7 @@ _typing_exec(PyObject *m) static struct PyModuleDef_Slot _typingmodule_slots[] = { {Py_mod_exec, _typing_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_uuidmodule.c b/Modules/_uuidmodule.c index 052cb9fef3b21c..c5e78b1510b5e3 100644 --- a/Modules/_uuidmodule.c +++ b/Modules/_uuidmodule.c @@ -3,10 +3,10 @@ * DCE compatible Universally Unique Identifier library. */ -// Need limited C API version 3.12 for Py_MOD_PER_INTERPRETER_GIL_SUPPORTED +// Need limited C API version 3.13 for Py_mod_gil #include "pyconfig.h" // Py_GIL_DISABLED #ifndef Py_GIL_DISABLED -# define Py_LIMITED_API 0x030c0000 +# define Py_LIMITED_API 0x030d0000 #endif #include "Python.h" @@ -111,6 +111,7 @@ static PyMethodDef uuid_methods[] = { static PyModuleDef_Slot uuid_slots[] = { {Py_mod_exec, uuid_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_weakref.c b/Modules/_weakref.c index 1ea3ed5e40b761..a5c15c0f10b930 100644 --- a/Modules/_weakref.c +++ b/Modules/_weakref.c @@ -171,6 +171,7 @@ weakref_exec(PyObject *module) static struct PyModuleDef_Slot weakref_slots[] = { {Py_mod_exec, weakref_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_winapi.c b/Modules/_winapi.c index 57b8bdc7ea2448..7bc1f6350851cb 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -3141,6 +3141,7 @@ static int winapi_exec(PyObject *m) static PyModuleDef_Slot winapi_slots[] = { {Py_mod_exec, winapi_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/_xxtestfuzz/_xxtestfuzz.c b/Modules/_xxtestfuzz/_xxtestfuzz.c index a2dbabce71ed67..2952d7043e01fe 100644 --- a/Modules/_xxtestfuzz/_xxtestfuzz.c +++ b/Modules/_xxtestfuzz/_xxtestfuzz.c @@ -28,13 +28,18 @@ static PyMethodDef module_methods[] = { {NULL}, }; +static PyModuleDef_Slot module_slots[] = { + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {0, NULL}, +}; + static struct PyModuleDef _fuzzmodule = { PyModuleDef_HEAD_INIT, "_fuzz", NULL, 0, module_methods, - NULL, + module_slots, NULL, NULL, NULL @@ -43,5 +48,5 @@ static struct PyModuleDef _fuzzmodule = { PyMODINIT_FUNC PyInit__xxtestfuzz(void) { - return PyModule_Create(&_fuzzmodule); + return PyModuleDef_Init(&_fuzzmodule); } diff --git a/Modules/_zoneinfo.c b/Modules/_zoneinfo.c index fcd4af64df0be9..38c3f0c45d803f 100644 --- a/Modules/_zoneinfo.c +++ b/Modules/_zoneinfo.c @@ -2760,6 +2760,7 @@ zoneinfomodule_exec(PyObject *m) static PyModuleDef_Slot zoneinfomodule_slots[] = { {Py_mod_exec, zoneinfomodule_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL}, }; diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index 317f4974814945..a3b833d47cd9ea 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -3220,6 +3220,7 @@ array_modexec(PyObject *m) static PyModuleDef_Slot arrayslots[] = { {Py_mod_exec, array_modexec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/atexitmodule.c b/Modules/atexitmodule.c index 8e908da2534c55..297a8d74ba3bf4 100644 --- a/Modules/atexitmodule.c +++ b/Modules/atexitmodule.c @@ -322,6 +322,7 @@ Two public functions, register and unregister, are defined.\n\ static PyModuleDef_Slot atexitmodule_slots[] = { {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/binascii.c b/Modules/binascii.c index 86493241a1fb7e..250f03a9531eed 100644 --- a/Modules/binascii.c +++ b/Modules/binascii.c @@ -1278,6 +1278,7 @@ binascii_exec(PyObject *module) static PyModuleDef_Slot binascii_slots[] = { {Py_mod_exec, binascii_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/cjkcodecs/cjkcodecs.h b/Modules/cjkcodecs/cjkcodecs.h index 766f82983025e4..2b446ba5226ac0 100644 --- a/Modules/cjkcodecs/cjkcodecs.h +++ b/Modules/cjkcodecs/cjkcodecs.h @@ -503,6 +503,7 @@ static struct PyMethodDef _cjk_methods[] = { static PyModuleDef_Slot _cjk_slots[] = { {Py_mod_exec, _cjk_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/cjkcodecs/multibytecodec.c b/Modules/cjkcodecs/multibytecodec.c index e5433d7dd85306..1c671adb4ff188 100644 --- a/Modules/cjkcodecs/multibytecodec.c +++ b/Modules/cjkcodecs/multibytecodec.c @@ -2094,6 +2094,7 @@ static struct PyMethodDef _multibytecodec_methods[] = { static PyModuleDef_Slot _multibytecodec_slots[] = { {Py_mod_exec, _multibytecodec_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c index 57bc55632be485..d901b350bc5343 100644 --- a/Modules/cmathmodule.c +++ b/Modules/cmathmodule.c @@ -1363,6 +1363,7 @@ cmath_exec(PyObject *mod) static PyModuleDef_Slot cmath_slots[] = { {Py_mod_exec, cmath_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/errnomodule.c b/Modules/errnomodule.c index 97e5f0180d76fb..3f96f2f846d612 100644 --- a/Modules/errnomodule.c +++ b/Modules/errnomodule.c @@ -1,9 +1,9 @@ /* Errno module */ -// Need limited C API version 3.12 for Py_MOD_PER_INTERPRETER_GIL_SUPPORTED +// Need limited C API version 3.13 for Py_mod_gil #include "pyconfig.h" // Py_GIL_DISABLED #ifndef Py_GIL_DISABLED -# define Py_LIMITED_API 0x030c0000 +# define Py_LIMITED_API 0x030d0000 #endif #include "Python.h" @@ -951,6 +951,7 @@ errno_exec(PyObject *module) static PyModuleDef_Slot errno_slots[] = { {Py_mod_exec, errno_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c index c70d43a36b5cc7..cfa3cbdc34bc86 100644 --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -1292,6 +1292,7 @@ static PyModuleDef_Slot faulthandler_slots[] = { {Py_mod_exec, PyExec_faulthandler}, // XXX gh-103092: fix isolation. //{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/fcntlmodule.c b/Modules/fcntlmodule.c index e24e5f98f4bc4d..b6eeec2c66f6e5 100644 --- a/Modules/fcntlmodule.c +++ b/Modules/fcntlmodule.c @@ -745,6 +745,7 @@ fcntl_exec(PyObject *module) static PyModuleDef_Slot fcntl_slots[] = { {Py_mod_exec, fcntl_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 8a1b483eddae35..57e4aae9ed557e 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -535,6 +535,7 @@ gcmodule_exec(PyObject *module) static PyModuleDef_Slot gcmodule_slots[] = { {Py_mod_exec, gcmodule_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/grpmodule.c b/Modules/grpmodule.c index a1fa6cf20f71fd..f7d3e12f347ec2 100644 --- a/Modules/grpmodule.c +++ b/Modules/grpmodule.c @@ -342,6 +342,7 @@ grpmodule_exec(PyObject *module) static PyModuleDef_Slot grpmodule_slots[] = { {Py_mod_exec, grpmodule_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 6ee447ef6a8cd6..05c464d1b7aa35 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -4751,6 +4751,7 @@ itertoolsmodule_exec(PyObject *mod) static struct PyModuleDef_Slot itertoolsmodule_slots[] = { {Py_mod_exec, itertoolsmodule_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 8ba0431f4a47b7..a3cbfc383761a0 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -4177,6 +4177,7 @@ static PyMethodDef math_methods[] = { static PyModuleDef_Slot math_slots[] = { {Py_mod_exec, math_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/md5module.c b/Modules/md5module.c index 9cbf11feaa9c32..ef9163e8be5b6c 100644 --- a/Modules/md5module.c +++ b/Modules/md5module.c @@ -375,6 +375,7 @@ md5_exec(PyObject *m) static PyModuleDef_Slot _md5_slots[] = { {Py_mod_exec, md5_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 0cce7c27f9b16a..dfc16ff4370349 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -1801,6 +1801,7 @@ mmap_exec(PyObject *module) static PyModuleDef_Slot mmap_slots[] = { {Py_mod_exec, mmap_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/overlapped.c b/Modules/overlapped.c index b9881d91ded244..77ee70ae133c85 100644 --- a/Modules/overlapped.c +++ b/Modules/overlapped.c @@ -2070,6 +2070,7 @@ overlapped_exec(PyObject *module) static PyModuleDef_Slot overlapped_slots[] = { {Py_mod_exec, overlapped_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index c9d67ccbb8c908..8537239fbc4516 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -17904,6 +17904,7 @@ posixmodule_exec(PyObject *m) static PyModuleDef_Slot posixmodile_slots[] = { {Py_mod_exec, posixmodule_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/pwdmodule.c b/Modules/pwdmodule.c index f58735aff99799..2240e2078b2d98 100644 --- a/Modules/pwdmodule.c +++ b/Modules/pwdmodule.c @@ -344,6 +344,7 @@ pwdmodule_exec(PyObject *module) static PyModuleDef_Slot pwdmodule_slots[] = { {Py_mod_exec, pwdmodule_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c index f04f96bc2f7601..f67d480f19de00 100644 --- a/Modules/pyexpat.c +++ b/Modules/pyexpat.c @@ -2117,6 +2117,7 @@ pyexpat_free(void *module) static PyModuleDef_Slot pyexpat_slots[] = { {Py_mod_exec, pyexpat_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/readline.c b/Modules/readline.c index c5c34535de0154..f59f8a9834caaf 100644 --- a/Modules/readline.c +++ b/Modules/readline.c @@ -1552,6 +1552,9 @@ PyInit_readline(void) if (m == NULL) return NULL; +#ifdef Py_GIL_DISABLED + PyModule_ExperimentalSetGIL(m, Py_MOD_GIL_NOT_USED); +#endif if (PyModule_AddIntConstant(m, "_READLINE_VERSION", RL_READLINE_VERSION) < 0) { diff --git a/Modules/resource.c b/Modules/resource.c index 8ee07bd0c8054c..3fe18e7c98e3d8 100644 --- a/Modules/resource.c +++ b/Modules/resource.c @@ -513,6 +513,7 @@ resource_exec(PyObject *module) static struct PyModuleDef_Slot resource_slots[] = { {Py_mod_exec, resource_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c index 6ea141ab1f9189..3eaee22c652c28 100644 --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -2802,6 +2802,7 @@ _select_exec(PyObject *m) static PyModuleDef_Slot _select_slots[] = { {Py_mod_exec, _select_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/sha1module.c b/Modules/sha1module.c index 345a6c215eb167..34a427a39b5cf8 100644 --- a/Modules/sha1module.c +++ b/Modules/sha1module.c @@ -371,6 +371,7 @@ _sha1_exec(PyObject *module) static PyModuleDef_Slot _sha1_slots[] = { {Py_mod_exec, _sha1_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/sha2module.c b/Modules/sha2module.c index 60be4228a00a03..7d6a1e40243f9d 100644 --- a/Modules/sha2module.c +++ b/Modules/sha2module.c @@ -866,6 +866,7 @@ static int sha2_exec(PyObject *module) static PyModuleDef_Slot _sha2_slots[] = { {Py_mod_exec, sha2_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/sha3module.c b/Modules/sha3module.c index c30e924a7072f7..084332c1efa0e0 100644 --- a/Modules/sha3module.c +++ b/Modules/sha3module.c @@ -602,6 +602,7 @@ _sha3_exec(PyObject *m) static PyModuleDef_Slot _sha3_slots[] = { {Py_mod_exec, _sha3_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index 08fedeacd96d28..7de5ebe0899b35 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -1698,6 +1698,7 @@ _signal_module_free(void *module) static PyModuleDef_Slot signal_slots[] = { {Py_mod_exec, signal_module_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 7720d59e46590e..daec560ddfcac7 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -8896,6 +8896,7 @@ socket_exec(PyObject *m) static struct PyModuleDef_Slot socket_slots[] = { {Py_mod_exec, socket_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL}, }; diff --git a/Modules/symtablemodule.c b/Modules/symtablemodule.c index ddc9ac3324356d..b4dbb54c3b47b0 100644 --- a/Modules/symtablemodule.c +++ b/Modules/symtablemodule.c @@ -110,6 +110,7 @@ symtable_init_constants(PyObject *m) static PyModuleDef_Slot symtable_slots[] = { {Py_mod_exec, symtable_init_constants}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index cb3f2b03990cb8..14e7ca591a076b 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -439,6 +439,7 @@ syslog_exec(PyObject *module) static PyModuleDef_Slot syslog_slots[] = { {Py_mod_exec, syslog_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/termios.c b/Modules/termios.c index a29474d650127f..f2c5a4bafa7012 100644 --- a/Modules/termios.c +++ b/Modules/termios.c @@ -1364,6 +1364,7 @@ termios_exec(PyObject *mod) static PyModuleDef_Slot termios_slots[] = { {Py_mod_exec, termios_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/timemodule.c b/Modules/timemodule.c index 3211c7530da0b2..0511339978897a 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c @@ -2128,6 +2128,7 @@ time_module_free(void *module) static struct PyModuleDef_Slot time_slots[] = { {Py_mod_exec, time_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c index 6ae35b9372b830..333ffe68a454e4 100644 --- a/Modules/unicodedata.c +++ b/Modules/unicodedata.c @@ -1668,6 +1668,7 @@ unicodedata_exec(PyObject *module) static PyModuleDef_Slot unicodedata_slots[] = { {Py_mod_exec, unicodedata_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/xxlimited.c b/Modules/xxlimited.c index 3357b8076b67b1..d86741e1dfc18c 100644 --- a/Modules/xxlimited.c +++ b/Modules/xxlimited.c @@ -62,10 +62,10 @@ pass */ -// Need limited C API version 3.12 for Py_MOD_PER_INTERPRETER_GIL_SUPPORTED +// Need limited C API version 3.13 for Py_mod_gil #include "pyconfig.h" // Py_GIL_DISABLED #ifndef Py_GIL_DISABLED -# define Py_LIMITED_API 0x030c0000 +# define Py_LIMITED_API 0x030d0000 #endif #include "Python.h" @@ -395,6 +395,7 @@ xx_modexec(PyObject *m) static PyModuleDef_Slot xx_slots[] = { {Py_mod_exec, xx_modexec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Modules/xxlimited_35.c b/Modules/xxlimited_35.c index 52690d9d10a81f..1063e54217b746 100644 --- a/Modules/xxlimited_35.c +++ b/Modules/xxlimited_35.c @@ -297,6 +297,10 @@ xx_modexec(PyObject *m) static PyModuleDef_Slot xx_slots[] = { {Py_mod_exec, xx_modexec}, +#ifdef Py_GIL_DISABLED + // These definitions are in the limited API, but not until 3.13. + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, +#endif {0, NULL} }; diff --git a/Modules/xxmodule.c b/Modules/xxmodule.c index 1e4e0ea3743ce3..a46bf8f0e64ee2 100644 --- a/Modules/xxmodule.c +++ b/Modules/xxmodule.c @@ -384,6 +384,7 @@ xx_exec(PyObject *m) static struct PyModuleDef_Slot xx_slots[] = { {Py_mod_exec, xx_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL}, }; diff --git a/Modules/xxsubtype.c b/Modules/xxsubtype.c index 560f43e5b3a643..9c548f44558d41 100644 --- a/Modules/xxsubtype.c +++ b/Modules/xxsubtype.c @@ -288,6 +288,7 @@ xxsubtype_exec(PyObject* m) static struct PyModuleDef_Slot xxsubtype_slots[] = { {Py_mod_exec, xxsubtype_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL}, }; diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c index fe9a6d8d4150ab..b115f67f228ba7 100644 --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -2106,6 +2106,7 @@ zlib_exec(PyObject *mod) static PyModuleDef_Slot zlib_slots[] = { {Py_mod_exec, zlib_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 2c259b7e869efe..32cb75c895881c 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -15537,6 +15537,7 @@ static PyMethodDef _string_methods[] = { static PyModuleDef_Slot module_slots[] = { {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/PC/_testconsole.c b/PC/_testconsole.c index f1ace003df483b..010a56be7bc8d3 100644 --- a/PC/_testconsole.c +++ b/PC/_testconsole.c @@ -31,6 +31,7 @@ static int execfunc(PyObject *m) PyModuleDef_Slot testconsole_slots[] = { {Py_mod_exec, execfunc}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL}, }; diff --git a/PC/msvcrtmodule.c b/PC/msvcrtmodule.c index 5ff703217b421f..b170e06b47dd59 100644 --- a/PC/msvcrtmodule.c +++ b/PC/msvcrtmodule.c @@ -656,6 +656,7 @@ exec_module(PyObject* m) static PyModuleDef_Slot msvcrt_slots[] = { {Py_mod_exec, exec_module}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/PC/winreg.c b/PC/winreg.c index 8096d17e43b7bc..efdf8addc06186 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -2179,6 +2179,7 @@ exec_module(PyObject *m) static PyModuleDef_Slot winreg_slots[] = { {Py_mod_exec, exec_module}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/PC/winsound.c b/PC/winsound.c index a6b2dac6ac1466..779c99c503d2d6 100644 --- a/PC/winsound.c +++ b/PC/winsound.c @@ -246,6 +246,7 @@ exec_module(PyObject *module) static PyModuleDef_Slot sound_slots[] = { {Py_mod_exec, exec_module}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Python/Python-ast.c b/Python/Python-ast.c index 60b46263a0d329..1430b2ad112a85 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -17452,6 +17452,7 @@ astmodule_exec(PyObject *m) static PyModuleDef_Slot astmodule_slots[] = { {Py_mod_exec, astmodule_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Python/Python-tokenize.c b/Python/Python-tokenize.c index a7891709b3b44a..41e8107e205b46 100644 --- a/Python/Python-tokenize.c +++ b/Python/Python-tokenize.c @@ -322,6 +322,7 @@ static PyMethodDef tokenize_methods[] = { static PyModuleDef_Slot tokenizemodule_slots[] = { {Py_mod_exec, tokenizemodule_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Python/_warnings.c b/Python/_warnings.c index 2ba704dcaa79b2..793cbc657f3184 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -1498,6 +1498,7 @@ warnings_module_exec(PyObject *module) static PyModuleDef_Slot warnings_slots[] = { {Py_mod_exec, warnings_module_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Python/import.c b/Python/import.c index 56011295f95190..7b3ded3466bdd3 100644 --- a/Python/import.c +++ b/Python/import.c @@ -4054,6 +4054,7 @@ imp_module_exec(PyObject *module) static PyModuleDef_Slot imp_slots[] = { {Py_mod_exec, imp_module_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; diff --git a/Python/marshal.c b/Python/marshal.c index 4bd8bb1d3a9308..ca22d6d679a230 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -1952,6 +1952,7 @@ marshal_module_exec(PyObject *mod) static PyModuleDef_Slot marshalmodule_slots[] = { {Py_mod_exec, marshal_module_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; From 99bc5cb4cb2a1a9ee07a2c445f2256b4dec6ec4d Mon Sep 17 00:00:00 2001 From: Brett Simmers Date: Wed, 1 May 2024 16:10:40 -0700 Subject: [PATCH 13/18] Fix 'gil_slot set but not used' warning --- Objects/moduleobject.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index a356c9d3399fcb..d877edaf5453e1 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -392,6 +392,8 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio ((PyModuleObject*)m)->md_def = def; #ifdef Py_GIL_DISABLED ((PyModuleObject*)m)->md_gil = gil_slot; +#else + (void)gil_slot; #endif } else { if (def->m_size > 0 || def->m_traverse || def->m_clear || def->m_free) { From 6882c13e52564465c3f113150bee82361ed83108 Mon Sep 17 00:00:00 2001 From: Brett Simmers Date: Wed, 1 May 2024 16:15:48 -0700 Subject: [PATCH 14/18] Patch generator for Python-ast.c instead of just the file itself --- Parser/asdl_c.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py index c4df2c52c032bc..1f0be456655b25 100755 --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -1443,6 +1443,7 @@ def visitModule(self, mod): static PyModuleDef_Slot astmodule_slots[] = { {Py_mod_exec, astmodule_exec}, {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL} }; From da63df16d40d0a5e3f9de699729bc27db963e928 Mon Sep 17 00:00:00 2001 From: Brett Simmers Date: Wed, 1 May 2024 16:16:42 -0700 Subject: [PATCH 15/18] Update limited API version for _scproxy.c --- Modules/_scproxy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/_scproxy.c b/Modules/_scproxy.c index 22df847a882ab2..e9170f2ce1ae87 100644 --- a/Modules/_scproxy.c +++ b/Modules/_scproxy.c @@ -3,10 +3,10 @@ * using the SystemConfiguration framework. */ -// Need limited C API version 3.12 for Py_MOD_PER_INTERPRETER_GIL_SUPPORTED +// Need limited C API version 3.13 for Py_mod_gil #include "pyconfig.h" // Py_GIL_DISABLED #ifndef Py_GIL_DISABLED -# define Py_LIMITED_API 0x030c0000 +# define Py_LIMITED_API 0x030d0000 #endif #include From 2998defea4d83c19d1a2e0c52576a88518ed3bf6 Mon Sep 17 00:00:00 2001 From: Brett Simmers Date: Wed, 1 May 2024 16:22:15 -0700 Subject: [PATCH 16/18] Fix _testconsole.c for Windows build --- PC/_testconsole.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PC/_testconsole.c b/PC/_testconsole.c index 010a56be7bc8d3..0dcea866f65d35 100644 --- a/PC/_testconsole.c +++ b/PC/_testconsole.c @@ -1,10 +1,10 @@ /* Testing module for multi-phase initialization of extension modules (PEP 489) */ -// Need limited C API version 3.12 for Py_MOD_PER_INTERPRETER_GIL_SUPPORTED +// Need limited C API version 3.13 for Py_mod_gil #include "pyconfig.h" // Py_GIL_DISABLED #ifndef Py_GIL_DISABLED -# define Py_LIMITED_API 0x030c0000 +# define Py_LIMITED_API 0x030d0000 #endif #include "Python.h" From 77d165203341b03f2046a08b9310d8cb9e82e957 Mon Sep 17 00:00:00 2001 From: Brett Simmers Date: Wed, 1 May 2024 21:35:05 -0700 Subject: [PATCH 17/18] Fix winsound.c for Windows build --- PC/winsound.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PC/winsound.c b/PC/winsound.c index 779c99c503d2d6..094c77ae34d678 100644 --- a/PC/winsound.c +++ b/PC/winsound.c @@ -35,10 +35,10 @@ winsound.PlaySound(None, 0) */ -// Need limited C API version 3.12 for Py_MOD_PER_INTERPRETER_GIL_SUPPORTED +// Need limited C API version 3.13 for Py_mod_gil #include "pyconfig.h" // Py_GIL_DISABLED #ifndef Py_GIL_DISABLED -# define Py_LIMITED_API 0x030c0000 +# define Py_LIMITED_API 0x030d0000 #endif #include From d1fe0ccd8cd4b9dee8bc1bb960d27c05eeb3d726 Mon Sep 17 00:00:00 2001 From: Brett Simmers Date: Thu, 2 May 2024 15:18:12 -0700 Subject: [PATCH 18/18] Mark more modules as not using the GIL --- Modules/_suggestions.c | 14 ++++++++++---- Modules/_testimportmultiple.c | 1 + Modules/_testmultiphase.c | 5 +++++ Modules/_testsinglephase.c | 6 ++++++ Modules/_tracemalloc.c | 3 +++ Python/bltinmodule.c | 3 +++ Python/sysmodule.c | 3 +++ 7 files changed, 31 insertions(+), 4 deletions(-) diff --git a/Modules/_suggestions.c b/Modules/_suggestions.c index 30b524d70c1211..80c7179c4c251c 100644 --- a/Modules/_suggestions.c +++ b/Modules/_suggestions.c @@ -49,15 +49,21 @@ static PyMethodDef module_methods[] = { {NULL, NULL, 0, NULL} // Sentinel }; +static PyModuleDef_Slot module_slots[] = { + {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, + {0, NULL}, +}; + static struct PyModuleDef suggestions_module = { PyModuleDef_HEAD_INIT, "_suggestions", NULL, - -1, - module_methods + 0, + module_methods, + module_slots, }; PyMODINIT_FUNC PyInit__suggestions(void) { - return PyModule_Create(&suggestions_module); + return PyModuleDef_Init(&suggestions_module); } - diff --git a/Modules/_testimportmultiple.c b/Modules/_testimportmultiple.c index 4c0213a2d90652..c147596f88a3a8 100644 --- a/Modules/_testimportmultiple.c +++ b/Modules/_testimportmultiple.c @@ -12,6 +12,7 @@ #include static PyModuleDef_Slot shared_slots[] = { + {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED}, {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL}, }; diff --git a/Modules/_testmultiphase.c b/Modules/_testmultiphase.c index 693b288477e53e..ca3d83233c5dd0 100644 --- a/Modules/_testmultiphase.c +++ b/Modules/_testmultiphase.c @@ -900,6 +900,9 @@ PyInit__test_module_state_shared(void) if (module == NULL) { return NULL; } +#ifdef Py_GIL_DISABLED + PyModule_ExperimentalSetGIL(module, Py_MOD_GIL_NOT_USED); +#endif if (PyModule_AddObjectRef(module, "Error", PyExc_Exception) < 0) { Py_DECREF(module); @@ -932,6 +935,7 @@ PyInit__testmultiphase_multiple_multiple_interpreters_slots(void) static PyModuleDef_Slot non_isolated_slots[] = { {Py_mod_exec, execfunc}, {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL}, }; @@ -952,6 +956,7 @@ static PyModuleDef_Slot shared_gil_only_slots[] = { We put it here explicitly to draw attention to the contrast with Py_MOD_PER_INTERPRETER_GIL_SUPPORTED. */ {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED}, + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, {0, NULL}, }; diff --git a/Modules/_testsinglephase.c b/Modules/_testsinglephase.c index 0d8a61b4aed185..49435b0b159cad 100644 --- a/Modules/_testsinglephase.c +++ b/Modules/_testsinglephase.c @@ -399,6 +399,9 @@ PyInit__testsinglephase_with_reinit(void) if (module == NULL) { return NULL; } +#ifdef Py_GIL_DISABLED + PyModule_ExperimentalSetGIL(module, Py_MOD_GIL_NOT_USED); +#endif assert(get_module_state(module) == NULL); @@ -461,6 +464,9 @@ PyInit__testsinglephase_with_state(void) if (module == NULL) { return NULL; } +#ifdef Py_GIL_DISABLED + PyModule_ExperimentalSetGIL(module, Py_MOD_GIL_NOT_USED); +#endif module_state *state = get_module_state(module); assert(state != NULL); diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c index 6dba3cac01c1c8..55028dc3a65ff4 100644 --- a/Modules/_tracemalloc.c +++ b/Modules/_tracemalloc.c @@ -219,6 +219,9 @@ PyInit__tracemalloc(void) m = PyModule_Create(&module_def); if (m == NULL) return NULL; +#ifdef Py_GIL_DISABLED + PyModule_ExperimentalSetGIL(m, Py_MOD_GIL_NOT_USED); +#endif if (_PyTraceMalloc_Init() < 0) { Py_DECREF(m); diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 7af3ac9c5158d6..6929f72c49877b 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -3124,6 +3124,9 @@ _PyBuiltin_Init(PyInterpreterState *interp) mod = _PyModule_CreateInitialized(&builtinsmodule, PYTHON_API_VERSION); if (mod == NULL) return NULL; +#ifdef Py_GIL_DISABLED + PyModule_ExperimentalSetGIL(mod, Py_MOD_GIL_NOT_USED); +#endif dict = PyModule_GetDict(mod); #ifdef Py_TRACE_REFS diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 726051521cf574..ef6ed469dda060 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -3740,6 +3740,9 @@ _PySys_Create(PyThreadState *tstate, PyObject **sysmod_p) if (sysmod == NULL) { return _PyStatus_ERR("failed to create a module object"); } +#ifdef Py_GIL_DISABLED + PyModule_ExperimentalSetGIL(sysmod, Py_MOD_GIL_NOT_USED); +#endif PyObject *sysdict = PyModule_GetDict(sysmod); if (sysdict == NULL) {