diff --git a/Misc/NEWS.d/next/C API/2020-11-18-20-33-35.bpo-1635741.B4ztSk.rst b/Misc/NEWS.d/next/C API/2020-11-18-20-33-35.bpo-1635741.B4ztSk.rst new file mode 100644 index 00000000000..bce80c86de5 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2020-11-18-20-33-35.bpo-1635741.B4ztSk.rst @@ -0,0 +1 @@ +Port :mod:`gc` extension module to multiphase initialization (:pep:`489`) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index e6ad0f2dd42..45201435f24 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -165,12 +165,17 @@ PyStatus _PyGC_Init(PyThreadState *tstate) { GCState *gcstate = &tstate->interp->gc; + + gcstate->garbage = PyList_New(0); if (gcstate->garbage == NULL) { - gcstate->garbage = PyList_New(0); - if (gcstate->garbage == NULL) { - return _PyStatus_NO_MEMORY(); - } + return _PyStatus_NO_MEMORY(); } + + gcstate->callbacks = PyList_New(0); + if (gcstate->callbacks == NULL) { + return _PyStatus_NO_MEMORY(); + } + return _PyStatus_OK(); } @@ -1992,59 +1997,50 @@ static PyMethodDef GcMethods[] = { {NULL, NULL} /* Sentinel */ }; -static struct PyModuleDef gcmodule = { - PyModuleDef_HEAD_INIT, - "gc", /* m_name */ - gc__doc__, /* m_doc */ - -1, /* m_size */ - GcMethods, /* m_methods */ - NULL, /* m_reload */ - NULL, /* m_traverse */ - NULL, /* m_clear */ - NULL /* m_free */ -}; - -PyMODINIT_FUNC -PyInit_gc(void) +static int +gcmodule_exec(PyObject *module) { GCState *gcstate = get_gc_state(); - PyObject *m = PyModule_Create(&gcmodule); - - if (m == NULL) { - return NULL; + /* garbage and callbacks are initialized by _PyGC_Init() early in + * interpreter lifecycle. */ + assert(gcstate->garbage != NULL); + if (PyModule_AddObjectRef(module, "garbage", gcstate->garbage) < 0) { + return -1; + } + assert(gcstate->callbacks != NULL); + if (PyModule_AddObjectRef(module, "callbacks", gcstate->callbacks) < 0) { + return -1; } - if (gcstate->garbage == NULL) { - gcstate->garbage = PyList_New(0); - if (gcstate->garbage == NULL) { - return NULL; - } - } - Py_INCREF(gcstate->garbage); - if (PyModule_AddObject(m, "garbage", gcstate->garbage) < 0) { - return NULL; - } - - if (gcstate->callbacks == NULL) { - gcstate->callbacks = PyList_New(0); - if (gcstate->callbacks == NULL) { - return NULL; - } - } - Py_INCREF(gcstate->callbacks); - if (PyModule_AddObject(m, "callbacks", gcstate->callbacks) < 0) { - return NULL; - } - -#define ADD_INT(NAME) if (PyModule_AddIntConstant(m, #NAME, NAME) < 0) { return NULL; } +#define ADD_INT(NAME) if (PyModule_AddIntConstant(module, #NAME, NAME) < 0) { return -1; } ADD_INT(DEBUG_STATS); ADD_INT(DEBUG_COLLECTABLE); ADD_INT(DEBUG_UNCOLLECTABLE); ADD_INT(DEBUG_SAVEALL); ADD_INT(DEBUG_LEAK); #undef ADD_INT - return m; + return 0; +} + +static PyModuleDef_Slot gcmodule_slots[] = { + {Py_mod_exec, gcmodule_exec}, + {0, NULL} +}; + +static struct PyModuleDef gcmodule = { + PyModuleDef_HEAD_INIT, + .m_name = "gc", + .m_doc = gc__doc__, + .m_size = 0, // per interpreter state, see: get_gc_state() + .m_methods = GcMethods, + .m_slots = gcmodule_slots +}; + +PyMODINIT_FUNC +PyInit_gc(void) +{ + return PyModuleDef_Init(&gcmodule); } /* Public API to invoke gc.collect() from C */