Make _Py_TryIncref
public as an unstable API as PyUnstable_Object_TryIncref()
#128844
Labels
_Py_TryIncref
public as an unstable API as PyUnstable_Object_TryIncref()
#128844
Feature or enhancement
We should make
_Py_TryIncref
public as function with the following signature:The function increments the reference count if it's not zero in a thread-safe way. It's logically equivalent to the following snippet and in the default (GIL-enabled) build it's implemented as such:
Additionally, we should make
_PyObject_SetMaybeWeakref
public asPyUnstable_Object_EnableTryIncRef
. This function has no equivalent in the GIL-enabled build (it's a no-op), but it's important for makingTryIncref
work reliably with our biased reference counting implementation.Motivation
The
TryIncref
primitive is a building block for handling borrowed and unowned references. It addresses an issue that generally cannot be solved by adding extra synchronization like mutexes because it handles the race between the reference count reaching zero (which is outside developers' control) and theTryIncref
.We use it internally in three subsystems:
PyObject *
entries.Recently, we discovered a thread safety bug in pybind11 related to the use of borrowed/unowned references. Using
_Py_TryIncref
in place ofPy_INCREF
would fix the bug. I think nanobind probably has a similar issue.Alternatives
PyWeakRef
objects increases the overhead of pybind11 bindings by 30% in some simple tests._Py_TryIncref
in extensions. I think this is much worse than making the function public as an unstable API because it requires direct access to the reference count fields -- the implementation is tied to the implementation of biased reference counting -- and I'd like to avoid extensions depending directly on those details.See also
Py_INCREF
for the free-threaded build #113920The text was updated successfully, but these errors were encountered: