diff options
author | Guido van Rossum <guido@python.org> | 2001-10-29 22:11:00 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 2001-10-29 22:11:00 (GMT) |
commit | 7ad2d1eb8eaf8db634b440ef3c4f5a1b9b654cb5 (patch) | |
tree | ceb93389ae63c9e74452ceeda94a32c046d1cea2 /Objects | |
parent | c57a285cb4cd61439fd3ea804184ed8a8a1ac358 (diff) | |
download | cpython-7ad2d1eb8eaf8db634b440ef3c4f5a1b9b654cb5.zip cpython-7ad2d1eb8eaf8db634b440ef3c4f5a1b9b654cb5.tar.gz cpython-7ad2d1eb8eaf8db634b440ef3c4f5a1b9b654cb5.tar.bz2 |
Add __del__ callbacks. They are too useful to leave out.
XXX Remaining problems:
- The GC module doesn't know about these; I think it has its reasons
to disallow calling __del__, but for now, __del__ on new-style
objects is called when the GC module discards an object, for better
or for worse.
- The code to call a __del__ handler is really ridiculously
complicated, due to all the different debug #ifdefs. I've copied
this from the similar code in classobject.c, so I'm pretty sure I
did it right, but it's not pretty. :-(
- No tests yet.
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/typeobject.c | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/Objects/typeobject.c b/Objects/typeobject.c index d5f6a8f..b7abba9 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -230,6 +230,77 @@ subtype_traverse(PyObject *self, visitproc visit, void *arg) return 0; } +staticforward PyObject *lookup_maybe(PyObject *, char *, PyObject **); + +static int +call_finalizer(PyObject *self) +{ + static PyObject *del_str = NULL; + PyObject *del, *res; + PyObject *error_type, *error_value, *error_traceback; + + /* Temporarily resurrect the object. */ +#ifdef Py_TRACE_REFS +#ifndef Py_REF_DEBUG +# error "Py_TRACE_REFS defined but Py_REF_DEBUG not." +#endif + /* much too complicated if Py_TRACE_REFS defined */ + _Py_NewReference((PyObject *)self); +#ifdef COUNT_ALLOCS + /* compensate for boost in _Py_NewReference; note that + * _Py_RefTotal was also boosted; we'll knock that down later. + */ + self->ob_type->tp_allocs--; +#endif +#else /* !Py_TRACE_REFS */ + /* Py_INCREF boosts _Py_RefTotal if Py_REF_DEBUG is defined */ + Py_INCREF(self); +#endif /* !Py_TRACE_REFS */ + + /* Save the current exception, if any. */ + PyErr_Fetch(&error_type, &error_value, &error_traceback); + + /* Execute __del__ method, if any. */ + del = lookup_maybe(self, "__del__", &del_str); + if (del != NULL) { + res = PyEval_CallObject(del, NULL); + if (res == NULL) + PyErr_WriteUnraisable(del); + else + Py_DECREF(res); + Py_DECREF(del); + } + + /* Restore the saved exception. */ + PyErr_Restore(error_type, error_value, error_traceback); + + /* Undo the temporary resurrection; can't use DECREF here, it would + * cause a recursive call. + */ +#ifdef Py_REF_DEBUG + /* _Py_RefTotal was boosted either by _Py_NewReference or + * Py_INCREF above. + */ + _Py_RefTotal--; +#endif + if (--self->ob_refcnt > 0) { +#ifdef COUNT_ALLOCS + self->ob_type->tp_frees--; +#endif + _PyObject_GC_TRACK(self); + return -1; /* __del__ added a reference; don't delete now */ + } +#ifdef Py_TRACE_REFS + _Py_ForgetReference((PyObject *)self); +#ifdef COUNT_ALLOCS + /* compensate for increment in _Py_ForgetReference */ + self->ob_type->tp_frees--; +#endif +#endif + + return 0; +} + static void subtype_dealloc(PyObject *self) { @@ -238,6 +309,9 @@ subtype_dealloc(PyObject *self) /* This exists so we can DECREF self->ob_type */ + if (call_finalizer(self) < 0) + return; + /* Find the nearest base with a different tp_dealloc */ type = self->ob_type; base = type->tp_base; |