aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Python/gc_free_threading.c
diff options
context:
space:
mode:
authorSam Gross <colesbury@gmail.com>2024-04-29 14:36:02 -0400
committerGitHub <noreply@github.com>2024-04-29 14:36:02 -0400
commit7ccacb220d99662b626c8bc63b00a27eaf604f0c (patch)
tree231cb901ee62e523be237392b0f2b966aa8be128 /Python/gc_free_threading.c
parent8d4b756fd31d4d91b55105b1241561e92cc571a3 (diff)
downloadcpython-7ccacb220d99662b626c8bc63b00a27eaf604f0c.tar.gz
cpython-7ccacb220d99662b626c8bc63b00a27eaf604f0c.zip
gh-117783: Immortalize objects that use deferred reference counting (#118112)
Deferred reference counting is not fully implemented yet. As a temporary measure, we immortalize objects that would use deferred reference counting to avoid multi-threaded scaling bottlenecks. This is only performed in the free-threaded build once the first non-main thread is started. Additionally, some tests, including refleak tests, suppress this behavior.
Diffstat (limited to 'Python/gc_free_threading.c')
-rw-r--r--Python/gc_free_threading.c30
1 files changed, 30 insertions, 0 deletions
diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c
index 9cf0e989d09..8c0940d8f06 100644
--- a/Python/gc_free_threading.c
+++ b/Python/gc_free_threading.c
@@ -704,6 +704,12 @@ _PyGC_Init(PyInterpreterState *interp)
{
GCState *gcstate = &interp->gc;
+ if (_Py_IsMainInterpreter(interp)) {
+ // gh-117783: immortalize objects that would use deferred refcounting
+ // once the first non-main thread is created.
+ gcstate->immortalize.enable_on_thread_created = 1;
+ }
+
gcstate->garbage = PyList_New(0);
if (gcstate->garbage == NULL) {
return _PyStatus_NO_MEMORY();
@@ -1781,6 +1787,30 @@ custom_visitor_wrapper(const mi_heap_t *heap, const mi_heap_area_t *area,
return true;
}
+// gh-117783: Immortalize objects that use deferred reference counting to
+// temporarily work around scaling bottlenecks.
+static bool
+immortalize_visitor(const mi_heap_t *heap, const mi_heap_area_t *area,
+ void *block, size_t block_size, void *args)
+{
+ PyObject *op = op_from_block(block, args, false);
+ if (op != NULL && _PyObject_HasDeferredRefcount(op)) {
+ _Py_SetImmortal(op);
+ op->ob_gc_bits &= ~_PyGC_BITS_DEFERRED;
+ }
+ return true;
+}
+
+void
+_PyGC_ImmortalizeDeferredObjects(PyInterpreterState *interp)
+{
+ struct visitor_args args;
+ _PyEval_StopTheWorld(interp);
+ gc_visit_heaps(interp, &immortalize_visitor, &args);
+ interp->gc.immortalize.enabled = 1;
+ _PyEval_StartTheWorld(interp);
+}
+
void
PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void *arg)
{