Skip to content

Commit 52d9d3b

Browse files
ambvshihai1991
andauthored
[3.9] bpo-44050: Extension modules can share state when they don't support sub-interpreters. (GH-27794) (GH-28741)
(cherry picked from commit b9bb748) Co-authored-by: Hai Shi <shihai1992@gmail.com>
1 parent 950b324 commit 52d9d3b

File tree

4 files changed

+61
-1
lines changed

4 files changed

+61
-1
lines changed

Lib/test/test_capi.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,37 @@ def test_mutate_exception(self):
680680

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

683+
def test_module_state_shared_in_global(self):
684+
"""
685+
bpo-44050: Extension module state should be shared between interpreters
686+
when it doesn't support sub-interpreters.
687+
"""
688+
r, w = os.pipe()
689+
self.addCleanup(os.close, r)
690+
self.addCleanup(os.close, w)
691+
692+
script = textwrap.dedent(f"""
693+
import importlib.machinery
694+
import importlib.util
695+
import os
696+
697+
fullname = '_test_module_state_shared'
698+
origin = importlib.util.find_spec('_testmultiphase').origin
699+
loader = importlib.machinery.ExtensionFileLoader(fullname, origin)
700+
spec = importlib.util.spec_from_loader(fullname, loader)
701+
module = importlib.util.module_from_spec(spec)
702+
attr_id = str(id(module.Error)).encode()
703+
704+
os.write({w}, attr_id)
705+
""")
706+
exec(script)
707+
main_attr_id = os.read(r, 100)
708+
709+
ret = support.run_in_subinterp(script)
710+
self.assertEqual(ret, 0)
711+
subinterp_attr_id = os.read(r, 100)
712+
self.assertEqual(main_attr_id, subinterp_attr_id)
713+
683714

684715
class TestThreadState(unittest.TestCase):
685716

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Extensions that indicate they use global state (by setting ``m_size`` to -1)
2+
can again be used in multiple interpreters. This reverts to behavior of
3+
Python 3.8.

Modules/_testmultiphase.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,30 @@ PyInit__testmultiphase_meth_state_access(PyObject *spec)
834834
return PyModuleDef_Init(&def_meth_state_access);
835835
}
836836

837+
static PyModuleDef def_module_state_shared = {
838+
PyModuleDef_HEAD_INIT,
839+
.m_name = "_test_module_state_shared",
840+
.m_doc = PyDoc_STR("Regression Test module for single-phase init."),
841+
.m_size = -1,
842+
};
843+
844+
PyMODINIT_FUNC
845+
PyInit__test_module_state_shared(PyObject *spec)
846+
{
847+
PyObject *module = PyModule_Create(&def_module_state_shared);
848+
if (module == NULL) {
849+
return NULL;
850+
}
851+
852+
Py_INCREF(PyExc_Exception);
853+
if (PyModule_AddObject(module, "Error", PyExc_Exception) < 0) {
854+
Py_DECREF(PyExc_Exception);
855+
Py_DECREF(module);
856+
return NULL;
857+
}
858+
return module;
859+
}
860+
837861

838862
/*** Helper for imp test ***/
839863

Python/import.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -710,7 +710,9 @@ _PyImport_FixupExtensionObject(PyObject *mod, PyObject *name,
710710
return -1;
711711
}
712712

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

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy