Support cyclic garbage collection.

This commit is contained in:
Tom Rothamel
2024-12-26 23:56:41 -05:00
parent a535365da0
commit 2da5f4ae6a
3 changed files with 43 additions and 3 deletions
+1
View File
@@ -1,4 +1,5 @@
*.c
*.so
*.egg-info
*.html
build
+41 -2
View File
@@ -10,8 +10,8 @@ Value unions, followed by a series of byes that give the value union correspondi
"""
from libc.stdlib cimport calloc, free
from cpython.object cimport PyObject
from cpython.ref cimport Py_XINCREF, Py_XDECREF
from cpython.object cimport PyObject, PyTypeObject, traverseproc, visitproc, Py_TPFLAGS_HAVE_GC
from cpython.ref cimport Py_XINCREF, Py_XDECREF, Py_CLEAR
from sys import intern
@@ -34,6 +34,9 @@ cdef class CObject:
# This points to value_count PyObject *s, followed by index_count bytes
cdef PyObject **values
# Note: Adding any non-slot objects to this object will require tp_traverse and tp_clear to be
# changed.
def __init__(self):
cdef int i
@@ -60,6 +63,42 @@ cdef class CObject:
free(self.values)
cdef int cobject_tp_traverse(PyObject *raw, visitproc visit, void *arg) except -1:
"""
Supports cyclic garbage collection by visiting objects in slots.
"""
cdef CObject self = <CObject> raw
for i in range(self.value_count):
if self.values[i] is not NULL:
visit(<PyObject *>self.values[i], arg)
return 0
cdef int cobject_tp_clear(object raw) except -1:
"""
Supports cyclic garbage collection by clearing slots to break a cycle.
"""
cdef CObject self = raw
for i in range(self.value_count):
if self.values[i] is not NULL:
Py_CLEAR(self.values[i])
return 0
# Assign the functions to the tp_traverse and tp_clear slots of CObject.
cdef PyTypeObject *cobject = <PyTypeObject *> CObject
cobject.tp_traverse = cobject_tp_traverse
cobject.tp_clear = cobject_tp_clear
cobject.tp_flags = cobject.tp_flags | Py_TPFLAGS_HAVE_GC
cdef class Slot:
# The index of this slot inside the indexes contained by CObject.
+1 -1
View File
@@ -2,6 +2,6 @@
set -e
cython cslots.pyx
cython -a cslots.pyx
pip install -e .
python3 -m pytest