[Python-checkins] python/dist/src/Modules gcmodule.c,2.49,2.50

tim_one@users.sourceforge.net tim_one@users.sourceforge.net
Tue, 02 Jul 2002 11:12:38 -0700


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

Modified Files:
	gcmodule.c 
Log Message:
Finished transitioning to using gc_refs to track gc objects' states.
This was mostly a matter of adding comments and light code rearrangement.
Upon untracking, gc_next is still set to NULL.  It's a cheap way to
provoke memory faults if calling code is insane.  It's also used in some
way by the trashcan mechanism.


Index: gcmodule.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/gcmodule.c,v
retrieving revision 2.49
retrieving revision 2.50
diff -C2 -d -r2.49 -r2.50
*** gcmodule.c	2 Jul 2002 00:52:30 -0000	2.49
--- gcmodule.c	2 Jul 2002 18:12:35 -0000	2.50
***************
*** 29,35 ****
  #define FROM_GC(g) ((PyObject *)(((PyGC_Head *)g)+1))
  
- /* True if an object is tracked by the GC */
- #define IS_TRACKED(o) ((AS_GC(o))->gc.gc_next != NULL)
- 
  /*** Global GC state ***/
  
--- 29,32 ----
***************
*** 59,62 ****
--- 56,65 ----
  static int collecting;
  
+ /* list of uncollectable objects */
+ static PyObject *garbage;
+ 
+ /* Python string to use if unhandled exception occurs */
+ static PyObject *gc_str;
+ 
  /* set for debugging information */
  #define DEBUG_STATS		(1<<0) /* print collection statistics */
***************
*** 73,100 ****
  static int debug;
  
! /* When a collection begins, gc_refs is set to ob_refcnt for, and only for,
!  * the objects in the generation being collected, called the "young"
!  * generation at that point.  As collection proceeds, the gc_refs members
!  * of young objects are set to GC_REACHABLE when it becomes known that they're
!  * uncollectable, and to GC_TENTATIVELY_UNREACHABLE when the evidence
!  * suggests they are collectable (this can't be known for certain until all
!  * of the young generation is scanned).
!  */
  
! /* Special gc_refs values. */
  #define GC_UNTRACKED			_PyGC_REFS_UNTRACKED
  #define GC_REACHABLE			_PyGC_REFS_REACHABLE
  #define GC_TENTATIVELY_UNREACHABLE	_PyGC_REFS_TENTATIVELY_UNREACHABLE
  
  #define IS_REACHABLE(o) ((AS_GC(o))->gc.gc_refs == GC_REACHABLE)
  #define IS_TENTATIVELY_UNREACHABLE(o) ( \
  	(AS_GC(o))->gc.gc_refs == GC_TENTATIVELY_UNREACHABLE)
  
- /* list of uncollectable objects */
- static PyObject *garbage;
- 
- /* Python string to use if unhandled exception occurs */
- static PyObject *gc_str;
- 
  /*** list functions ***/
  
--- 76,127 ----
  static int debug;
  
! /*--------------------------------------------------------------------------
! gc_refs values.
  
! Between collections, every gc'ed object has one of two gc_refs values:
! 
! GC_UNTRACKED
!     The initial state; objects returned by PyObject_GC_Malloc are in this
!     state.  The object doesn't live in any generation list, and its
!     tp_traverse slot must not be called.
! 
! GC_REACHABLE
!     The object lives in some generation list, and its tp_traverse is safe to
!     call.  An object transitions to GC_REACHABLE when PyObject_GC_Track
!     is called.
! 
! During a collection, gc_refs can temporarily take on other states:
! 
! >= 0
!     At the start of a collection, update_refs() copies the true refcount
!     to gc_refs, for each object in the generation being collected.
!     subtract_refs() then adjusts gc_refs so that it equals the number of
!     times an object is referenced directly from outside the generation
!     being collected.
!     gc_refs reamins >= 0 throughout these steps.
! 
! GC_TENTATIVELY_UNREACHABLE
!     move_unreachable() then moves objects not reachable (whether directly or
!     indirectly) from outside the generation into an "unreachable" set.
!     Objects that are found to be reachable have gc_refs set to GC_REACHABLE
!     again.  Objects that are found to be unreachable have gc_refs set to
!     GC_TENTATIVELY_UNREACHABLE.  It's "tentatively" because the pass doing
!     this can't be sure until it ends, and GC_TENTATIVELY_UNREACHABLE may
!     transition back to GC_REACHABLE.
! 
!     Only objects with GC_TENTATIVELY_UNREACHABLE still set are candidates
!     for collection.  If it's decided not to collect such an object (e.g.,
!     it has a __del__ method), its gc_refs is restored to GC_REACHABLE again.
! ----------------------------------------------------------------------------
! */
  #define GC_UNTRACKED			_PyGC_REFS_UNTRACKED
  #define GC_REACHABLE			_PyGC_REFS_REACHABLE
  #define GC_TENTATIVELY_UNREACHABLE	_PyGC_REFS_TENTATIVELY_UNREACHABLE
  
