[Python-checkins] CVS: python/dist/src/Modules gcmodule.c,2.18,2.19

Neil Schemenauer nascheme@users.sourceforge.net
Wed, 29 Aug 2001 17:05:53 -0700


Update of /cvsroot/python/python/dist/src/Modules
In directory usw-pr-cvs1:/tmp/cvs-serv12908/Modules

Modified Files:
	gcmodule.c 
Log Message:
Make more things internal to this file.  Remove
visit_finalizer_reachable since it's the same as visit_reachable.
Rename visit_reachable to visit_move.  Objects can now have the GC type
flag set, reachable by tp_traverse and not be in a GC linked list.  This
should make the collector more robust and easier to use by extension
module writers.  Add memory management functions for container objects
(new, del, resize).


Index: gcmodule.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/gcmodule.c,v
retrieving revision 2.18
retrieving revision 2.19
diff -C2 -d -r2.18 -r2.19
*** gcmodule.c	2001/08/10 14:46:47	2.18
--- gcmodule.c	2001/08/30 00:05:51	2.19
***************
*** 9,13 ****
    Eric Tiedemann, and various others.
  
!   http://www.arctrix.com/nas/python/gc.html
    http://www.python.org/pipermail/python-dev/2000-March/003869.html
    http://www.python.org/pipermail/python-dev/2000-March/004010.html
--- 9,13 ----
    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
***************
*** 19,34 ****
  */
  
- 
  #include "Python.h"
  
  #ifdef WITH_CYCLE_GC
  
! /* magic gc_refs value */
! #define GC_MOVED -1
  
  /*** Global GC state ***/
  
  /* linked lists of container objects */
! static PyGC_Head generation0 = {&generation0, &generation0, 0};
  static PyGC_Head generation1 = {&generation1, &generation1, 0};
  static PyGC_Head generation2 = {&generation2, &generation2, 0};
--- 19,37 ----
  */
  
  #include "Python.h"
  
  #ifdef WITH_CYCLE_GC
  
! /* Get an object's GC head */
! #define AS_GC(o) ((PyGC_Head *)(o)-1)
! 
! /* Get the object given the GC head */
! #define FROM_GC(g) ((PyObject *)(((PyGC_Head *)g)+1))
  
+ 
  /*** Global GC state ***/
  
  /* linked lists of container objects */
! PyGC_Head _PyGC_generation0 = {&_PyGC_generation0, &_PyGC_generation0, 0};
  static PyGC_Head generation1 = {&generation1, &generation1, 0};
  static PyGC_Head generation2 = {&generation2, &generation2, 0};
***************
*** 44,47 ****
--- 47,53 ----
  static int allocated;
  
+ /* true if we are currently running the collector */
+ static int collecting;
+ 
  /* set for debugging information */
  #define DEBUG_STATS		(1<<0) /* print collection statistics */
***************
*** 58,61 ****
--- 64,70 ----
  static int debug;
  
+ /* Special gc_refs value */
+ #define GC_MOVED  -123
+ 
  /* list of uncollectable objects */
  static PyObject *garbage;
***************
*** 87,94 ****
  	node->gc_prev->gc_next = node->gc_next;
  	node->gc_next->gc_prev = node->gc_prev;
! #ifdef Py_DEBUG
! 	node->gc_prev = NULL;
! 	node->gc_next = NULL;
! #endif
  }
  
--- 96,100 ----
  	node->gc_prev->gc_next = node->gc_next;
  	node->gc_next->gc_prev = node->gc_prev;
! 	node->gc_next = NULL; /* object is not currently tracked */
  }
  
***************
*** 138,141 ****
--- 144,148 ----
  
  
+ 
  /* Set all gc_refs = ob_refcnt */
  static void
***************
*** 144,148 ****
  	PyGC_Head *gc = containers->gc_next;
  	for (; gc != containers; gc=gc->gc_next) {
! 		gc->gc_refs = PyObject_FROM_GC(gc)->ob_refcnt;
  	}
  }
--- 151,155 ----
  	PyGC_Head *gc = containers->gc_next;
  	for (; gc != containers; gc=gc->gc_next) {
! 		gc->gc_refs = FROM_GC(gc)->ob_refcnt;
  	}
  }
