Skip to content

Commit b09c445

Browse files
Update the global cache while still under the main interpreter.
1 parent f9e132f commit b09c445

File tree

2 files changed

+62
-54
lines changed

2 files changed

+62
-54
lines changed

Lib/test/test_import/__init__.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -3014,20 +3014,20 @@ def test_basic_multiple_interpreters_deleted_no_reset(self):
30143014
# * alive in 0 interpreters
30153015
# * module def in _PyRuntime.imports.extensions
30163016
# * mod init func ran for the first time (since reset)
3017-
# * m_copy is NULL (claered when the interpreter was destroyed)
3017+
# * m_copy is still set (owned by main interpreter)
30183018
# * module's global state was initialized, not reset
30193019

30203020
# Use a subinterpreter that sticks around.
30213021
loaded_interp1 = self.import_in_subinterp(interpid1)
30223022
self.check_common(loaded_interp1)
3023-
self.check_semi_fresh(loaded_interp1, loaded_main, base)
3023+
self.check_copied(loaded_interp1, base)
30243024

30253025
# At this point:
30263026
# * alive in 1 interpreter (interp1)
30273027
# * module def still in _PyRuntime.imports.extensions
3028-
# * mod init func ran for the second time (since reset)
3029-
# * m_copy was copied from interp1 (was NULL)
3030-
# * module's global state was updated, not reset
3028+
# * mod init func did not run again
3029+
# * m_copy was not changed
3030+
# * module's global state was not touched
30313031

30323032
# Use a subinterpreter while the previous one is still alive.
30333033
loaded_interp2 = self.import_in_subinterp(interpid2)
@@ -3038,8 +3038,8 @@ def test_basic_multiple_interpreters_deleted_no_reset(self):
30383038
# * alive in 2 interpreters (interp1, interp2)
30393039
# * module def still in _PyRuntime.imports.extensions
30403040
# * mod init func did not run again
3041-
# * m_copy was copied from interp2 (was from interp1)
3042-
# * module's global state was updated, not reset
3041+
# * m_copy was not changed
3042+
# * module's global state was not touched
30433043

30443044
@requires_subinterpreters
30453045
def test_basic_multiple_interpreters_reset_each(self):

Python/import.c

+55-47
Original file line numberDiff line numberDiff line change
@@ -1967,6 +1967,46 @@ import_run_extension(PyThreadState *tstate, PyModInitFunction p0,
19671967
assert(def != NULL);
19681968
}
19691969

1970+
/* Do anything else that should be done
1971+
* while still using the main interpreter. */
1972+
if (res.kind == _Py_ext_module_kind_SINGLEPHASE) {
1973+
/* Remember the filename as the __file__ attribute */
1974+
if (info->filename != NULL) {
1975+
if (PyModule_AddObjectRef(mod, "__file__", info->filename) < 0) {
1976+
PyErr_Clear(); /* Not important enough to report */
1977+
}
1978+
}
1979+
1980+
/* Update global import state. */
1981+
assert(def->m_base.m_index != 0);
1982+
struct singlephase_global_update singlephase = {
1983+
// XXX Modules that share a def should each get their own index,
1984+
// whereas currently they share (which means the per-interpreter
1985+
// cache is less reliable than it should be).
1986+
.m_index=def->m_base.m_index,
1987+
.origin=info->origin,
1988+
};
1989+
// gh-88216: Extensions and def->m_base.m_copy can be updated
1990+
// when the extension module doesn't support sub-interpreters.
1991+
if (def->m_size == -1) {
1992+
/* We will reload from m_copy. */
1993+
assert(def->m_base.m_init == NULL);
1994+
singlephase.m_dict = PyModule_GetDict(mod);
1995+
assert(singlephase.m_dict != NULL);
1996+
}
1997+
else {
1998+
/* We will reload via the init function. */
1999+
assert(def->m_size >= 0);
2000+
assert(def->m_base.m_copy == NULL);
2001+
singlephase.m_init = p0;
2002+
}
2003+
cached = update_global_state_for_extension(
2004+
tstate, info->path, info->name, def, &singlephase);
2005+
if (cached == NULL) {
2006+
goto error;
2007+
}
2008+
}
2009+
19702010
/* Switch back to the subinterpreter. */
19712011
if (main_tstate != tstate) {
19722012
/* Any module we got from the init function will have to be
@@ -2003,63 +2043,31 @@ import_run_extension(PyThreadState *tstate, PyModInitFunction p0,
20032043
if (_PyImport_CheckSubinterpIncompatibleExtensionAllowed(name_buf) < 0) {
20042044
goto error;
20052045
}
2006-
assert(mod != NULL);
2007-
assert(PyModule_Check(mod));
2008-
2009-
/* Remember the filename as the __file__ attribute */
2010-
if (info->filename != NULL) {
2011-
if (PyModule_AddObjectRef(mod, "__file__", info->filename) < 0) {
2012-
PyErr_Clear(); /* Not important enough to report */
2013-
}
2014-
}
2015-
2016-
/* Update global import state. */
2017-
assert(def->m_base.m_index != 0);
2018-
struct singlephase_global_update singlephase = {
2019-
// XXX Modules that share a def should each get their own index,
2020-
// whereas currently they share (which means the per-interpreter
2021-
// cache is less reliable than it should be).
2022-
.m_index=def->m_base.m_index,
2023-
.origin=info->origin,
2024-
};
2025-
// gh-88216: Extensions and def->m_base.m_copy can be updated
2026-
// when the extension module doesn't support sub-interpreters.
2027-
if (def->m_size == -1) {
2028-
/* We will reload from m_copy. */
2029-
assert(def->m_base.m_init == NULL);
2030-
singlephase.m_dict = PyModule_GetDict(mod);
2031-
assert(singlephase.m_dict != NULL);
2032-
}
2033-
else {
2034-
/* We will reload via the init function. */
2035-
assert(def->m_size >= 0);
2036-
assert(def->m_base.m_copy == NULL);
2037-
singlephase.m_init = p0;
2038-
}
2039-
cached = update_global_state_for_extension(
2040-
tstate, info->path, info->name, def, &singlephase);
2041-
if (cached == NULL) {
2042-
goto error;
2043-
}
2046+
assert(!PyErr_Occurred());
20442047

20452048
if (main_tstate != tstate) {
20462049
/* We switched to the main interpreter to run the init
20472050
* function, so now we will "reload" the module from the
20482051
* cached data using the original subinterpreter. */
2049-
Py_CLEAR(mod);
2052+
assert(mod == NULL);
20502053
mod = reload_singlephase_extension(tstate, cached, info);
20512054
if (mod == NULL) {
20522055
goto error;
20532056
}
2057+
assert(!PyErr_Occurred());
2058+
assert(PyModule_Check(mod));
20542059
}
2055-
assert(!PyErr_Occurred());
2056-
2057-
/* Update per-interpreter import state. */
2058-
PyObject *modules = get_modules_dict(tstate, true);
2059-
if (finish_singlephase_extension(
2060-
tstate, mod, cached, info->name, modules) < 0)
2061-
{
2062-
goto error;
2060+
else {
2061+
assert(mod != NULL);
2062+
assert(PyModule_Check(mod));
2063+
2064+
/* Update per-interpreter import state. */
2065+
PyObject *modules = get_modules_dict(tstate, true);
2066+
if (finish_singlephase_extension(
2067+
tstate, mod, cached, info->name, modules) < 0)
2068+
{
2069+
goto error;
2070+
}
20632071
}
20642072
}
20652073

0 commit comments

Comments
 (0)