gh-116322: Add Py_mod_gil module slot (#116882)

This PR adds the ability to enable the GIL if it was disabled at
interpreter startup, and modifies the multi-phase module initialization
path to enable the GIL when loading a module, unless that module's spec
includes a slot indicating it can run safely without the GIL.

PEP 703 called the constant for the slot `Py_mod_gil_not_used`; I went
with `Py_MOD_GIL_NOT_USED` for consistency with gh-104148.

A warning will be issued up to once per interpreter for the first
GIL-using module that is loaded. If `-v` is given, a shorter message
will be printed to stderr every time a GIL-using module is loaded
(including the first one that issues a warning).
This commit is contained in:
Brett Simmers 2024-05-03 08:30:55 -07:00 committed by GitHub
parent 3e818afb9b
commit c2627d6eea
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
123 changed files with 376 additions and 62 deletions

View file

@ -249,6 +249,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;
}
@ -261,6 +264,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 = Py_MOD_GIL_USED;
int has_execution_slots = 0;
const char *name;
int ret;
@ -315,6 +320,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(
@ -374,6 +390,11 @@ 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;
#else
(void)gil_slot;
#endif
} else {
if (def->m_size > 0 || def->m_traverse || def->m_clear || def->m_free) {
PyErr_Format(
@ -415,6 +436,19 @@ error:
return NULL;
}
#ifdef Py_GIL_DISABLED
int
PyModule_ExperimentalSetGIL(PyObject *module, void *gil)
{
if (!PyModule_Check(module)) {
PyErr_BadInternalCall();
return -1;
}
((PyModuleObject *)module)->md_gil = gil;
return 0;
}
#endif
int
PyModule_ExecDef(PyObject *module, PyModuleDef *def)
{
@ -470,6 +504,7 @@ PyModule_ExecDef(PyObject *module, PyModuleDef *def)
}
break;
case Py_mod_multiple_interpreters:
case Py_mod_gil:
/* handled in PyModule_FromDefAndSpec2 */
break;
default: