static PyObject * gc_get_referents(PyObject *self, PyObject *args) { int 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; }
/* Add op to the _PyTrash_delete_later list. Called when the current * call-stack depth gets large. op must be a currently untracked gc'ed * object, with refcount 0. Py_DECREF must already have been called on it. */ void _PyTrash_deposit_object(PyObject *op) { assert(PyObject_IS_GC(op)); assert(_Py_AS_GC(op)->gc.gc_refs == _PyGC_REFS_UNTRACKED); assert(op->ob_refcnt == 0); _Py_AS_GC(op)->gc.gc_prev = (PyGC_Head *)_PyTrash_delete_later; _PyTrash_delete_later = op; }
/* A traversal callback for move_finalizer_reachable. */ static int visit_move(PyObject *op, PyGC_Head *tolist) { if (PyObject_IS_GC(op)) { if (IS_TENTATIVELY_UNREACHABLE(op)) { PyGC_Head *gc = AS_GC(op); gc_list_move(gc, tolist); gc->gc.gc_refs = GC_REACHABLE; } } return 0; }
static void green_dealloc(PyGreenlet* self) { PyObject_GC_UnTrack((PyObject *)self); if (PyObject_IS_GC((PyObject *)self)) { Py_TRASHCAN_SAFE_BEGIN(self); green_dealloc_safe(self); Py_TRASHCAN_SAFE_END(self); } else { /* This object cannot be garbage collected, so trashcan is not allowed */ green_dealloc_safe(self); } }
static PyObject * gc_is_tracked(PyObject *self, PyObject *obj) { PyObject *result; if (PyObject_IS_GC(obj) && IS_TRACKED(obj)) result = Py_True; else result = Py_False; Py_INCREF(result); return result; }
/* A traversal callback for subtract_refs. */ static int visit_decref(PyObject *op, void *data) { assert(op != NULL); if (PyObject_IS_GC(op)) { PyGC_Head *gc = AS_GC(op); /* We're only interested in gc_refs for objects in the * generation being collected, which can be recognized * because only they have positive gc_refs. */ assert(gc->gc.gc_refs != 0); /* else refcount was too small */ if (gc->gc.gc_refs > 0) gc->gc.gc_refs--; } return 0; }
size_t _PySys_GetSizeOf(PyObject* o) { static PyObject* str__sizeof__ = NULL; PyObject* res = NULL; Py_ssize_t size; /* Make sure the type is initialized. float gets initialized late */ if (PyType_Ready(Py_TYPE(o)) < 0) return (size_t)-1; /* Instance of old-style class */ if (PyInstance_Check(o)) size = PyInstance_Type.tp_basicsize; /* all other objects */ else { PyObject* method = _PyObject_LookupSpecial(o, "__sizeof__", &str__sizeof__); if (method == NULL) { if (!PyErr_Occurred()) PyErr_Format(PyExc_TypeError, "Type %.100s doesn't define __sizeof__", Py_TYPE(o)->tp_name); } else { res = PyObject_CallFunctionObjArgs(method, NULL); Py_DECREF(method); } if (res == NULL) return (size_t)-1; size = (size_t)PyInt_AsSsize_t(res); Py_DECREF(res); if (size == -1 && PyErr_Occurred()) return (size_t)-1; } if (size < 0) { PyErr_SetString(PyExc_ValueError, "__sizeof__() should return >= 0"); return (size_t)-1; } /* add gc_head size */ if (PyObject_IS_GC(o)) return ((size_t)size) + sizeof(PyGC_Head); return (size_t)size; }
/* A traversal callback for move_unreachable. */ static int visit_reachable(PyObject *op, PyGC_Head *reachable) { if (PyObject_IS_GC(op)) { PyGC_Head *gc = AS_GC(op); const int gc_refs = gc->gc.gc_refs; if (gc_refs == 0) { /* This is in move_unreachable's 'young' list, but * the traversal hasn't yet gotten to it. All * we need to do is tell move_unreachable that it's * reachable. */ gc->gc.gc_refs = 1; } else if (gc_refs == GC_TENTATIVELY_UNREACHABLE) { /* This had gc_refs = 0 when move_unreachable got * to it, but turns out it's reachable after all. * Move it back to move_unreachable's 'young' list, * and move_unreachable will eventually get to it * again. */ gc_list_move(gc, reachable); gc->gc.gc_refs = 1; } /* Else there's nothing to do. * If gc_refs > 0, it must be in move_unreachable's 'young' * list, and move_unreachable will eventually get to it. * 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. */ else { assert(gc_refs > 0 || gc_refs == GC_REACHABLE || gc_refs == GC_UNTRACKED); } } return 0; }
/* For debugging convenience. */ void _Node_Dump(char *msg, NodeObject *self) { fprintf(stderr, "%s\n" " node : ", msg); if (self == NULL) { fprintf(stderr, "NULL\n"); } else { PyObject_Print((PyObject *) self, stderr, 0); fprintf(stderr, "\n" " type : %s\n" " refcount: %" PY_FORMAT_SIZE_T "d\n" " GC refs: %" PY_FORMAT_SIZE_T "d\n" " parent : %p\n", self->ob_type == NULL ? "NULL" : self->ob_type->tp_name, self->ob_refcnt, PyObject_IS_GC((PyObject *)self) ? _Py_AS_GC(self)->gc.gc_refs : 0, Node_GET_PARENT(self)); if (Container_Check(self)) { fprintf(stderr, " children: %" PY_FORMAT_SIZE_T "d\n", Container_GET_COUNT(self)); } } fprintf(stderr, "----------------------\n"); }