]> granicus.if.org Git - python/commitdiff
handle_finalizers(): Rewrote to call append_objects() and gc_list_merge()
authorTim Peters <tim.peters@gmail.com>
Sun, 6 Apr 2003 19:41:39 +0000 (19:41 +0000)
committerTim Peters <tim.peters@gmail.com>
Sun, 6 Apr 2003 19:41:39 +0000 (19:41 +0000)
instead of looping.  Smaller and clearer.  Faster, too, when we're not
appending to gc.garbage:  gc_list_merge() takes constant time, regardless
of the lists' sizes.

append_objects():  Moved up to live with the other list manipulation
utilities.

Modules/gcmodule.c

index 1bb065b1c221ed155cc5fad84888519ea9308051..36e53ec2ed8aa61d0a6910ede4e9f62e90fc3ea2 100644 (file)
@@ -182,6 +182,24 @@ gc_list_size(PyGC_Head *list)
        return n;
 }
 
+/* Append objects in a GC list to a Python list.
+ * Return 0 if all OK, < 0 if error (out of memory for list).
+ */
+static int
+append_objects(PyObject *py_list, PyGC_Head *gc_list)
+{
+       PyGC_Head *gc;
+       for (gc = gc_list->gc.gc_next; gc != gc_list; gc = gc->gc.gc_next) {
+               PyObject *op = FROM_GC(gc);
+               if (op != py_list) {
+                       if (PyList_Append(py_list, op)) {
+                               return -1; /* exception */
+                       }
+               }
+       }
+       return 0;
+}
+
 /*** end of list stuff ***/
 
 
@@ -457,33 +475,26 @@ debug_cycle(char *msg, PyObject *op)
 
 /* Handle uncollectable garbage (cycles with finalizers, and stuff reachable
  * only from such cycles).
+ * If DEBUG_SAVEALL or hasfinalizer, the objects in finalizers are appended
+ * to the module garbage list (a Python list).  The objects in finalizers
+ * are merged into the old list regardless.
+ * Returns 0 if all OK, <0 on error (out of memory to grow the garbage list).
+ * The finalizers list is made empty on a successful return.
  */
-static void
+static int
 handle_finalizers(PyGC_Head *finalizers, PyGC_Head *old, int hasfinalizer)
 {
-       PyGC_Head *gc;
        if (garbage == NULL) {
                garbage = PyList_New(0);
                if (garbage == NULL)
                        Py_FatalError("gc couldn't create gc.garbage list");
        }
-       for (gc = finalizers->gc.gc_next;
-            gc != finalizers;
-            gc = finalizers->gc.gc_next) {
-               PyObject *op = FROM_GC(gc);
-
-               assert(IS_REACHABLE(op));
-               if ((debug & DEBUG_SAVEALL) || hasfinalizer) {
-                       /* 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);
-               }
-               gc_list_remove(gc);
-               gc_list_append(gc, old);
+       if ((debug & DEBUG_SAVEALL) || hasfinalizer) {
+               if (append_objects(garbage, finalizers) < 0)
+                       return -1;
        }
+       gc_list_merge(finalizers, old);
+       return 0;
 }
 
 /* Break reference cycles by clearing the containers involved. This is
@@ -662,8 +673,8 @@ collect(int generation)
         * reachable list of garbage.  The programmer has to deal with
         * this if they insist on creating this type of structure.
         */
-       handle_finalizers(&finalizers, old, 1);
-       handle_finalizers(&reachable_from_finalizers, old, 0);
+       if (handle_finalizers(&finalizers, old, 1) == 0)
+               (void)handle_finalizers(&reachable_from_finalizers, old, 0);
 
        if (PyErr_Occurred()) {
                if (gc_str == NULL) {
@@ -907,22 +918,6 @@ PyDoc_STRVAR(gc_get_objects__doc__,
 "Return a list of objects tracked by the collector (excluding the list\n"
 "returned).\n");
 
-/* appending objects in a GC list to a Python list */
-static int
-append_objects(PyObject *py_list, PyGC_Head *gc_list)
-{
-       PyGC_Head *gc;
-       for (gc = gc_list->gc.gc_next; gc != gc_list; gc = gc->gc.gc_next) {
-               PyObject *op = FROM_GC(gc);
-               if (op != py_list) {
-                       if (PyList_Append(py_list, op)) {
-                               return -1; /* exception */
-                       }
-               }
-       }
-       return 0;
-}
-
 static PyObject *
 gc_get_objects(PyObject *self, PyObject *noargs)
 {