diff options
author | Tim Peters <tim.peters@gmail.com> | 2003-04-06 19:41:39 (GMT) |
---|---|---|
committer | Tim Peters <tim.peters@gmail.com> | 2003-04-06 19:41:39 (GMT) |
commit | 259272b7a0edaf06b1a70379e74907ae4166c67e (patch) | |
tree | af8bfbcddb9f6db9453b3aafb6f42488959afb7f | |
parent | f394df47fd943d7067b5c3bedbf2c359d864923c (diff) | |
download | cpython-259272b7a0edaf06b1a70379e74907ae4166c67e.zip cpython-259272b7a0edaf06b1a70379e74907ae4166c67e.tar.gz cpython-259272b7a0edaf06b1a70379e74907ae4166c67e.tar.bz2 |
handle_finalizers(): Rewrote to call append_objects() and gc_list_merge()
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.
-rw-r--r-- | Modules/gcmodule.c | 67 |
1 files changed, 31 insertions, 36 deletions
diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 1bb065b..36e53ec 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -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) { |