Skip to content

Commit 0351844

Browse files
committed
Merge branch 'pythongh-117783-immortalize' into nogil-integration
2 parents db11b2d + 21ca2bc commit 0351844

File tree

4 files changed

+46
-0
lines changed

4 files changed

+46
-0
lines changed

Include/internal/pycore_gc.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,10 @@ struct _gc_runtime_state {
312312
collections, and are awaiting to undergo a full collection for
313313
the first time. */
314314
Py_ssize_t long_lived_pending;
315+
316+
/* True to use immortalization in places where we would normally use
317+
deferred reference counting. */
318+
int immortalize_deferred;
315319
#endif
316320
};
317321

@@ -343,6 +347,11 @@ extern void _PyGC_ClearAllFreeLists(PyInterpreterState *interp);
343347
extern void _Py_ScheduleGC(PyThreadState *tstate);
344348
extern void _Py_RunGC(PyThreadState *tstate);
345349

350+
#ifdef Py_GIL_DISABLED
351+
// gh-117783: Immortalize objects that use deferred reference counting
352+
extern void _PyGC_ImmortalizeDeferredObjects(PyInterpreterState *interp);
353+
#endif
354+
346355
#ifdef __cplusplus
347356
}
348357
#endif

Objects/object.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2427,6 +2427,12 @@ _PyObject_SetDeferredRefcount(PyObject *op)
24272427
assert(PyType_IS_GC(Py_TYPE(op)));
24282428
assert(_Py_IsOwnedByCurrentThread(op));
24292429
assert(op->ob_ref_shared == 0);
2430+
PyInterpreterState *interp = _PyInterpreterState_GET();
2431+
if (interp->gc.immortalize_deferred) {
2432+
// gh-117696:
2433+
_Py_SetImmortal(op);
2434+
return;
2435+
}
24302436
op->ob_gc_bits |= _PyGC_BITS_DEFERRED;
24312437
op->ob_ref_local += 1;
24322438
op->ob_ref_shared = _Py_REF_QUEUED;

Python/gc_free_threading.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1781,6 +1781,30 @@ custom_visitor_wrapper(const mi_heap_t *heap, const mi_heap_area_t *area,
17811781
return true;
17821782
}
17831783

1784+
// gh-117783: Immortalize objects that use deferred reference counting to
1785+
// temporarily work around scaling bottlenecks.
1786+
static bool
1787+
immortalize_visitor(const mi_heap_t *heap, const mi_heap_area_t *area,
1788+
void *block, size_t block_size, void *args)
1789+
{
1790+
PyObject *op = op_from_block(block, args, false);
1791+
if (op != NULL && _PyObject_HasDeferredRefcount(op)) {
1792+
_Py_SetImmortal(op);
1793+
op->ob_gc_bits &= ~_PyGC_BITS_DEFERRED;
1794+
}
1795+
return true;
1796+
}
1797+
1798+
void
1799+
_PyGC_ImmortalizeDeferredObjects(PyInterpreterState *interp)
1800+
{
1801+
struct visitor_args args;
1802+
_PyEval_StopTheWorld(interp);
1803+
gc_visit_heaps(interp, &immortalize_visitor, &args);
1804+
interp->gc.immortalize_deferred = 1;
1805+
_PyEval_StartTheWorld(interp);
1806+
}
1807+
17841808
void
17851809
PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void *arg)
17861810
{

Python/pystate.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1566,6 +1566,13 @@ new_threadstate(PyInterpreterState *interp, int whence)
15661566
// Must be called with lock unlocked to avoid re-entrancy deadlock.
15671567
PyMem_RawFree(new_tstate);
15681568
}
1569+
else {
1570+
#ifdef Py_GIL_DISABLED
1571+
if (!interp->gc.immortalize_deferred) {
1572+
_PyGC_ImmortalizeDeferredObjects(interp);
1573+
}
1574+
#endif
1575+
}
15691576

15701577
#ifdef Py_GIL_DISABLED
15711578
// Must be called with lock unlocked to avoid lock ordering deadlocks.

0 commit comments

Comments
 (0)