***************
*** 152,156 ****
  {
  	if (op && PyObject_IS_GC(op)) {
! 		PyObject_AS_GC(op)->gc_refs--;
  	}
  	return 0;
--- 159,165 ----
  {
  	if (op && PyObject_IS_GC(op)) {
! 		PyGC_Head *gc = AS_GC(op);
! 		if (gc->gc_next != NULL)
! 			AS_GC(op)->gc_refs--;
  	}
  	return 0;
***************
*** 164,169 ****
  	PyGC_Head *gc = containers->gc_next;
  	for (; gc != containers; gc=gc->gc_next) {
! 		traverse = PyObject_FROM_GC(gc)->ob_type->tp_traverse;
! 		(void) traverse(PyObject_FROM_GC(gc),
  			       (visitproc)visit_decref,
  			       NULL);
--- 173,178 ----
  	PyGC_Head *gc = containers->gc_next;
  	for (; gc != containers; gc=gc->gc_next) {
! 		traverse = FROM_GC(gc)->ob_type->tp_traverse;
! 		(void) traverse(FROM_GC(gc),
  			       (visitproc)visit_decref,
  			       NULL);
***************
*** 189,199 ****
  
  static int
! visit_reachable(PyObject *op, PyGC_Head *roots)
  {
  	if (PyObject_IS_GC(op)) {
! 		PyGC_Head *gc = PyObject_AS_GC(op);
! 		if (gc && gc->gc_refs != GC_MOVED) {
  			gc_list_remove(gc);
! 			gc_list_append(gc, roots);
  			gc->gc_refs = GC_MOVED;
  		}
--- 198,208 ----
  
  static int
! visit_move(PyObject *op, PyGC_Head *tolist)
  {
  	if (PyObject_IS_GC(op)) {
! 		PyGC_Head *gc = AS_GC(op);
! 		if (gc->gc_next != NULL && gc->gc_refs != GC_MOVED) {
  			gc_list_remove(gc);
! 			gc_list_append(gc, tolist);
  			gc->gc_refs = GC_MOVED;
  		}
***************
*** 210,222 ****
  	for (; gc != reachable; gc=gc->gc_next) {
  		/* careful, reachable list is growing here */
! 		PyObject *op = PyObject_FROM_GC(gc);
  		traverse = op->ob_type->tp_traverse;
  		(void) traverse(op,
! 			       (visitproc)visit_reachable,
  			       (void *)reachable);
  	}
  }
  
! /* move all objects with finalizers (instances with __del__) */
  static void
  move_finalizers(PyGC_Head *unreachable, PyGC_Head *finalizers)
--- 219,231 ----
  	for (; gc != reachable; gc=gc->gc_next) {
  		/* careful, reachable list is growing here */
! 		PyObject *op = FROM_GC(gc);
  		traverse = op->ob_type->tp_traverse;
  		(void) traverse(op,
! 			       (visitproc)visit_move,
  			       (void *)reachable);
  	}
  }
  
! /* Move all objects with finalizers (instances with __del__) */
  static void
  move_finalizers(PyGC_Head *unreachable, PyGC_Head *finalizers)
***************
*** 231,235 ****
  	}
  	for (; gc != unreachable; gc=next) {
! 		PyObject *op = PyObject_FROM_GC(gc);
  		next = gc->gc_next;
  		if (PyInstance_Check(op) && PyObject_HasAttr(op, delstr)) {
--- 240,244 ----
  	}
  	for (; gc != unreachable; gc=next) {
! 		PyObject *op = FROM_GC(gc);
  		next = gc->gc_next;
  		if (PyInstance_Check(op) && PyObject_HasAttr(op, delstr)) {
***************
*** 240,259 ****
  }
  
- 
- /* called by tp_traverse */
- static int
- visit_finalizer_reachable(PyObject *op, PyGC_Head *finalizers)
- {
- 	if (PyObject_IS_GC(op)) {
- 		PyGC_Head *gc = PyObject_AS_GC(op);
- 		if (gc && gc->gc_refs != GC_MOVED) {
- 			gc_list_remove(gc);
- 			gc_list_append(gc, finalizers);
- 			gc->gc_refs = GC_MOVED;
- 		}
- 	}
- 	return 0;
- }
- 
  /* Move objects referenced from roots to roots */
  static void
--- 249,252 ----
***************
*** 264,270 ****
  	for (; gc != finalizers; gc=gc->gc_next) {
  		/* careful, finalizers list is growing here */
! 		traverse = PyObject_FROM_GC(gc)->ob_type->tp_traverse;
! 		(void) traverse(PyObject_FROM_GC(gc), 
! 			       (visitproc)visit_finalizer_reachable,
  			       (void *)finalizers);
  	}
--- 257,263 ----
  	for (; gc != finalizers; gc=gc->gc_next) {
  		/* careful, finalizers list is growing here */
! 		traverse = FROM_GC(gc)->ob_type->tp_traverse;
! 		(void) traverse(FROM_GC(gc), 
! 			       (visitproc)visit_move,
  			       (void *)finalizers);
  	}
***************
*** 307,311 ****
  	for (gc = finalizers->gc_next; gc != finalizers;
  			gc = finalizers->gc_next) {
! 		PyObject *op = PyObject_FROM_GC(gc);
  		if ((debug & DEBUG_SAVEALL) || PyInstance_Check(op)) {
  			/* If SAVEALL is not set then just append
--- 300,304 ----
  	for (gc = finalizers->gc_next; gc != finalizers;
  			gc = finalizers->gc_next) {
! 		PyObject *op = FROM_GC(gc);
  		if ((debug & DEBUG_SAVEALL) || PyInstance_Check(op)) {
  			/* If SAVEALL is not set then just append
***************
*** 331,335 ****
  	while (unreachable->gc_next != unreachable) {
  		PyGC_Head *gc = unreachable->gc_next;
! 		PyObject *op = PyObject_FROM_GC(gc);
  		if (debug & DEBUG_SAVEALL) {
  			PyList_Append(garbage, op);
--- 324,328 ----
  	while (unreachable->gc_next != unreachable) {
  		PyGC_Head *gc = unreachable->gc_next;
! 		PyObject *op = FROM_GC(gc);
  		if (debug & DEBUG_SAVEALL) {
  			PyList_Append(garbage, op);
***************
*** 367,371 ****
  			"gc: objects in each generation: %ld %ld %ld\n",
  			generation,
! 			gc_list_size(&generation0),
  			gc_list_size(&generation1),
  			gc_list_size(&generation2));
--- 360,364 ----
  			"gc: objects in each generation: %ld %ld %ld\n",
  			generation,
! 			gc_list_size(&_PyGC_generation0),
  			gc_list_size(&generation1),
  			gc_list_size(&generation2));
***************
*** 408,412 ****
  		m++;
  		if (debug & DEBUG_COLLECTABLE) {
! 			debug_cycle("collectable", PyObject_FROM_GC(gc));
  		}
  	}
--- 401,405 ----
  		m++;
  		if (debug & DEBUG_COLLECTABLE) {
! 			debug_cycle("collectable", FROM_GC(gc));
  		}
  	}
***************
*** 422,426 ****
  		n++;
  		if (debug & DEBUG_UNCOLLECTABLE) {
! 			debug_cycle("uncollectable", PyObject_FROM_GC(gc));
  		}
  	}
--- 415,419 ----
  		n++;
  		if (debug & DEBUG_UNCOLLECTABLE) {
! 			debug_cycle("uncollectable", FROM_GC(gc));
  		}
  	}
***************
*** 462,466 ****
  	if (collections1 > threshold2) {
  		generation = 2;
! 		gc_list_merge(&generation0, &generation2);
  		gc_list_merge(&generation1, &generation2);
  		if (generation2.gc_next != &generation2) {
--- 455,459 ----
  	if (collections1 > threshold2) {
  		generation = 2;
! 		gc_list_merge(&_PyGC_generation0, &generation2);
  		gc_list_merge(&generation1, &generation2);
  		if (generation2.gc_next != &generation2) {
***************
*** 472,476 ****
  		generation = 1;
  		collections1++;
! 		gc_list_merge(&generation0, &generation1);
  		if (generation1.gc_next != &generation1) {
  			n = collect(&generation1, &generation2);
--- 465,469 ----
  		generation = 1;
  		collections1++;
! 		gc_list_merge(&_PyGC_generation0, &generation1);
  		if (generation1.gc_next != &generation1) {
  			n = collect(&generation1, &generation2);
***************
*** 481,486 ****
  		generation = 0;
  		collections0++;
! 		if (generation0.gc_next != &generation0) {
! 			n = collect(&generation0, &generation1);
  		}
  	}
--- 474,479 ----
  		generation = 0;
  		collections0++;
! 		if (_PyGC_generation0.gc_next != &_PyGC_generation0) {
! 			n = collect(&_PyGC_generation0, &generation1);
  		}
  	}
***************
*** 488,530 ****
  }
  
- void
- _PyGC_Insert(PyObject *op)
- {
- 	/* collection lock since collecting may cause allocations */
- 	static int collecting = 0;
- 
- #ifdef Py_DEBUG
- 	if (!PyObject_IS_GC(op)) {
- 		abort();
- 	}
- #endif
- 	if (allocated > threshold0 &&
- 	    enabled &&
- 	    threshold0 &&
- 	    !collecting &&
- 	    !PyErr_Occurred()) {
- 		collecting++;
- 		collect_generations();
- 		collecting--;
- 	}
- 	allocated++;
- 	gc_list_append(PyObject_AS_GC(op), &generation0);
- }
- 
- void
- _PyGC_Remove(PyObject *op)
- {
- 	PyGC_Head *g = PyObject_AS_GC(op);
- #ifdef Py_DEBUG
- 	if (!PyObject_IS_GC(op)) {
- 		abort();
- 	}
- #endif
- 	gc_list_remove(g);
- 	if (allocated > 0) {
- 		allocated--;
- 	}
- }
- 
  static char gc_enable__doc__[] =
  "enable() -> None\n"
--- 481,484 ----
***************
*** 596,600 ****
  
  	generation = 2;
! 	gc_list_merge(&generation0, &generation2);
  	gc_list_merge(&generation1, &generation2);
  	n = collect(&generation2, &generation2);
--- 550,554 ----
  
  	generation = 2;
! 	gc_list_merge(&_PyGC_generation0, &generation2);
  	gc_list_merge(&generation1, &generation2);
  	n = collect(&generation2, &generation2);
***************
*** 694,698 ****
  	traverseproc traverse;
  	for (gc = list->gc_next; gc != list; gc = gc->gc_next) {
! 		obj = PyObject_FROM_GC(gc);
  		traverse = obj->ob_type->tp_traverse;
  		if (obj == objs || obj == resultlist)
--- 648,652 ----
  	traverseproc traverse;
  	for (gc = list->gc_next; gc != list; gc = gc->gc_next) {
! 		obj = FROM_GC(gc);
  		traverse = obj->ob_type->tp_traverse;
  		if (obj == objs || obj == resultlist)
***************
*** 714,718 ****
  {
  	PyObject *result = PyList_New(0);
! 	if (!(gc_referents_for(args, &generation0, result) &&
  	      gc_referents_for(args, &generation1, result) &&
  	      gc_referents_for(args, &generation2, result))) {
--- 668,672 ----
  {
  	PyObject *result = PyList_New(0);
! 	if (!(gc_referents_for(args, &_PyGC_generation0, result) &&
  	      gc_referents_for(args, &generation1, result) &&
  	      gc_referents_for(args, &generation2, result))) {
***************
*** 736,740 ****
  	PyGC_Head *gc;
  	for (gc = gc_list->gc_next; gc != gc_list; gc = gc->gc_next) {
! 		PyObject *op = PyObject_FROM_GC(gc);
  		if (op != py_list) {
  			Py_INCREF(op);
--- 690,694 ----
  	PyGC_Head *gc;
  	for (gc = gc_list->gc_next; gc != gc_list; gc = gc->gc_next) {
! 		PyObject *op = FROM_GC(gc);
  		if (op != py_list) {
  			Py_INCREF(op);
***************
*** 752,756 ****
  		return NULL;
  	result = PyList_New(0);
! 	append_objects(result, &generation0);
  	append_objects(result, &generation1);
  	append_objects(result, &generation2);
--- 706,710 ----
  		return NULL;
  	result = PyList_New(0);
! 	append_objects(result, &_PyGC_generation0);
  	append_objects(result, &generation1);
  	append_objects(result, &generation2);
***************
*** 821,823 ****
--- 775,878 ----
  }
  
+ /* for debugging */
+ void _PyGC_Dump(PyGC_Head *g)
+ {
+ 	_PyObject_Dump(FROM_GC(g));
+ }
+ 
  #endif /* WITH_CYCLE_GC */
+ 
+ /* extension modules might be compiled with GC support so these
+    functions must always be available */
+ 
+ void
+ _PyObject_GC_Track(PyObject *op)
+ {
+ 	_PyObject_GC_TRACK(op);
+ }
+ 
+ void
+ _PyObject_GC_UnTrack(PyObject *op)
+ {
+ 	_PyObject_GC_UNTRACK(op);
+ }
+ 
+ PyObject *
+ _PyObject_GC_Malloc(PyTypeObject *tp, int size)
+ {
+ 	PyObject *op;
+ #ifdef WITH_CYCLE_GC
+ 	PyGC_Head *g = PyObject_MALLOC(_PyObject_VAR_SIZE(tp, size) +
+ 						sizeof(PyGC_Head));
+ 	if (g == NULL)
+ 		return (PyObject *)PyErr_NoMemory();
+ 	g->gc_next = NULL;
+ 	allocated++;
+  	if (allocated > threshold0 &&
+  	    enabled &&
+  	    threshold0 &&
+  	    !collecting &&
+  	    !PyErr_Occurred()) {
+ 		collecting = 1;
+  		collect_generations();
+ 		collecting = 0;
+ 	}
+ 	op = FROM_GC(g);
+ #else
+ 	op = PyObject_MALLOC(_PyObject_VAR_SIZE(tp, size));
+ 	if (op == NULL)
+ 		return (PyObject *)PyErr_NoMemory();
+ 
+ #endif
+ 	return op;
+ }
+ 
+ PyObject *
+ _PyObject_GC_New(PyTypeObject *tp)
+ {
+ 	PyObject *op = _PyObject_GC_Malloc(tp, 0);
+ 	return PyObject_INIT(op, tp);
+ }
+ 
+ PyVarObject *
+ _PyObject_GC_NewVar(PyTypeObject *tp, int size)
+ {
+ 	PyVarObject *op = (PyVarObject *) _PyObject_GC_Malloc(tp, size);
+ 	return PyObject_INIT_VAR(op, tp, size);
+ }
+ 
+ PyVarObject *
+ _PyObject_GC_Resize(PyVarObject *op, int size)
+ {
+ #ifdef WITH_CYCLE_GC
+ 	PyGC_Head *g = AS_GC(op);
+ 	g = PyObject_REALLOC(g, _PyObject_VAR_SIZE(op->ob_type, size) +
+ 						sizeof(PyGC_Head));
+ 	if (g == NULL)
+ 		return (PyVarObject *)PyErr_NoMemory();
+ 	op = (PyVarObject *) FROM_GC(g);
+ #else
+ 	op = PyObject_REALLOC(op, _PyObject_VAR_SIZE(op->ob_type, size));
+ 	if (op == NULL)
+ 		return (PyVarObject *)PyErr_NoMemory();
+ #endif
+ 	op->ob_size = size;
+ 	return op;
+ }
+ 
+ void
+ _PyObject_GC_Del(PyObject *op)
+ {
+ #ifdef WITH_CYCLE_GC
+ 	PyGC_Head *g = AS_GC(op);
+ 	if (g->gc_next != NULL)
+ 		gc_list_remove(g);
+ 	if (allocated > 0) {
+ 		allocated--;
+ 	}
+ 	PyObject_FREE(g);
+ #else
+ 	PyObject_FREE(op);
+ #endif
+ }
+