Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ea40563

Browse files
committed
Reserved another gc_refs value for untracked objects. Every live gc
object should now have a well-defined gc_refs value, with clear transitions among gc_refs states. As a result, none of the visit_XYZ traversal callbacks need to check IS_TRACKED() anymore, and those tests were removed. (They were already looking for objects with specific gc_refs states, and the gc_refs state of an untracked object can no longer match any other gc_refs state by accident.) Added more asserts. I expect that the gc_next == NULL indicator for an untracked object is now redundant and can also be removed, but I ran out of time for this.
1 parent 7c75bf2 commit ea40563

2 files changed

Lines changed: 26 additions & 8 deletions

File tree

Include/objimpl.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,12 +262,18 @@ extern PyGC_Head *_PyGC_generation0;
262262

263263
#define _Py_AS_GC(o) ((PyGC_Head *)(o)-1)
264264

265+
#define _PyGC_REFS_UNTRACKED (-2)
266+
#define _PyGC_REFS_REACHABLE (-3)
267+
#define _PyGC_REFS_TENTATIVELY_UNREACHABLE (-4)
268+
265269
/* Tell the GC to track this object. NB: While the object is tracked the
266270
* collector it must be safe to call the ob_traverse method. */
267271
#define _PyObject_GC_TRACK(o) do { \
268272
PyGC_Head *g = _Py_AS_GC(o); \
269-
if (g->gc.gc_next != NULL) \
270-
Py_FatalError("GC object already in linked list"); \
273+
if (g->gc.gc_refs != _PyGC_REFS_UNTRACKED) \
274+
Py_FatalError("GC object already tracked"); \
275+
assert(g->gc.gc_refs == _PyGC_REFS_UNTRACKED); \
276+
g->gc.gc_refs = _PyGC_REFS_REACHABLE; \
271277
g->gc.gc_next = _PyGC_generation0; \
272278
g->gc.gc_prev = _PyGC_generation0->gc.gc_prev; \
273279
g->gc.gc_prev->gc.gc_next = g; \
@@ -277,6 +283,8 @@ extern PyGC_Head *_PyGC_generation0;
277283
/* Tell the GC to stop tracking this object. */
278284
#define _PyObject_GC_UNTRACK(o) do { \
279285
PyGC_Head *g = _Py_AS_GC(o); \
286+
assert(g->gc.gc_refs != _PyGC_REFS_UNTRACKED); \
287+
g->gc.gc_refs = _PyGC_REFS_UNTRACKED; \
280288
g->gc.gc_prev->gc.gc_next = g->gc.gc_next; \
281289
g->gc.gc_next->gc.gc_prev = g->gc.gc_prev; \
282290
g->gc.gc_next = NULL; \

Modules/gcmodule.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,9 @@ static int debug;
8282
*/
8383

8484
/* Special gc_refs values. */
85-
#define GC_REACHABLE -123
86-
#define GC_TENTATIVELY_UNREACHABLE -42
85+
#define GC_UNTRACKED _PyGC_REFS_UNTRACKED
86+
#define GC_REACHABLE _PyGC_REFS_REACHABLE
87+
#define GC_TENTATIVELY_UNREACHABLE _PyGC_REFS_TENTATIVELY_UNREACHABLE
8788

8889
#define IS_REACHABLE(o) ((AS_GC(o))->gc.gc_refs == GC_REACHABLE)
8990
#define IS_TENTATIVELY_UNREACHABLE(o) ( \
@@ -179,8 +180,10 @@ static void
179180
update_refs(PyGC_Head *containers)
180181
{
181182
PyGC_Head *gc = containers->gc.gc_next;
182-
for (; gc != containers; gc = gc->gc.gc_next)
183+
for (; gc != containers; gc = gc->gc.gc_next) {
184+
assert(gc->gc.gc_refs == GC_REACHABLE);
183185
gc->gc.gc_refs = FROM_GC(gc)->ob_refcnt;
186+
}
184187
}
185188

186189
/* A traversal callback for subtract_refs. */
@@ -222,7 +225,7 @@ subtract_refs(PyGC_Head *containers)
222225
static int
223226
visit_reachable(PyObject *op, PyGC_Head *reachable)
224227
{
225-
if (PyObject_IS_GC(op) && IS_TRACKED(op)) {
228+
if (PyObject_IS_GC(op)) {
226229
PyGC_Head *gc = AS_GC(op);
227230
const int gc_refs = gc->gc.gc_refs;
228231

@@ -250,8 +253,14 @@ visit_reachable(PyObject *op, PyGC_Head *reachable)
250253
* list, and move_unreachable will eventually get to it.
251254
* If gc_refs == GC_REACHABLE, it's either in some other
252255
* generation so we don't care about it, or move_unreachable
253-
* already dealt with it.
256+
* already deat with it.
257+
* If gc_refs == GC_UNTRACKED, it must be ignored.
254258
*/
259+
else {
260+
assert(gc_refs > 0
261+
|| gc_refs == GC_REACHABLE
262+
|| gc_refs == GC_UNTRACKED);
263+
}
255264
}
256265
return 0;
257266
}
@@ -352,7 +361,7 @@ static int
352361
visit_move(PyObject *op, PyGC_Head *tolist)
353362
{
354363
if (PyObject_IS_GC(op)) {
355-
if (IS_TRACKED(op) && IS_TENTATIVELY_UNREACHABLE(op)) {
364+
if (IS_TENTATIVELY_UNREACHABLE(op)) {
356365
PyGC_Head *gc = AS_GC(op);
357366
gc_list_remove(gc);
358367
gc_list_append(gc, tolist);
@@ -966,6 +975,7 @@ _PyObject_GC_Malloc(size_t basicsize)
966975
if (g == NULL)
967976
return PyErr_NoMemory();
968977
g->gc.gc_next = NULL;
978+
g->gc.gc_refs = GC_UNTRACKED;
969979
generations[0].count++; /* number of allocated GC objects */
970980
if (generations[0].count > generations[0].threshold &&
971981
enabled &&

0 commit comments

Comments
 (0)