@@ -53,10 +53,12 @@ static int allocated;
5353#define DEBUG_UNCOLLECTABLE (1<<2) /* print uncollectable objects */
5454#define DEBUG_INSTANCES (1<<3) /* print instances */
5555#define DEBUG_OBJECTS (1<<4) /* print other objects */
56+ #define DEBUG_SAVEALL (1<<5) /* save all garbage in gc.garbage */
5657#define DEBUG_LEAK DEBUG_COLLECTABLE | \
5758 DEBUG_UNCOLLECTABLE | \
5859 DEBUG_INSTANCES | \
59- DEBUG_OBJECTS
60+ DEBUG_OBJECTS | \
61+ DEBUG_SAVEALL
6062static int debug ;
6163
6264/* list of uncollectable objects */
@@ -100,7 +102,8 @@ gc_list_move(PyGC_Head *from, PyGC_Head *to)
100102 if (from -> gc_next == from ) {
101103 /* empty from list */
102104 gc_list_init (to );
103- } else {
105+ }
106+ else {
104107 to -> gc_next = from -> gc_next ;
105108 to -> gc_next -> gc_prev = to ;
106109 to -> gc_prev = from -> gc_prev ;
@@ -290,7 +293,8 @@ debug_cycle(char *msg, PyObject *op)
290293{
291294 if ((debug & DEBUG_INSTANCES ) && PyInstance_Check (op )) {
292295 debug_instance (msg , (PyInstanceObject * )op );
293- } else if (debug & DEBUG_OBJECTS ) {
296+ }
297+ else if (debug & DEBUG_OBJECTS ) {
294298 PySys_WriteStderr ("gc: %.100s <%.100s %p>\n" ,
295299 msg , op -> ob_type -> tp_name , op );
296300 }
@@ -307,19 +311,20 @@ handle_finalizers(PyGC_Head *finalizers, PyGC_Head *old)
307311 for (gc = finalizers -> gc_next ; gc != finalizers ;
308312 gc = finalizers -> gc_next ) {
309313 PyObject * op = PyObject_FROM_GC (gc );
310- /* Add all instances to a Python accessible list of garbage */
311- if (PyInstance_Check (op )) {
314+ if ((debug & DEBUG_SAVEALL ) || PyInstance_Check (op )) {
315+ /* If SAVEALL is not set then just append
316+ * instances to the list of garbage. We assume
317+ * that all objects in the finalizers list are
318+ * reachable from instances. */
312319 PyList_Append (garbage , op );
313320 }
314- /* We assume that all objects in finalizers are reachable from
315- * instances. Once we add the instances to the garbage list
316- * everything is reachable from Python again. */
321+ /* object is now reachable again */
317322 gc_list_remove (gc );
318323 gc_list_append (gc , old );
319324 }
320325}
321326
322- /* Break reference cycles by clearing the containers involved. This is
327+ /* Break reference cycles by clearing the containers involved. This is
323328 * tricky business as the lists can be changing and we don't know which
324329 * objects may be freed. It is possible I screwed something up here. */
325330static void
@@ -330,17 +335,18 @@ delete_garbage(PyGC_Head *unreachable, PyGC_Head *old)
330335 while (unreachable -> gc_next != unreachable ) {
331336 PyGC_Head * gc = unreachable -> gc_next ;
332337 PyObject * op = PyObject_FROM_GC (gc );
333- /*
334- PyList_Append(garbage, op);
335- */
336- if ((clear = op -> ob_type -> tp_clear ) != NULL ) {
337- Py_INCREF (op );
338- clear ((PyObject * )op );
339- Py_DECREF (op );
338+ if (debug & DEBUG_SAVEALL ) {
339+ PyList_Append (garbage , op );
340+ }
341+ else {
342+ if ((clear = op -> ob_type -> tp_clear ) != NULL ) {
343+ Py_INCREF (op );
344+ clear ((PyObject * )op );
345+ Py_DECREF (op );
346+ }
340347 }
341- /* only try to call tp_clear once for each object */
342348 if (unreachable -> gc_next == gc ) {
343- /* still alive, move it, it may die later */
349+ /* object is still alive, move it, it may die later */
344350 gc_list_remove (gc );
345351 gc_list_append (gc , old );
346352 }
@@ -425,7 +431,8 @@ collect(PyGC_Head *young, PyGC_Head *old)
425431 if (debug & DEBUG_STATS ) {
426432 if (m == 0 && n == 0 ) {
427433 PySys_WriteStderr ("gc: done.\n" );
428- } else {
434+ }
435+ else {
429436 PySys_WriteStderr (
430437 "gc: done, %ld unreachable, %ld uncollectable.\n" ,
431438 n + m , n );
@@ -438,6 +445,9 @@ collect(PyGC_Head *young, PyGC_Head *old)
438445 handle_finalizers (& finalizers , old );
439446
440447 if (PyErr_Occurred ()) {
448+ if (gc_str == NULL ) {
449+ gc_str = PyString_FromString ("garbage collection" );
450+ }
441451 PyErr_WriteUnraisable (gc_str );
442452 Py_FatalError ("unexpected exception during garbage collection" );
443453 }
@@ -461,15 +471,17 @@ collect_generations(void)
461471 n = collect (& generation2 , & generation2 );
462472 }
463473 collections1 = 0 ;
464- } else if (collections0 > threshold1 ) {
474+ }
475+ else if (collections0 > threshold1 ) {
465476 generation = 1 ;
466477 collections1 ++ ;
467478 gc_list_merge (& generation0 , & generation1 );
468479 if (generation1 .gc_next != & generation1 ) {
469480 n = collect (& generation1 , & generation2 );
470481 }
471482 collections0 = 0 ;
472- } else {
483+ }
484+ else {
473485 generation = 0 ;
474486 collections0 ++ ;
475487 if (generation0 .gc_next != & generation0 ) {
@@ -603,6 +615,7 @@ static char gc_set_debug__doc__[] =
603615" DEBUG_UNCOLLECTABLE - Print unreachable but uncollectable objects found.\n"
604616" DEBUG_INSTANCES - Print instance objects.\n"
605617" DEBUG_OBJECTS - Print objects other than instances.\n"
618+ " DEBUG_SAVEALL - Save objects to gc.garbage rather than freeing them.\n"
606619" DEBUG_LEAK - Debug leaking programs (everything but STATS).\n"
607620;
608621
@@ -679,14 +692,14 @@ static char gc__doc__ [] =
679692;
680693
681694static PyMethodDef GcMethods [] = {
682- {"enable" , gc_enable , METH_VARARGS , gc_enable__doc__ },
683- {"disable" , gc_disable , METH_VARARGS , gc_disable__doc__ },
695+ {"enable" , gc_enable , METH_VARARGS , gc_enable__doc__ },
696+ {"disable" , gc_disable , METH_VARARGS , gc_disable__doc__ },
684697 {"isenabled" , gc_isenabled , METH_VARARGS , gc_isenabled__doc__ },
685698 {"set_debug" , gc_set_debug , METH_VARARGS , gc_set_debug__doc__ },
686699 {"get_debug" , gc_get_debug , METH_VARARGS , gc_get_debug__doc__ },
687700 {"set_threshold" , gc_set_thresh , METH_VARARGS , gc_set_thresh__doc__ },
688701 {"get_threshold" , gc_get_thresh , METH_VARARGS , gc_get_thresh__doc__ },
689- {"collect" , gc_collect , METH_VARARGS , gc_collect__doc__ },
702+ {"collect" , gc_collect , METH_VARARGS , gc_collect__doc__ },
690703 {NULL , NULL } /* Sentinel */
691704};
692705
@@ -705,9 +718,6 @@ initgc(void)
705718 if (garbage == NULL ) {
706719 garbage = PyList_New (0 );
707720 }
708- if (gc_str == NULL ) {
709- gc_str = PyString_FromString ("garbage collection" );
710- }
711721 PyDict_SetItemString (d , "garbage" , garbage );
712722 PyDict_SetItemString (d , "DEBUG_STATS" ,
713723 PyInt_FromLong (DEBUG_STATS ));
@@ -719,6 +729,8 @@ initgc(void)
719729 PyInt_FromLong (DEBUG_INSTANCES ));
720730 PyDict_SetItemString (d , "DEBUG_OBJECTS" ,
721731 PyInt_FromLong (DEBUG_OBJECTS ));
732+ PyDict_SetItemString (d , "DEBUG_SAVEALL" ,
733+ PyInt_FromLong (DEBUG_SAVEALL ));
722734 PyDict_SetItemString (d , "DEBUG_LEAK" ,
723735 PyInt_FromLong (DEBUG_LEAK ));
724736}
0 commit comments