mirror of https://github.com/python/cpython
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.
This commit is contained in:
parent
f49c6f9954
commit
a765c120f6
|
@ -226,24 +226,36 @@ move_root_reachable(PyGC_Head *reachable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move all objects with finalizers (instances with __del__) */
|
/* return true of object has a finalization method */
|
||||||
static void
|
static int
|
||||||
move_finalizers(PyGC_Head *unreachable, PyGC_Head *finalizers)
|
has_finalizer(PyObject *op)
|
||||||
{
|
{
|
||||||
PyGC_Head *next;
|
|
||||||
PyGC_Head *gc = unreachable->gc.gc_next;
|
|
||||||
static PyObject *delstr = NULL;
|
static PyObject *delstr = NULL;
|
||||||
if (delstr == NULL) {
|
if (delstr == NULL) {
|
||||||
delstr = PyString_InternFromString("__del__");
|
delstr = PyString_InternFromString("__del__");
|
||||||
if (delstr == NULL)
|
if (delstr == NULL)
|
||||||
Py_FatalError("PyGC: can't initialize __del__ string");
|
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) {
|
for (; gc != unreachable; gc=next) {
|
||||||
PyObject *op = FROM_GC(gc);
|
PyObject *op = FROM_GC(gc);
|
||||||
next = gc->gc.gc_next;
|
next = gc->gc.gc_next;
|
||||||
if ((PyInstance_Check(op) ||
|
if (has_finalizer(op)) {
|
||||||
PyType_HasFeature(op->ob_type, Py_TPFLAGS_HEAPTYPE)) &&
|
|
||||||
PyObject_HasAttr(op, delstr)) {
|
|
||||||
gc_list_remove(gc);
|
gc_list_remove(gc);
|
||||||
gc_list_append(gc, finalizers);
|
gc_list_append(gc, finalizers);
|
||||||
}
|
}
|
||||||
|
@ -269,7 +281,7 @@ static void
|
||||||
debug_instance(char *msg, PyInstanceObject *inst)
|
debug_instance(char *msg, PyInstanceObject *inst)
|
||||||
{
|
{
|
||||||
char *cname;
|
char *cname;
|
||||||
/* be careful not to create new dictionaries */
|
/* simple version of instance_repr */
|
||||||
PyObject *classname = inst->in_class->cl_name;
|
PyObject *classname = inst->in_class->cl_name;
|
||||||
if (classname != NULL && PyString_Check(classname))
|
if (classname != NULL && PyString_Check(classname))
|
||||||
cname = PyString_AsString(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;
|
for (gc = finalizers->gc.gc_next; gc != finalizers;
|
||||||
gc = finalizers->gc.gc_next) {
|
gc = finalizers->gc.gc_next) {
|
||||||
PyObject *op = FROM_GC(gc);
|
PyObject *op = FROM_GC(gc);
|
||||||
if ((debug & DEBUG_SAVEALL) || PyInstance_Check(op)) {
|
if ((debug & DEBUG_SAVEALL) || has_finalizer(op)) {
|
||||||
/* If SAVEALL is not set then just append
|
/* If SAVEALL is not set then just append objects with
|
||||||
* instances to the list of garbage. We assume
|
* finalizers to the list of garbage. All objects in
|
||||||
* that all objects in the finalizers list are
|
* the finalizers list are reachable from those
|
||||||
* reachable from instances. */
|
* objects. */
|
||||||
PyList_Append(garbage, op);
|
PyList_Append(garbage, op);
|
||||||
}
|
}
|
||||||
/* object is now reachable again */
|
/* object is now reachable again */
|
||||||
|
|
Loading…
Reference in New Issue