[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
+ }
+