]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-1635741: Port gc module to multiphase initialization (GH-23377)
authorChristian Heimes <christian@python.org>
Thu, 19 Nov 2020 14:08:34 +0000 (15:08 +0100)
committerGitHub <noreply@github.com>
Thu, 19 Nov 2020 14:08:34 +0000 (06:08 -0800)
Signed-off-by: Christian Heimes <christian@python.org>
Automerge-Triggered-By: GH:tiran
Misc/NEWS.d/next/C API/2020-11-18-20-33-35.bpo-1635741.B4ztSk.rst [new file with mode: 0644]
Modules/gcmodule.c

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 (file)
index 0000000..bce80c8
--- /dev/null
@@ -0,0 +1 @@
+Port :mod:`gc` extension module to multiphase initialization (:pep:`489`)
index e6ad0f2dd4222738f30b7382145431955019cb37..45201435f24605bfcfc286f9ea93afa6f8f998e4 100644 (file)
@@ -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;
-    }
-
-    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;
-        }
+    /* 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;
     }
-    Py_INCREF(gcstate->callbacks);
-    if (PyModule_AddObject(m, "callbacks", gcstate->callbacks) < 0) {
-        return NULL;
+    assert(gcstate->callbacks != NULL);
+    if (PyModule_AddObjectRef(module, "callbacks", gcstate->callbacks) < 0) {
+        return -1;
     }
 
-#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 */