summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2003-04-05 18:40:50 (GMT)
committerTim Peters <tim.peters@gmail.com>2003-04-05 18:40:50 (GMT)
commitf6ae7a43eb781f2922309278d8005415e507ad28 (patch)
treeaab06f53e6b8a16e95af4a4f58fadbcbe7120e14 /Modules
parent2f74fddfc1bd81838cb80e726d391f4c810e525a (diff)
downloadcpython-f6ae7a43eb781f2922309278d8005415e507ad28.zip
cpython-f6ae7a43eb781f2922309278d8005415e507ad28.tar.gz
cpython-f6ae7a43eb781f2922309278d8005415e507ad28.tar.bz2
move_finalizers(): Rewrote. It's not necessary for this routine
to special-case classic classes, or to worry about refcounts; has_finalizer() deleted the current object iff the first entry in the unreachable list has changed. I don't believe it was correct to check for ob_refcnt == 1, either: the dealloc routine would get called by Py_DECREF then, but there's nothing to stop the dealloc routine from ressurecting the object, and then gc would remain at the head of the unreachable list despite that its refcount temporarily fell to 0 (and that would lead to an infinite loop in move_finalizers()). I'm still worried about has_finalizer() resurrecting other objects in the unreachable list: what's to stop them from getting collected?
Diffstat (limited to 'Modules')
-rw-r--r--Modules/gcmodule.c49
1 files changed, 20 insertions, 29 deletions
diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c
index 729e9d5..91df906 100644
--- a/Modules/gcmodule.c
+++ b/Modules/gcmodule.c
@@ -361,7 +361,15 @@ has_finalizer(PyObject *op)
return 0;
}
-/* Move all objects out of unreachable and into collectable or finalizers.
+/* Move all objects out of unreachable, into collectable or finalizers.
+ * It's possible that some objects will get collected (via refcount falling
+ * to 0), or resurrected, as a side effect of checking for __del__ methods.
+ * After, finalizers contains all the objects from unreachable that haven't
+ * been collected by magic, and that have a finalizer. gc_refs is
+ * GC_REACHABLE for all of those. collectable contains all the remaining
+ * objects from unreachable, and gc_refs remains GC_TENTATIVELY_UNREACHABLE
+ * for those (we're still not sure they're reclaimable after this! Some
+ * may yet by reachable *from* the objects in finalizers).
*/
static void
move_finalizers(PyGC_Head *unreachable, PyGC_Head *collectable,
@@ -372,36 +380,19 @@ move_finalizers(PyGC_Head *unreachable, PyGC_Head *collectable,
PyObject *op = FROM_GC(gc);
int finalizer;
- if (PyInstance_Check(op)) {
- /* The HasAttr() check may run enough Python
- code to deallocate the object or make it
- reachable again. INCREF the object before
- calling HasAttr() to guard against the client
- code deallocating the object.
- */
- Py_INCREF(op);
- finalizer = PyObject_HasAttr(op, delstr);
- if (op->ob_refcnt == 1) {
- /* The object will be deallocated.
- Nothing left to do.
- */
- Py_DECREF(op);
- continue;
- }
- Py_DECREF(op);
- }
- else
- finalizer = has_finalizer(op);
- if (finalizer) {
- gc_list_remove(gc);
- gc_list_append(gc, finalizers);
- gc->gc.gc_refs = GC_REACHABLE;
- }
- else {
+ assert(IS_TENTATIVELY_UNREACHABLE(op));
+
+ finalizer = has_finalizer(op);
+ if (unreachable->gc.gc_next == gc) {
gc_list_remove(gc);
- gc_list_append(gc, collectable);
- /* XXX change gc_refs? */
+ if (finalizer) {
+ gc_list_append(gc, finalizers);
+ gc->gc.gc_refs = GC_REACHABLE;
+ }
+ else
+ gc_list_append(gc, collectable);
}
+ /* else has_finalizer() deleted op via side effect */
}
}