Skip to content

Commit 296eba9

Browse files
committed
Small code cleanup.
We can remove the shutdown case disable_deferred_refcounting() call inside scan_heap_visitor() if we are careful about it. The key is that frame_disable_deferred_refcounting() might fail if the object is untracked.
1 parent 0d266cb commit 296eba9

File tree

1 file changed

+17
-25
lines changed

1 file changed

+17
-25
lines changed

Python/gc_free_threading.c

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -308,17 +308,18 @@ disable_deferred_refcounting(PyObject *op)
308308
// should also be disabled when we turn off deferred refcounting.
309309
_PyObject_DisablePerThreadRefcounting(op);
310310
}
311-
312-
// Generators and frame objects may contain deferred references to other
313-
// objects. If the pointed-to objects are part of cyclic trash, we may
314-
// have disabled deferred refcounting on them and need to ensure that we
315-
// use strong references, in case the generator or frame object is
316-
// resurrected by a finalizer.
317-
if (PyGen_CheckExact(op) || PyCoro_CheckExact(op) || PyAsyncGen_CheckExact(op)) {
318-
frame_disable_deferred_refcounting(&((PyGenObject *)op)->gi_iframe);
319-
}
320-
else if (PyFrame_Check(op)) {
321-
frame_disable_deferred_refcounting(((PyFrameObject *)op)->f_frame);
311+
if (_PyObject_GC_IS_TRACKED(op)) {
312+
// Generators and frame objects may contain deferred references to other
313+
// objects. If the pointed-to objects are part of cyclic trash, we may
314+
// have disabled deferred refcounting on them and need to ensure that we
315+
// use strong references, in case the generator or frame object is
316+
// resurrected by a finalizer.
317+
if (PyGen_CheckExact(op) || PyCoro_CheckExact(op) || PyAsyncGen_CheckExact(op)) {
318+
frame_disable_deferred_refcounting(&((PyGenObject *)op)->gi_iframe);
319+
}
320+
else if (PyFrame_Check(op)) {
321+
frame_disable_deferred_refcounting(((PyFrameObject *)op)->f_frame);
322+
}
322323
}
323324
}
324325

@@ -1240,25 +1241,16 @@ scan_heap_visitor(const mi_heap_t *heap, const mi_heap_area_t *area,
12401241
return true;
12411242
}
12421243

1243-
if (state->reason == _Py_GC_REASON_SHUTDOWN) {
1244-
// Disable deferred refcounting for reachable objects as well during
1245-
// interpreter shutdown. This ensures that these objects are collected
1246-
// immediately when their last reference is removed.
1247-
disable_deferred_refcounting(op);
1248-
}
1249-
12501244
// object is reachable, restore `ob_tid`; we're done with these objects
12511245
gc_restore_tid(op);
12521246
gc_clear_alive(op);
12531247
return true;
12541248
}
12551249

1256-
// Disables deferred refcounting for all GC objects during interpreter
1257-
// shutdown. The scan_heap_visitor() skips untracked objects but those
1258-
// could have deferred refcounts enabled as well. This is separated
1259-
// into a separate scan pass since we only need to do it at shutdown.
1260-
// Note that untracked GC objects are typically exact tuples but could
1261-
// also be GC objects that were never tracked or manually untracked.
1250+
// Disable deferred refcounting for reachable objects during interpreter
1251+
// shutdown. This ensures that these objects are collected immediately when
1252+
// their last reference is removed. This needs to consider both tracked and
1253+
// untracked GC objects, since either might have deferred refcounts enabled.
12621254
static bool
12631255
scan_heap_disable_deferred(const mi_heap_t *heap, const mi_heap_area_t *area,
12641256
void *block, size_t block_size, void *args)
@@ -1267,7 +1259,7 @@ scan_heap_disable_deferred(const mi_heap_t *heap, const mi_heap_area_t *area,
12671259
if (op == NULL) {
12681260
return true;
12691261
}
1270-
if (!_Py_IsImmortal(op) && _PyObject_HasDeferredRefcount(op)) {
1262+
if (!_Py_IsImmortal(op)) {
12711263
disable_deferred_refcounting(op);
12721264
}
12731265
return true;

0 commit comments

Comments
 (0)