diff options
Diffstat (limited to 'Modules/gcmodule.c')
-rw-r--r-- | Modules/gcmodule.c | 153 |
1 files changed, 75 insertions, 78 deletions
diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 81344ca828c..8c524f8309d 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -9,9 +9,14 @@ Eric Tiedemann, and various others. http://www.arctrix.com/nas/python/gc/ - http://www.python.org/pipermail/python-dev/2000-March/003869.html - http://www.python.org/pipermail/python-dev/2000-March/004010.html - http://www.python.org/pipermail/python-dev/2000-March/004022.html + + The following mailing list threads provide a historical perspective on + the design of this module. Note that a fair amount of refinement has + occurred since those discussions. + + http://mail.python.org/pipermail/python-dev/2000-March/002385.html + http://mail.python.org/pipermail/python-dev/2000-March/002434.html + http://mail.python.org/pipermail/python-dev/2000-March/002497.html For a highlevel view of the collection process, read the collect function. @@ -156,13 +161,9 @@ static Py_ssize_t long_lived_pending = 0; #define DEBUG_STATS (1<<0) /* print collection statistics */ #define DEBUG_COLLECTABLE (1<<1) /* print collectable objects */ #define DEBUG_UNCOLLECTABLE (1<<2) /* print uncollectable objects */ -#define DEBUG_INSTANCES (1<<3) /* print instances */ -#define DEBUG_OBJECTS (1<<4) /* print other objects */ #define DEBUG_SAVEALL (1<<5) /* save all garbage in gc.garbage */ #define DEBUG_LEAK DEBUG_COLLECTABLE | \ DEBUG_UNCOLLECTABLE | \ - DEBUG_INSTANCES | \ - DEBUG_OBJECTS | \ DEBUG_SAVEALL static int debug; static PyObject *tmod = NULL; @@ -493,28 +494,6 @@ move_unreachable(PyGC_Head *young, PyGC_Head *unreachable) } } -/* Return true if object has a finalization method. - * CAUTION: An instance of an old-style class has to be checked for a - *__del__ method, and earlier versions of this used to call PyObject_HasAttr, - * which in turn could call the class's __getattr__ hook (if any). That - * could invoke arbitrary Python code, mutating the object graph in arbitrary - * ways, and that was the source of some excruciatingly subtle bugs. - */ -static int -has_finalizer(PyObject *op) -{ - if (PyInstance_Check(op)) { - assert(delstr != NULL); - return _PyInstance_Lookup(op, delstr) != NULL; - } - else if (PyType_HasFeature(op->ob_type, Py_TPFLAGS_HEAPTYPE)) - return op->ob_type->tp_del != NULL; - else if (PyGen_CheckExact(op)) - return PyGen_NeedsFinalizing((PyGenObject *)op); - else - return 0; -} - /* Try to untrack all currently tracked dictionaries */ static void untrack_dicts(PyGC_Head *head) @@ -529,6 +508,16 @@ untrack_dicts(PyGC_Head *head) } } +/* Return true if object has a finalization method. */ +static int +has_finalizer(PyObject *op) +{ + if (PyGen_CheckExact(op)) + return PyGen_NeedsFinalizing((PyGenObject *)op); + else + return op->ob_type->tp_del != NULL; +} + /* Move the objects in unreachable with __del__ methods into `finalizers`. * Objects moved into `finalizers` have gc_refs set to GC_REACHABLE; the * objects remaining in unreachable are left at GC_TENTATIVELY_UNREACHABLE. @@ -740,29 +729,10 @@ handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old) } static void -debug_instance(char *msg, PyInstanceObject *inst) -{ - char *cname; - /* simple version of instance_repr */ - PyObject *classname = inst->in_class->cl_name; - if (classname != NULL && PyString_Check(classname)) - cname = PyString_AsString(classname); - else - cname = "?"; - PySys_WriteStderr("gc: %.100s <%.100s instance at %p>\n", - msg, cname, inst); -} - -static void debug_cycle(char *msg, PyObject *op) { - if ((debug & DEBUG_INSTANCES) && PyInstance_Check(op)) { - debug_instance(msg, (PyInstanceObject *)op); - } - else if (debug & DEBUG_OBJECTS) { - PySys_WriteStderr("gc: %.100s <%.100s %p>\n", - msg, Py_TYPE(op)->tp_name, op); - } + PySys_WriteStderr("gc: %.100s <%.100s %p>\n", + msg, Py_TYPE(op)->tp_name, op); } /* Handle uncollectable garbage (cycles with finalizers, and stuff reachable @@ -841,10 +811,7 @@ clear_freelists(void) (void)PyFrame_ClearFreeList(); (void)PyCFunction_ClearFreeList(); (void)PyTuple_ClearFreeList(); -#ifdef Py_USING_UNICODE (void)PyUnicode_ClearFreeList(); -#endif - (void)PyInt_ClearFreeList(); (void)PyFloat_ClearFreeList(); } @@ -882,7 +849,7 @@ collect(int generation) double t1 = 0.0; if (delstr == NULL) { - delstr = PyString_InternFromString("__del__"); + delstr = PyUnicode_InternFromString("__del__"); if (delstr == NULL) Py_FatalError("gc couldn't allocate \"__del__\""); } @@ -1022,7 +989,7 @@ collect(int generation) if (PyErr_Occurred()) { if (gc_str == NULL) - gc_str = PyString_FromString("garbage collection"); + gc_str = PyUnicode_FromString("garbage collection"); PyErr_WriteUnraisable(gc_str); Py_FatalError("unexpected exception during garbage collection"); } @@ -1122,7 +1089,7 @@ gc_collect(PyObject *self, PyObject *args, PyObject *kws) collecting = 0; } - return PyInt_FromSsize_t(n); + return PyLong_FromSsize_t(n); } PyDoc_STRVAR(gc_set_debug__doc__, @@ -1136,8 +1103,6 @@ PyDoc_STRVAR(gc_set_debug__doc__, " DEBUG_STATS - Print statistics during collection.\n" " DEBUG_COLLECTABLE - Print collectable objects found.\n" " DEBUG_UNCOLLECTABLE - Print unreachable but uncollectable objects found.\n" -" DEBUG_INSTANCES - Print instance objects.\n" -" DEBUG_OBJECTS - Print objects other than instances.\n" " DEBUG_SAVEALL - Save objects to gc.garbage rather than freeing them.\n" " DEBUG_LEAK - Debug leaking programs (everything but STATS).\n"); @@ -1382,27 +1347,36 @@ static PyMethodDef GcMethods[] = { {NULL, NULL} /* Sentinel */ }; +static struct PyModuleDef gcmodule = { + PyModuleDef_HEAD_INIT, + "gc", /* m_name */ + gc__doc__, /* m_doc */ + -1, /* m_size */ + GcMethods, /* m_methods */ + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL /* m_free */ +}; + PyMODINIT_FUNC -initgc(void) +PyInit_gc(void) { PyObject *m; - m = Py_InitModule4("gc", - GcMethods, - gc__doc__, - NULL, - PYTHON_API_VERSION); + m = PyModule_Create(&gcmodule); + if (m == NULL) - return; + return NULL; if (garbage == NULL) { garbage = PyList_New(0); if (garbage == NULL) - return; + return NULL; } Py_INCREF(garbage); if (PyModule_AddObject(m, "garbage", garbage) < 0) - return; + return NULL; /* Importing can't be done in collect() because collect() * can be called via PyGC_Collect() in Py_Finalize(). @@ -1416,15 +1390,14 @@ initgc(void) PyErr_Clear(); } -#define ADD_INT(NAME) if (PyModule_AddIntConstant(m, #NAME, NAME) < 0) return +#define ADD_INT(NAME) if (PyModule_AddIntConstant(m, #NAME, NAME) < 0) return NULL ADD_INT(DEBUG_STATS); ADD_INT(DEBUG_COLLECTABLE); ADD_INT(DEBUG_UNCOLLECTABLE); - ADD_INT(DEBUG_INSTANCES); - ADD_INT(DEBUG_OBJECTS); ADD_INT(DEBUG_SAVEALL); ADD_INT(DEBUG_LEAK); #undef ADD_INT + return m; } /* API to invoke gc.collect() from C */ @@ -1444,6 +1417,38 @@ PyGC_Collect(void) return n; } +void +_PyGC_Fini(void) +{ + if (!(debug & DEBUG_SAVEALL) + && garbage != NULL && PyList_GET_SIZE(garbage) > 0) { + char *message; + if (debug & DEBUG_UNCOLLECTABLE) + message = "gc: %zd uncollectable objects at " \ + "shutdown"; + else + message = "gc: %zd uncollectable objects at " \ + "shutdown; use gc.set_debug(gc.DEBUG_UNCOLLECTABLE) to list them"; + if (PyErr_WarnFormat(PyExc_ResourceWarning, 0, message, + PyList_GET_SIZE(garbage)) < 0) + PyErr_WriteUnraisable(NULL); + if (debug & DEBUG_UNCOLLECTABLE) { + PyObject *repr = NULL, *bytes = NULL; + repr = PyObject_Repr(garbage); + if (!repr || !(bytes = PyUnicode_EncodeFSDefault(repr))) + PyErr_WriteUnraisable(garbage); + else { + PySys_WriteStderr( + " %s\n", + PyBytes_AS_STRING(bytes) + ); + } + Py_XDECREF(repr); + Py_XDECREF(bytes); + } + } +} + /* for debugging */ void _PyGC_Dump(PyGC_Head *g) @@ -1560,11 +1565,3 @@ PyObject_GC_Del(void *op) } PyObject_FREE(g); } - -/* for binary compatibility with 2.2 */ -#undef _PyObject_GC_Del -void -_PyObject_GC_Del(PyObject *op) -{ - PyObject_GC_Del(op); -} |