From a765c120f6fd3004ad3dbc34771f848b19caf18d Mon Sep 17 00:00:00 2001 From: Neil Schemenauer Date: Thu, 1 Nov 2001 17:35:23 +0000 Subject: [PATCH] Add has_finalizer predictate function. Use it when deciding which objects to save in gc.garbage. This should be the last change needed to fix SF bug 477059: "__del__ on new classes vs. GC". Note that this change slightly changes the behavior of the collector. Before, if a cycle was found that contained instances with __del__ methods then all instance objects in that cycle were saved in gc.garbage. Now, only objects with __del__ methods are saved in gc.garbage. --- Modules/gcmodule.c | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index a0522a09524..0738eb67fff 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -226,24 +226,36 @@ move_root_reachable(PyGC_Head *reachable) } } -/* Move all objects with finalizers (instances with __del__) */ -static void -move_finalizers(PyGC_Head *unreachable, PyGC_Head *finalizers) +/* return true of object has a finalization method */ +static int +has_finalizer(PyObject *op) { - PyGC_Head *next; - PyGC_Head *gc = unreachable->gc.gc_next; static PyObject *delstr = NULL; if (delstr == NULL) { delstr = PyString_InternFromString("__del__"); if (delstr == NULL) Py_FatalError("PyGC: can't initialize __del__ string"); } + if ((PyInstance_Check(op) || + PyType_HasFeature(op->ob_type, Py_TPFLAGS_HEAPTYPE)) && + PyObject_HasAttr(op, delstr)) { + return 1; + } + else { + return 0; + } +} + +/* Move all objects with finalizers (instances with __del__) */ +static void +move_finalizers(PyGC_Head *unreachable, PyGC_Head *finalizers) +{ + PyGC_Head *next; + PyGC_Head *gc = unreachable->gc.gc_next; for (; gc != unreachable; gc=next) { PyObject *op = FROM_GC(gc); next = gc->gc.gc_next; - if ((PyInstance_Check(op) || - PyType_HasFeature(op->ob_type, Py_TPFLAGS_HEAPTYPE)) && - PyObject_HasAttr(op, delstr)) { + if (has_finalizer(op)) { gc_list_remove(gc); gc_list_append(gc, finalizers); } @@ -269,7 +281,7 @@ static void debug_instance(char *msg, PyInstanceObject *inst) { char *cname; - /* be careful not to create new dictionaries */ + /* simple version of instance_repr */ PyObject *classname = inst->in_class->cl_name; if (classname != NULL && PyString_Check(classname)) cname = PyString_AsString(classname); @@ -302,11 +314,11 @@ handle_finalizers(PyGC_Head *finalizers, PyGC_Head *old) for (gc = finalizers->gc.gc_next; gc != finalizers; gc = finalizers->gc.gc_next) { PyObject *op = FROM_GC(gc); - if ((debug & DEBUG_SAVEALL) || PyInstance_Check(op)) { - /* If SAVEALL is not set then just append - * instances to the list of garbage. We assume - * that all objects in the finalizers list are - * reachable from instances. */ + if ((debug & DEBUG_SAVEALL) || has_finalizer(op)) { + /* If SAVEALL is not set then just append objects with + * finalizers to the list of garbage. All objects in + * the finalizers list are reachable from those + * objects. */ PyList_Append(garbage, op); } /* object is now reachable again */