Skip to content

Commit

Permalink
bpo-44050: Extension modules can share state when they don't support …
Browse files Browse the repository at this point in the history
…sub-interpreters. (GH-27794) (GH-28738)

Automerge-Triggered-By: GH:encukou
(cherry picked from commit b9bb748)

Co-authored-by: Hai Shi <shihai1992@gmail.com>
  • Loading branch information
miss-islington and shihai1991 committed Oct 5, 2021
1 parent d0d0909 commit d0d2965
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 1 deletion.
31 changes: 31 additions & 0 deletions Lib/test/test_capi.py
Expand Up @@ -762,6 +762,37 @@ def test_mutate_exception(self):

self.assertFalse(hasattr(binascii.Error, "foobar"))

def test_module_state_shared_in_global(self):
"""
bpo-44050: Extension module state should be shared between interpreters
when it doesn't support sub-interpreters.
"""
r, w = os.pipe()
self.addCleanup(os.close, r)
self.addCleanup(os.close, w)

script = textwrap.dedent(f"""
import importlib.machinery
import importlib.util
import os
fullname = '_test_module_state_shared'
origin = importlib.util.find_spec('_testmultiphase').origin
loader = importlib.machinery.ExtensionFileLoader(fullname, origin)
spec = importlib.util.spec_from_loader(fullname, loader)
module = importlib.util.module_from_spec(spec)
attr_id = str(id(module.Error)).encode()
os.write({w}, attr_id)
""")
exec(script)
main_attr_id = os.read(r, 100)

ret = support.run_in_subinterp(script)
self.assertEqual(ret, 0)
subinterp_attr_id = os.read(r, 100)
self.assertEqual(main_attr_id, subinterp_attr_id)


class TestThreadState(unittest.TestCase):

Expand Down
@@ -0,0 +1,3 @@
Extensions that indicate they use global state (by setting ``m_size`` to -1)
can again be used in multiple interpreters. This reverts to behavior of
Python 3.8.
22 changes: 22 additions & 0 deletions Modules/_testmultiphase.c
Expand Up @@ -844,6 +844,28 @@ PyInit__testmultiphase_meth_state_access(PyObject *spec)
return PyModuleDef_Init(&def_meth_state_access);
}

static PyModuleDef def_module_state_shared = {
PyModuleDef_HEAD_INIT,
.m_name = "_test_module_state_shared",
.m_doc = PyDoc_STR("Regression Test module for single-phase init."),
.m_size = -1,
};

PyMODINIT_FUNC
PyInit__test_module_state_shared(PyObject *spec)
{
PyObject *module = PyModule_Create(&def_module_state_shared);
if (module == NULL) {
return NULL;
}

if (PyModule_AddObjectRef(module, "Error", PyExc_Exception) < 0) {
Py_DECREF(module);
return NULL;
}
return module;
}


/*** Helper for imp test ***/

Expand Down
4 changes: 3 additions & 1 deletion Python/import.c
Expand Up @@ -441,7 +441,9 @@ _PyImport_FixupExtensionObject(PyObject *mod, PyObject *name,
return -1;
}

if (_Py_IsMainInterpreter(tstate->interp)) {
// bpo-44050: Extensions and def->m_base.m_copy can be updated
// when the extension module doesn't support sub-interpreters.
if (_Py_IsMainInterpreter(tstate->interp) || def->m_size == -1) {
if (def->m_size == -1) {
if (def->m_base.m_copy) {
/* Somebody already imported the module,
Expand Down

0 comments on commit d0d2965

Please sign in to comment.