Skip to content

Commit 9b04072

Browse files
committed
fully implement GC protocol for _functools._lru_list_elem
1 parent 2a54acf commit 9b04072

File tree

1 file changed

+36
-12
lines changed

1 file changed

+36
-12
lines changed

Modules/_functoolsmodule.c

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,27 +1161,51 @@ typedef struct lru_list_elem {
11611161

11621162
#define lru_list_elem_CAST(op) ((lru_list_elem *)(op))
11631163

1164+
static int
1165+
lru_list_elem_clear(PyObject *op)
1166+
{
1167+
lru_list_elem *link = lru_list_elem_CAST(op);
1168+
Py_CLEAR(link->key);
1169+
Py_CLEAR(link->result);
1170+
return 0;
1171+
}
1172+
11641173
static void
11651174
lru_list_elem_dealloc(PyObject *op)
11661175
{
1167-
lru_list_elem *link = lru_list_elem_CAST(op);
1168-
PyTypeObject *tp = Py_TYPE(link);
1169-
Py_XDECREF(link->key);
1170-
Py_XDECREF(link->result);
1171-
tp->tp_free(link);
1176+
PyTypeObject *tp = Py_TYPE(op);
1177+
PyObject_GC_UnTrack(op);
1178+
(void)lru_list_elem_clear(op);
1179+
tp->tp_free(op);
11721180
Py_DECREF(tp);
11731181
}
11741182

1183+
static int
1184+
lru_list_elem_traverse(PyObject *op, visitproc visit, void *arg)
1185+
{
1186+
lru_list_elem *self = lru_list_elem_CAST(op);
1187+
Py_VISIT(Py_TYPE(op));
1188+
Py_VISIT(self->key);
1189+
Py_VISIT(self->result);
1190+
return 0;
1191+
}
1192+
11751193
static PyType_Slot lru_list_elem_type_slots[] = {
1194+
{Py_tp_clear, lru_list_elem_clear},
11761195
{Py_tp_dealloc, lru_list_elem_dealloc},
1196+
{Py_tp_traverse, lru_list_elem_traverse},
11771197
{0, 0}
11781198
};
11791199

11801200
static PyType_Spec lru_list_elem_type_spec = {
11811201
.name = "functools._lru_list_elem",
11821202
.basicsize = sizeof(lru_list_elem),
1183-
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
1184-
Py_TPFLAGS_IMMUTABLETYPE,
1203+
.flags = (
1204+
Py_TPFLAGS_DEFAULT
1205+
| Py_TPFLAGS_DISALLOW_INSTANTIATION
1206+
| Py_TPFLAGS_IMMUTABLETYPE
1207+
| Py_TPFLAGS_HAVE_GC
1208+
),
11851209
.slots = lru_list_elem_type_slots
11861210
};
11871211

@@ -1454,8 +1478,10 @@ bounded_lru_cache_update_lock_held(lru_cache_object *self,
14541478
self->root.next == &self->root)
14551479
{
14561480
/* Cache is not full, so put the result in a new link */
1457-
link = (lru_list_elem *)PyObject_New(lru_list_elem,
1458-
self->lru_list_elem_type);
1481+
PyTypeObject *type = self->lru_list_elem_type;
1482+
assert(type != NULL);
1483+
assert(type->tp_alloc != NULL);
1484+
link = (lru_list_elem *)type->tp_alloc(type, 0);
14591485
if (link == NULL) {
14601486
Py_DECREF(key);
14611487
Py_DECREF(result);
@@ -1811,9 +1837,7 @@ lru_cache_tp_traverse(PyObject *op, visitproc visit, void *arg)
18111837
lru_list_elem *link = self->root.next;
18121838
while (link != &self->root) {
18131839
lru_list_elem *next = link->next;
1814-
Py_VISIT(link->key);
1815-
Py_VISIT(link->result);
1816-
Py_VISIT(Py_TYPE(link));
1840+
Py_VISIT(link);
18171841
link = next;
18181842
}
18191843
Py_VISIT(self->cache);

0 commit comments

Comments
 (0)