Mailing List Archive

python/dist/src/Modules gcmodule.c,2.49,2.50
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 ----