mirror of https://github.com/python/cpython
gh-117953: Let update_global_state_for_extension() Caller Decide If Singlephase or Not (gh-118193)
This change makes other upcoming changes simpler.
This commit is contained in:
parent
03e3e31723
commit
1acd249798
113
Python/import.c
113
Python/import.c
|
@ -1185,19 +1185,51 @@ is_core_module(PyInterpreterState *interp, PyObject *name, PyObject *path)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
static bool
|
||||||
|
is_singlephase(PyModuleDef *def)
|
||||||
|
{
|
||||||
|
if (def == NULL) {
|
||||||
|
/* It must be a module created by reload_singlephase_extension()
|
||||||
|
* from m_copy. Ideally we'd do away with this case. */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (def->m_slots == NULL) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
struct singlephase_global_update {
|
||||||
|
PyObject *m_dict;
|
||||||
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
update_global_state_for_extension(PyThreadState *tstate,
|
update_global_state_for_extension(PyThreadState *tstate,
|
||||||
PyObject *mod, PyModuleDef *def,
|
PyObject *path, PyObject *name,
|
||||||
PyObject *name, PyObject *path)
|
PyModuleDef *def,
|
||||||
|
struct singlephase_global_update *singlephase)
|
||||||
{
|
{
|
||||||
assert(mod != NULL && PyModule_Check(mod));
|
/* Copy the module's __dict__, if applicable. */
|
||||||
assert(def == _PyModule_GetDef(mod));
|
if (singlephase == NULL) {
|
||||||
|
assert(def->m_base.m_copy == NULL);
|
||||||
// bpo-44050: Extensions and def->m_base.m_copy can be updated
|
}
|
||||||
// when the extension module doesn't support sub-interpreters.
|
else {
|
||||||
if (def->m_size == -1) {
|
assert(def->m_base.m_init != NULL
|
||||||
if (!is_core_module(tstate->interp, name, path)) {
|
|| is_core_module(tstate->interp, name, path));
|
||||||
|
if (singlephase->m_dict == NULL) {
|
||||||
|
assert(def->m_base.m_copy == NULL);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assert(PyDict_Check(singlephase->m_dict));
|
||||||
|
// gh-88216: Extensions and def->m_base.m_copy can be updated
|
||||||
|
// when the extension module doesn't support sub-interpreters.
|
||||||
|
assert(def->m_size == -1);
|
||||||
|
assert(!is_core_module(tstate->interp, name, path));
|
||||||
assert(PyUnicode_CompareWithASCIIString(name, "sys") != 0);
|
assert(PyUnicode_CompareWithASCIIString(name, "sys") != 0);
|
||||||
assert(PyUnicode_CompareWithASCIIString(name, "builtins") != 0);
|
assert(PyUnicode_CompareWithASCIIString(name, "builtins") != 0);
|
||||||
if (def->m_base.m_copy) {
|
if (def->m_base.m_copy) {
|
||||||
|
@ -1206,17 +1238,16 @@ update_global_state_for_extension(PyThreadState *tstate,
|
||||||
XXX this should really not happen. */
|
XXX this should really not happen. */
|
||||||
Py_CLEAR(def->m_base.m_copy);
|
Py_CLEAR(def->m_base.m_copy);
|
||||||
}
|
}
|
||||||
PyObject *dict = PyModule_GetDict(mod);
|
def->m_base.m_copy = PyDict_Copy(singlephase->m_dict);
|
||||||
if (dict == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
def->m_base.m_copy = PyDict_Copy(dict);
|
|
||||||
if (def->m_base.m_copy == NULL) {
|
if (def->m_base.m_copy == NULL) {
|
||||||
|
// XXX Ignore this error? Doing so would effectively
|
||||||
|
// mark the module as not loadable. */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add the module's def to the global cache. */
|
||||||
// XXX Why special-case the main interpreter?
|
// XXX Why special-case the main interpreter?
|
||||||
if (_Py_IsMainInterpreter(tstate->interp) || def->m_size == -1) {
|
if (_Py_IsMainInterpreter(tstate->interp) || def->m_size == -1) {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
@ -1258,6 +1289,8 @@ int
|
||||||
_PyImport_FixupExtensionObject(PyObject *mod, PyObject *name,
|
_PyImport_FixupExtensionObject(PyObject *mod, PyObject *name,
|
||||||
PyObject *filename, PyObject *modules)
|
PyObject *filename, PyObject *modules)
|
||||||
{
|
{
|
||||||
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
|
|
||||||
if (mod == NULL || !PyModule_Check(mod)) {
|
if (mod == NULL || !PyModule_Check(mod)) {
|
||||||
PyErr_BadInternalCall();
|
PyErr_BadInternalCall();
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1268,15 +1301,28 @@ _PyImport_FixupExtensionObject(PyObject *mod, PyObject *name,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyThreadState *tstate = _PyThreadState_GET();
|
/* Only single-phase init extension modules can reach here. */
|
||||||
|
assert(is_singlephase(def));
|
||||||
|
assert(!is_core_module(tstate->interp, name, filename));
|
||||||
|
assert(!is_core_module(tstate->interp, name, name));
|
||||||
|
|
||||||
|
struct singlephase_global_update singlephase = {0};
|
||||||
|
// gh-88216: Extensions and def->m_base.m_copy can be updated
|
||||||
|
// when the extension module doesn't support sub-interpreters.
|
||||||
|
if (def->m_size == -1) {
|
||||||
|
singlephase.m_dict = PyModule_GetDict(mod);
|
||||||
|
assert(singlephase.m_dict != NULL);
|
||||||
|
}
|
||||||
if (update_global_state_for_extension(
|
if (update_global_state_for_extension(
|
||||||
tstate, mod, def, name, filename) < 0)
|
tstate, filename, name, def, &singlephase) < 0)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (finish_singlephase_extension(tstate, mod, def, name, modules) < 0) {
|
if (finish_singlephase_extension(tstate, mod, def, name, modules) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1407,11 +1453,25 @@ _PyImport_FixupBuiltin(PyThreadState *tstate, PyObject *mod, const char *name,
|
||||||
goto finally;
|
goto finally;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We only use _PyImport_FixupBuiltin() for the core builtin modules
|
||||||
|
* (sys and builtins). These modules are single-phase init with no
|
||||||
|
* module state, but we also don't populate def->m_base.m_copy
|
||||||
|
* for them. */
|
||||||
|
assert(is_core_module(tstate->interp, nameobj, nameobj));
|
||||||
|
assert(is_singlephase(def));
|
||||||
|
assert(def->m_size == -1);
|
||||||
|
assert(def->m_base.m_copy == NULL);
|
||||||
|
|
||||||
|
struct singlephase_global_update singlephase = {
|
||||||
|
/* We don't want def->m_base.m_copy populated. */
|
||||||
|
.m_dict=NULL,
|
||||||
|
};
|
||||||
if (update_global_state_for_extension(
|
if (update_global_state_for_extension(
|
||||||
tstate, mod, def, nameobj, nameobj) < 0)
|
tstate, nameobj, nameobj, def, &singlephase) < 0)
|
||||||
{
|
{
|
||||||
goto finally;
|
goto finally;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (finish_singlephase_extension(tstate, mod, def, nameobj, modules) < 0) {
|
if (finish_singlephase_extension(tstate, mod, def, nameobj, modules) < 0) {
|
||||||
goto finally;
|
goto finally;
|
||||||
}
|
}
|
||||||
|
@ -1444,6 +1504,7 @@ is_builtin(PyObject *name)
|
||||||
static PyObject*
|
static PyObject*
|
||||||
create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec)
|
create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec)
|
||||||
{
|
{
|
||||||
|
PyModuleDef *def = NULL;
|
||||||
PyObject *mod = import_find_extension(tstate, name, name);
|
PyObject *mod = import_find_extension(tstate, name, name);
|
||||||
if (mod || _PyErr_Occurred(tstate)) {
|
if (mod || _PyErr_Occurred(tstate)) {
|
||||||
return mod;
|
return mod;
|
||||||
|
@ -1473,20 +1534,32 @@ create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PyObject_TypeCheck(mod, &PyModuleDef_Type)) {
|
if (PyObject_TypeCheck(mod, &PyModuleDef_Type)) {
|
||||||
return PyModule_FromDefAndSpec((PyModuleDef*)mod, spec);
|
def = (PyModuleDef*)mod;
|
||||||
|
assert(!is_singlephase(def));
|
||||||
|
return PyModule_FromDefAndSpec(def, spec);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
assert(PyModule_Check(mod));
|
assert(PyModule_Check(mod));
|
||||||
PyModuleDef *def = PyModule_GetDef(mod);
|
def = PyModule_GetDef(mod);
|
||||||
if (def == NULL) {
|
if (def == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
assert(is_singlephase(def));
|
||||||
|
|
||||||
/* Remember pointer to module init function. */
|
/* Remember pointer to module init function. */
|
||||||
def->m_base.m_init = p0;
|
def->m_base.m_init = p0;
|
||||||
|
|
||||||
|
struct singlephase_global_update singlephase = {0};
|
||||||
|
// gh-88216: Extensions and def->m_base.m_copy can be updated
|
||||||
|
// when the extension module doesn't support sub-interpreters.
|
||||||
|
if (def->m_size == -1
|
||||||
|
&& !is_core_module(tstate->interp, name, name))
|
||||||
|
{
|
||||||
|
singlephase.m_dict = PyModule_GetDict(mod);
|
||||||
|
assert(singlephase.m_dict != NULL);
|
||||||
|
}
|
||||||
if (update_global_state_for_extension(
|
if (update_global_state_for_extension(
|
||||||
tstate, mod, def, name, name) < 0)
|
tstate, name, name, def, &singlephase) < 0)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue