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.
This commit is contained in:
Tim Peters 2003-04-06 19:41:39 +00:00
parent f394df47fd
commit 259272b7a0
1 changed files with 31 additions and 36 deletions

View 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)
{