PyDoc_STRVAR(gc_get_debug__doc__,"get_debug() -> flags\n""\n""Get the garbage collection debugging flags.\n"); static PyObject *gc_get_debug(PyObject *self, PyObject *noargs){ return Py_BuildValue("i", debug);} PyDoc_STRVAR(gc_set_thresh__doc__,"set_threshold(threshold0, [threshold1, threshold2]) -> None\n""\n""Sets the collection thresholds. Setting threshold0 to zero disables\n""collection.\n"); static PyObject *gc_set_thresh(PyObject *self, PyObject *args){ int i; if (!PyArg_ParseTuple(args, "i|ii:set_threshold", &generations[0].threshold, &generations[1].threshold, &generations[2].threshold)) return NULL; for (i = 2; i < NUM_GENERATIONS; i++) { /* generations higher than 2 get the same threshold */ generations[i].threshold = generations[2].threshold; } Py_INCREF(Py_None); return Py_None;} PyDoc_STRVAR(gc_get_thresh__doc__,"get_threshold() -> (threshold0, threshold1, threshold2)\n""\n""Return the current collection thresholds\n"); static PyObject *gc_get_thresh(PyObject *self, PyObject *noargs){ return Py_BuildValue("(iii)", generations[0].threshold, generations[1].threshold, generations[2].threshold);} PyDoc_STRVAR(gc_get_count__doc__,"get_count() -> (count0, count1, count2)\n""\n""Return the current collection counts\n"); static PyObject *gc_get_count(PyObject *self, PyObject *noargs){ return Py_BuildValue("(iii)", generations[0].count, generations[1].count, generations[2].count);} static intreferrersvisit(PyObject* obj, PyObject *objs){ Py_ssize_t i; for (i = 0; i < PyTuple_GET_SIZE(objs); i++) if (PyTuple_GET_ITEM(objs, i) == obj) return 1; return 0;} static intgc_referrers_for(PyObject *objs, PyGC_Head *list, PyObject *resultlist){ PyGC_Head *gc; PyObject *obj; traverseproc traverse; for (gc = list->gc.gc_next; gc != list; gc = gc->gc.gc_next) { obj = FROM_GC(gc); traverse = obj->ob_type->tp_traverse; if (obj == objs || obj == resultlist) continue; if (traverse(obj, (visitproc)referrersvisit, objs)) { if (PyList_Append(resultlist, obj) < 0) return 0; /* error */ } } return 1; /* no error */} PyDoc_STRVAR(gc_get_referrers__doc__,"get_referrers(*objs) -> list\n\Return the list of objects that directly refer to any of objs."); static PyObject *gc_get_referrers(PyObject *self, PyObject *args){ int i; PyObject *result = PyList_New(0); if (!result) return NULL; for (i = 0; i < NUM_GENERATIONS; i++) { if (!(gc_referrers_for(args, GEN_HEAD(i), result))) { Py_DECREF(result); return NULL; } } return result;} /* Append obj to list; return true if error (out of memory), false if OK. */static intreferentsvisit(PyObject *obj, PyObject *list){ return PyList_Append(list, obj) < 0;} PyDoc_STRVAR(gc_get_referents__doc__,"get_referents(*objs) -> list\n\Return the list of objects that are directly referred to by objs."); static PyObject *gc_get_referents(PyObject *self, PyObject *args){ Py_ssize_t i; PyObject *result = PyList_New(0); if (result == NULL) return NULL; for (i = 0; i < PyTuple_GET_SIZE(args); i++) { traverseproc traverse; PyObject *obj = PyTuple_GET_ITEM(args, i); if (! PyObject_IS_GC(obj)) continue; traverse = obj->ob_type->tp_traverse; if (! traverse) continue; if (traverse(obj, (visitproc)referentsvisit, result)) { Py_DECREF(result); return NULL; } } return result;} PyDoc_STRVAR(gc_get_objects__doc__,"get_objects() -> [...]\n""\n""Return a list of objects tracked by the collector (excluding the list\n""returned).\n"); static PyObject *gc_get_objects(PyObject *self, PyObject *noargs){ int i; PyObject* result; result = PyList_New(0); if (result == NULL) return NULL; for (i = 0; i < NUM_GENERATIONS; i++) { if (append_objects(result, GEN_HEAD(i))) { Py_DECREF(result); return NULL; } } return result;} PyDoc_STRVAR(gc__doc__,"This module provides access to the garbage collector for reference cycles.\n""\n""enable() -- Enable automatic garbage collection.\n""disable() -- Disable automatic garbage collection.\n""isenabled() -- Returns true if automatic collection is enabled.\n""collect() -- Do a full collection right now.\n""get_count() -- Return the current collection counts.\n""set_debug() -- Set debugging flags.\n""get_debug() -- Get debugging flags.\n""set_threshold() -- Set the collection thresholds.\n""get_threshold() -- Return the current the collection thresholds.\n""get_objects() -- Return a list of all objects tracked by the collector.\n""get_referrers() -- Return the list of objects that refer to an object.\n""get_referents() -- Return the list of objects that an object refers to.\n"); static PyMethodDef GcMethods[] = { {"enable", gc_enable, METH_NOARGS, gc_enable__doc__}, {"disable", gc_disable, METH_NOARGS, gc_disable__doc__}, {"isenabled", gc_isenabled, METH_NOARGS, gc_isenabled__doc__}, {"set_debug", gc_set_debug, METH_VARARGS, gc_set_debug__doc__}, {"get_debug", gc_get_debug, METH_NOARGS, gc_get_debug__doc__}, {"get_count", gc_get_count, METH_NOARGS, gc_get_count__doc__}, {"set_threshold", gc_set_thresh, METH_VARARGS, gc_set_thresh__doc__}, {"get_threshold", gc_get_thresh, METH_NOARGS, gc_get_thresh__doc__}, {"collect", (PyCFunction)gc_collect, METH_VARARGS | METH_KEYWORDS, gc_collect__doc__}, {"get_objects", gc_get_objects,METH_NOARGS, gc_get_objects__doc__}, {"get_referrers", gc_get_referrers, METH_VARARGS, gc_get_referrers__doc__}, {"get_referents", gc_get_referents, METH_VARARGS, gc_get_referents__doc__}, {NULL, NULL} /* Sentinel */}; PyMODINIT_FUNCinitgc(void){ PyObject *m; m = Py_InitModule4("gc", GcMethods, gc__doc__, NULL, PYTHON_API_VERSION); if (m == NULL) return; if (garbage == NULL) { garbage = PyList_New(0); if (garbage == NULL) return; } Py_INCREF(garbage); if (PyModule_AddObject(m, "garbage", garbage) < 0) return; /* Importing can't be done in collect() because collect() * can be called via PyGC_Collect() in Py_Finalize(). * This wouldn't be a problem, except that <initialized> is * reset to 0 before calling collect which trips up * the import and triggers an assertion. */ if (tmod == NULL) { tmod = PyImport_ImportModule("time"); if (tmod == NULL) PyErr_Clear(); } #define ADD_INT(NAME) if (PyModule_AddIntConstant(m, #NAME, NAME) < 0) return ADD_INT(DEBUG_STATS); ADD_INT(DEBUG_COLLECTABLE); ADD_INT(DEBUG_UNCOLLECTABLE); ADD_INT(DEBUG_INSTANCES); ADD_INT(DEBUG_OBJECTS); ADD_INT(DEBUG_SAVEALL); ADD_INT(DEBUG_LEAK);#undef ADD_INT} /* API to invoke gc.collect() from C */Py_ssize_tPyGC_Collect(void){ Py_ssize_t n; if (collecting) n = 0; /* already collecting, don't do anything */ else { collecting = 1; n = collect(NUM_GENERATIONS - 1); collecting = 0; } return n;} /* for debugging */void_PyGC_Dump(PyGC_Head *g){ _PyObject_Dump(FROM_GC(g));} /* extension modules might be compiled with GC support so these functions must always be available */ #undef PyObject_GC_Track#undef PyObject_GC_UnTrack#undef PyObject_GC_Del#undef _PyObject_GC_Malloc voidPyObject_GC_Track(void *op){ _PyObject_GC_TRACK(op);} /* for binary compatibility with 2.2 */void_PyObject_GC_Track(PyObject *op){ PyObject_GC_Track(op);} voidPyObject_GC_UnTrack(void *op){ /* Obscure: the Py_TRASHCAN mechanism requires that we be able to * call PyObject_GC_UnTrack twice on an object. */ if (IS_TRACKED(op)) _PyObject_GC_UNTRACK(op);} /* for binary compatibility with 2.2 */void_PyObject_GC_UnTrack(PyObject *op){ PyObject_GC_UnTrack(op);} PyObject *_PyObject_GC_Malloc(size_t basicsize){ PyObject *op; PyGC_Head *g = (PyGC_Head *)PyObject_MALLOC( sizeof(PyGC_Head) + basicsize); if (g == NULL) return PyErr_NoMemory(); g->gc.gc_refs = GC_UNTRACKED; generations[0].count++; /* number of allocated GC objects */ if (generations[0].count > generations[0].threshold && enabled && generations[0].threshold && !collecting && !PyErr_Occurred()) { collecting = 1; collect_generations(); collecting = 0; } op = FROM_GC(g); return op;} PyObject *_PyObject_GC_New(PyTypeObject *tp){ PyObject *op = _PyObject_GC_Malloc(_PyObject_SIZE(tp)); if (op != NULL) op = PyObject_INIT(op, tp); return op;} PyVarObject *_PyObject_GC_NewVar(PyTypeObject *tp, Py_ssize_t nitems){ const size_t size = _PyObject_VAR_SIZE(tp, nitems); PyVarObject *op = (PyVarObject *) _PyObject_GC_Malloc(size); if (op != NULL) op = PyObject_INIT_VAR(op, tp, nitems); return op;} PyVarObject *_PyObject_GC_Resize(PyVarObject *op, Py_ssize_t nitems){ const size_t basicsize = _PyObject_VAR_SIZE(op->ob_type, nitems); PyGC_Head *g = AS_GC(op); g = (PyGC_Head *)PyObject_REALLOC(g, sizeof(PyGC_Head) + basicsize); if (g == NULL) return (PyVarObject *)PyErr_NoMemory(); op = (PyVarObject *) FROM_GC(g); op->ob_size = nitems; return op;} voidPyObject_GC_Del(void *op){ PyGC_Head *g = AS_GC(op); if (IS_TRACKED(op)) gc_list_remove(g); if (generations[0].count > 0) { generations[0].count--; } PyObject_FREE(g);} /* for binary compatibility with 2.2 */#undef _PyObject_GC_Delvoid_PyObject_GC_Del(PyObject *op){ PyObject_GC_Del(op);}Lines 1001–1390 of 1390. Previous lines
PyDoc_STRVAR(gc_get_debug__doc__, "get_debug() -> flags\n" "\n" "Get the garbage collection debugging flags.\n"); static PyObject * gc_get_debug(PyObject *self, PyObject *noargs) { return Py_BuildValue("i", debug); } PyDoc_STRVAR(gc_set_thresh__doc__, "set_threshold(threshold0, [threshold1, threshold2]) -> None\n" "\n" "Sets the collection thresholds. Setting threshold0 to zero disables\n" "collection.\n"); static PyObject * gc_set_thresh(PyObject *self, PyObject *args) { int i; if (!PyArg_ParseTuple(args, "i|ii:set_threshold", &generations[0].threshold, &generations[1].threshold, &generations[2].threshold)) return NULL; for (i = 2; i < NUM_GENERATIONS; i++) { /* generations higher than 2 get the same threshold */ generations[i].threshold = generations[2].threshold; } Py_INCREF(Py_None); return Py_None; } PyDoc_STRVAR(gc_get_thresh__doc__, "get_threshold() -> (threshold0, threshold1, threshold2)\n" "\n" "Return the current collection thresholds\n"); static PyObject * gc_get_thresh(PyObject *self, PyObject *noargs) { return Py_BuildValue("(iii)", generations[0].threshold, generations[1].threshold, generations[2].threshold); } PyDoc_STRVAR(gc_get_count__doc__, "get_count() -> (count0, count1, count2)\n" "\n" "Return the current collection counts\n"); static PyObject * gc_get_count(PyObject *self, PyObject *noargs) { return Py_BuildValue("(iii)", generations[0].count, generations[1].count, generations[2].count); } static int referrersvisit(PyObject* obj, PyObject *objs) { Py_ssize_t i; for (i = 0; i < PyTuple_GET_SIZE(objs); i++) if (PyTuple_GET_ITEM(objs, i) == obj) return 1; return 0; } static int gc_referrers_for(PyObject *objs, PyGC_Head *list, PyObject *resultlist) { PyGC_Head *gc; PyObject *obj; traverseproc traverse; for (gc = list->gc.gc_next; gc != list; gc = gc->gc.gc_next) { obj = FROM_GC(gc); traverse = obj->ob_type->tp_traverse; if (obj == objs || obj == resultlist) continue; if (traverse(obj, (visitproc)referrersvisit, objs)) { if (PyList_Append(resultlist, obj) < 0) return 0; /* error */ } } return 1; /* no error */ } PyDoc_STRVAR(gc_get_referrers__doc__, "get_referrers(*objs) -> list\n\ Return the list of objects that directly refer to any of objs."); static PyObject * gc_get_referrers(PyObject *self, PyObject *args) { int i; PyObject *result = PyList_New(0); if (!result) return NULL; for (i = 0; i < NUM_GENERATIONS; i++) { if (!(gc_referrers_for(args, GEN_HEAD(i), result))) { Py_DECREF(result); return NULL; } } return result; } /* Append obj to list; return true if error (out of memory), false if OK. */ static int referentsvisit(PyObject *obj, PyObject *list) { return PyList_Append(list, obj) < 0; } PyDoc_STRVAR(gc_get_referents__doc__, "get_referents(*objs) -> list\n\ Return the list of objects that are directly referred to by objs."); static PyObject * gc_get_referents(PyObject *self, PyObject *args) { Py_ssize_t i; PyObject *result = PyList_New(0); if (result == NULL) return NULL; for (i = 0; i < PyTuple_GET_SIZE(args); i++) { traverseproc traverse; PyObject *obj = PyTuple_GET_ITEM(args, i); if (! PyObject_IS_GC(obj)) continue; traverse = obj->ob_type->tp_traverse; if (! traverse) continue; if (traverse(obj, (visitproc)referentsvisit, result)) { Py_DECREF(result); return NULL; } } return result; } PyDoc_STRVAR(gc_get_objects__doc__, "get_objects() -> [...]\n" "\n" "Return a list of objects tracked by the collector (excluding the list\n" "returned).\n"); static PyObject * gc_get_objects(PyObject *self, PyObject *noargs) { int i; PyObject* result; result = PyList_New(0); if (result == NULL) return NULL; for (i = 0; i < NUM_GENERATIONS; i++) { if (append_objects(result, GEN_HEAD(i))) { Py_DECREF(result); return NULL; } } return result; } PyDoc_STRVAR(gc__doc__, "This module provides access to the garbage collector for reference cycles.\n" "\n" "enable() -- Enable automatic garbage collection.\n" "disable() -- Disable automatic garbage collection.\n" "isenabled() -- Returns true if automatic collection is enabled.\n" "collect() -- Do a full collection right now.\n" "get_count() -- Return the current collection counts.\n" "set_debug() -- Set debugging flags.\n" "get_debug() -- Get debugging flags.\n" "set_threshold() -- Set the collection thresholds.\n" "get_threshold() -- Return the current the collection thresholds.\n" "get_objects() -- Return a list of all objects tracked by the collector.\n" "get_referrers() -- Return the list of objects that refer to an object.\n" "get_referents() -- Return the list of objects that an object refers to.\n"); static PyMethodDef GcMethods[] = { {"enable", gc_enable, METH_NOARGS, gc_enable__doc__}, {"disable", gc_disable, METH_NOARGS, gc_disable__doc__}, {"isenabled", gc_isenabled, METH_NOARGS, gc_isenabled__doc__}, {"set_debug", gc_set_debug, METH_VARARGS, gc_set_debug__doc__}, {"get_debug", gc_get_debug, METH_NOARGS, gc_get_debug__doc__}, {"get_count", gc_get_count, METH_NOARGS, gc_get_count__doc__}, {"set_threshold", gc_set_thresh, METH_VARARGS, gc_set_thresh__doc__}, {"get_threshold", gc_get_thresh, METH_NOARGS, gc_get_thresh__doc__}, {"collect", (PyCFunction)gc_collect, METH_VARARGS | METH_KEYWORDS, gc_collect__doc__}, {"get_objects", gc_get_objects,METH_NOARGS, gc_get_objects__doc__}, {"get_referrers", gc_get_referrers, METH_VARARGS, gc_get_referrers__doc__}, {"get_referents", gc_get_referents, METH_VARARGS, gc_get_referents__doc__}, {NULL, NULL} /* Sentinel */ }; PyMODINIT_FUNC initgc(void) { PyObject *m; m = Py_InitModule4("gc", GcMethods, gc__doc__, NULL, PYTHON_API_VERSION); if (m == NULL) return; if (garbage == NULL) { garbage = PyList_New(0); if (garbage == NULL) return; } Py_INCREF(garbage); if (PyModule_AddObject(m, "garbage", garbage) < 0) return; /* Importing can't be done in collect() because collect() * can be called via PyGC_Collect() in Py_Finalize(). * This wouldn't be a problem, except that <initialized> is * reset to 0 before calling collect which trips up * the import and triggers an assertion. */ if (tmod == NULL) { tmod = PyImport_ImportModule("time"); if (tmod == NULL) PyErr_Clear(); } #define ADD_INT(NAME) if (PyModule_AddIntConstant(m, #NAME, NAME) < 0) return ADD_INT(DEBUG_STATS); ADD_INT(DEBUG_COLLECTABLE); ADD_INT(DEBUG_UNCOLLECTABLE); ADD_INT(DEBUG_INSTANCES); ADD_INT(DEBUG_OBJECTS); ADD_INT(DEBUG_SAVEALL); ADD_INT(DEBUG_LEAK); #undef ADD_INT } /* API to invoke gc.collect() from C */ Py_ssize_t PyGC_Collect(void) { Py_ssize_t n; if (collecting) n = 0; /* already collecting, don't do anything */ else { collecting = 1; n = collect(NUM_GENERATIONS - 1); collecting = 0; } return n; } /* for debugging */ void _PyGC_Dump(PyGC_Head *g) { _PyObject_Dump(FROM_GC(g)); } /* extension modules might be compiled with GC support so these functions must always be available */ #undef PyObject_GC_Track #undef PyObject_GC_UnTrack #undef PyObject_GC_Del #undef _PyObject_GC_Malloc void PyObject_GC_Track(void *op) { _PyObject_GC_TRACK(op); } /* for binary compatibility with 2.2 */ void _PyObject_GC_Track(PyObject *op) { PyObject_GC_Track(op); } void PyObject_GC_UnTrack(void *op) { /* Obscure: the Py_TRASHCAN mechanism requires that we be able to * call PyObject_GC_UnTrack twice on an object. */ if (IS_TRACKED(op)) _PyObject_GC_UNTRACK(op); } /* for binary compatibility with 2.2 */ void _PyObject_GC_UnTrack(PyObject *op) { PyObject_GC_UnTrack(op); } PyObject * _PyObject_GC_Malloc(size_t basicsize) { PyObject *op; PyGC_Head *g = (PyGC_Head *)PyObject_MALLOC( sizeof(PyGC_Head) + basicsize); if (g == NULL) return PyErr_NoMemory(); g->gc.gc_refs = GC_UNTRACKED; generations[0].count++; /* number of allocated GC objects */ if (generations[0].count > generations[0].threshold && enabled && generations[0].threshold && !collecting && !PyErr_Occurred()) { collecting = 1; collect_generations(); collecting = 0; } op = FROM_GC(g); return op; } PyObject * _PyObject_GC_New(PyTypeObject *tp) { PyObject *op = _PyObject_GC_Malloc(_PyObject_SIZE(tp)); if (op != NULL) op = PyObject_INIT(op, tp); return op; } PyVarObject * _PyObject_GC_NewVar(PyTypeObject *tp, Py_ssize_t nitems) { const size_t size = _PyObject_VAR_SIZE(tp, nitems); PyVarObject *op = (PyVarObject *) _PyObject_GC_Malloc(size); if (op != NULL) op = PyObject_INIT_VAR(op, tp, nitems); return op; } PyVarObject * _PyObject_GC_Resize(PyVarObject *op, Py_ssize_t nitems) { const size_t basicsize = _PyObject_VAR_SIZE(op->ob_type, nitems); PyGC_Head *g = AS_GC(op); g = (PyGC_Head *)PyObject_REALLOC(g, sizeof(PyGC_Head) + basicsize); if (g == NULL) return (PyVarObject *)PyErr_NoMemory(); op = (PyVarObject *) FROM_GC(g); op->ob_size = nitems; return op; } void PyObject_GC_Del(void *op) { PyGC_Head *g = AS_GC(op); if (IS_TRACKED(op)) gc_list_remove(g); if (generations[0].count > 0) { generations[0].count--; } PyObject_FREE(g); } /* for binary compatibility with 2.2 */ #undef _PyObject_GC_Del void _PyObject_GC_Del(PyObject *op) { PyObject_GC_Del(op); }