mirror of https://github.com/python/cpython
gh-99113: Add a check for Py_MOD_PER_INTERPRETER_GIL_SUPPORTED (gh-104206)
Py_MOD_PER_INTERPRETER_GIL_SUPPORTED is a new supported value for Py_mod_multiple_interpreters, added in gh-104205.
This commit is contained in:
parent
3b14b51d11
commit
fff193bbfe
|
@ -1861,6 +1861,26 @@ class SubinterpImportTests(unittest.TestCase):
|
|||
with self.subTest(f'{modname}: not strict'):
|
||||
self.check_compatible_here(modname, filename, strict=False)
|
||||
|
||||
@unittest.skipIf(_testmultiphase is None, "test requires _testmultiphase module")
|
||||
def test_multi_init_extension_per_interpreter_gil_compat(self):
|
||||
modname = '_test_shared_gil_only'
|
||||
filename = _testmultiphase.__file__
|
||||
loader = ExtensionFileLoader(modname, filename)
|
||||
spec = importlib.util.spec_from_loader(modname, loader)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
loader.exec_module(module)
|
||||
sys.modules[modname] = module
|
||||
|
||||
require_extension(module)
|
||||
with self.subTest(f'{modname}: isolated, strict'):
|
||||
self.check_incompatible_here(modname, filename, isolated=True)
|
||||
with self.subTest(f'{modname}: not isolated, strict'):
|
||||
self.check_compatible_here(modname, filename,
|
||||
strict=True, isolated=False)
|
||||
with self.subTest(f'{modname}: not isolated, not strict'):
|
||||
self.check_compatible_here(modname, filename,
|
||||
strict=False, isolated=False)
|
||||
|
||||
def test_python_compat(self):
|
||||
module = 'threading'
|
||||
require_pure_python(module)
|
||||
|
|
|
@ -348,6 +348,8 @@ class MultiPhaseExtensionModuleTests(abc.LoaderTests):
|
|||
'exec_err',
|
||||
'exec_raise',
|
||||
'exec_unreported_exception',
|
||||
'multiple_create_slots',
|
||||
'multiple_multiple_interpreters_slots',
|
||||
]:
|
||||
with self.subTest(name_base):
|
||||
name = self.name + '_' + name_base
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
Multi-phase init extension modules may now indicate that they support
|
||||
running in subinterpreters that have their own GIL. This is done by using
|
||||
``Py_MOD_PER_INTERPRETER_GIL_SUPPORTED`` as the value for the
|
||||
``Py_mod_multiple_interpreters`` module def slot. Otherwise the module, by
|
||||
default, cannot be imported in such subinterpreters. (This does not affect
|
||||
the main interpreter or subinterpreters that do not have their own GIL.) In
|
||||
addition to the isolation that multi-phase init already normally requires,
|
||||
support for per-interpreter GIL involves one additional constraint:
|
||||
thread-safety. If the module has external (linked) dependencies and those
|
||||
libraries have any state that isn't thread-safe then the module must do the
|
||||
additional work to add thread-safety. This should be an uncommon case.
|
|
@ -681,6 +681,27 @@ PyInit__testmultiphase_export_unreported_exception(void)
|
|||
return PyModuleDef_Init(&main_def);
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
createfunc_noop(PyObject *spec, PyModuleDef *def)
|
||||
{
|
||||
return PyModule_New("spam");
|
||||
}
|
||||
|
||||
static PyModuleDef_Slot slots_multiple_create_slots[] = {
|
||||
{Py_mod_create, createfunc_noop},
|
||||
{Py_mod_create, createfunc_noop},
|
||||
{0, NULL},
|
||||
};
|
||||
|
||||
static PyModuleDef def_multiple_create_slots = TEST_MODULE_DEF(
|
||||
"_testmultiphase_multiple_create_slots", slots_multiple_create_slots, NULL);
|
||||
|
||||
PyMODINIT_FUNC
|
||||
PyInit__testmultiphase_multiple_create_slots(void)
|
||||
{
|
||||
return PyModuleDef_Init(&def_multiple_create_slots);
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
createfunc_null(PyObject *spec, PyModuleDef *def)
|
||||
{
|
||||
|
@ -892,7 +913,24 @@ PyInit__test_module_state_shared(void)
|
|||
}
|
||||
|
||||
|
||||
/* multiple interpreters supports */
|
||||
/* multiple interpreters support */
|
||||
|
||||
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},
|
||||
{0, NULL},
|
||||
};
|
||||
|
||||
static PyModuleDef def_multiple_multiple_interpreters_slots = TEST_MODULE_DEF(
|
||||
"_testmultiphase_multiple_multiple_interpreters_slots",
|
||||
slots_multiple_multiple_interpreters_slots,
|
||||
NULL);
|
||||
|
||||
PyMODINIT_FUNC
|
||||
PyInit__testmultiphase_multiple_multiple_interpreters_slots(void)
|
||||
{
|
||||
return PyModuleDef_Init(&def_multiple_multiple_interpreters_slots);
|
||||
}
|
||||
|
||||
static PyModuleDef_Slot non_isolated_slots[] = {
|
||||
{Py_mod_exec, execfunc},
|
||||
|
@ -909,3 +947,23 @@ PyInit__test_non_isolated(void)
|
|||
{
|
||||
return PyModuleDef_Init(&non_isolated_def);
|
||||
}
|
||||
|
||||
|
||||
static PyModuleDef_Slot shared_gil_only_slots[] = {
|
||||
{Py_mod_exec, execfunc},
|
||||
/* Note that Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED is the default.
|
||||
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},
|
||||
{0, NULL},
|
||||
};
|
||||
|
||||
static PyModuleDef shared_gil_only_def = TEST_MODULE_DEF("_test_shared_gil_only",
|
||||
shared_gil_only_slots,
|
||||
testexport_methods);
|
||||
|
||||
PyMODINIT_FUNC
|
||||
PyInit__test_shared_gil_only(void)
|
||||
{
|
||||
return PyModuleDef_Init(&shared_gil_only_def);
|
||||
}
|
||||
|
|
|
@ -323,7 +323,13 @@ PyModule_FromDefAndSpec2(PyModuleDef* def, PyObject *spec, int module_api_versio
|
|||
goto error;
|
||||
}
|
||||
}
|
||||
// XXX Do a similar check once we have PyInterpreterState.ceval.own_gil.
|
||||
else if (multiple_interpreters != Py_MOD_PER_INTERPRETER_GIL_SUPPORTED
|
||||
&& interp->ceval.own_gil
|
||||
&& !_Py_IsMainInterpreter(interp)
|
||||
&& _PyImport_CheckSubinterpIncompatibleExtensionAllowed(name) < 0)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (create) {
|
||||
m = create(spec, def);
|
||||
|
|
Loading…
Reference in New Issue