+ #define IS_TRACKED(o) ((AS_GC(o))->gc.gc_refs != GC_UNTRACKED)
  #define IS_REACHABLE(o) ((AS_GC(o))->gc.gc_refs == GC_REACHABLE)
  #define IS_TENTATIVELY_UNREACHABLE(o) ( \
  	(AS_GC(o))->gc.gc_refs == GC_TENTATIVELY_UNREACHABLE)
  
  /*** list functions ***/
  
***************
*** 254,258 ****
  		 * If gc_refs == GC_REACHABLE, it's either in some other
  		 * generation so we don't care about it, or move_unreachable
! 		 * already deat with it.
  		 * If gc_refs == GC_UNTRACKED, it must be ignored.
  		 */
--- 281,285 ----
  		 * If gc_refs == GC_REACHABLE, it's either in some other
  		 * generation so we don't care about it, or move_unreachable
! 		 * already dealt with it.
  		 * If gc_refs == GC_UNTRACKED, it must be ignored.
  		 */
***************
*** 291,295 ****
  		PyGC_Head *next;
  
! 		if (gc->gc.gc_refs == 0) {
  			/* This *may* be unreachable.  To make progress,
  			 * assume it is.  gc isn't directly reachable from
--- 318,340 ----
  		PyGC_Head *next;
  
! 		if (gc->gc.gc_refs) {
!                         /* gc is definitely reachable from outside the
!                          * original 'young'.  Mark it as such, and traverse
!                          * its pointers to find any other objects that may
!                          * be directly reachable from it.  Note that the
!                          * call to tp_traverse may append objects to young,
!                          * so we have to wait until it returns to determine
!                          * the next object to visit.
!                          */
!                         PyObject *op = FROM_GC(gc);
!                         traverseproc traverse = op->ob_type->tp_traverse;
!                         assert(gc->gc.gc_refs > 0);
!                         gc->gc.gc_refs = GC_REACHABLE;
!                         (void) traverse(op,
!                                         (visitproc)visit_reachable,
!                                         (void *)young);
!                         next = gc->gc.gc_next;
! 		}
! 		else {
  			/* This *may* be unreachable.  To make progress,
  			 * assume it is.  gc isn't directly reachable from
***************
*** 304,324 ****
  			gc->gc.gc_refs = GC_TENTATIVELY_UNREACHABLE;
  		}
- 		else {
- 			/* gc is definitely reachable from outside the
- 			 * original 'young'.  Mark it as such, and traverse
- 			 * its pointers to find any other objects that may
- 			 * be directly reachable from it.  Note that the
- 			 * call to tp_traverse may append objects to young,
- 			 * so we have to wait until it returns to determine
- 			 * the next object to visit.
- 			 */
- 			PyObject *op = FROM_GC(gc);
- 			traverseproc traverse = op->ob_type->tp_traverse;
- 			gc->gc.gc_refs = GC_REACHABLE;
- 			(void) traverse(op,
- 			       		(visitproc)visit_reachable,
- 			    		(void *)young);
- 			next = gc->gc.gc_next;
- 		}
  		gc = next;
  	}
--- 349,352 ----
***************
*** 975,979 ****
  	if (g == NULL)
  		return PyErr_NoMemory();
- 	g->gc.gc_next = NULL;
  	g->gc.gc_refs = GC_UNTRACKED;
  	generations[0].count++; /* number of allocated GC objects */
--- 1003,1006 ----