mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
gh-128844: Make _Py_TryIncref
public as an unstable API. (#128926)
This exposes `_Py_TryIncref` as `PyUnstable_TryIncref()` and the helper function `_PyObject_SetMaybeWeakref` as `PyUnstable_EnableTryIncRef`. These are helpers for dealing with unowned references in a safe way, particularly in the free threading build. Co-authored-by: Petr Viktorin <encukou@gmail.com>
This commit is contained in:
parent
7dd0a7e52e
commit
d23f5701ad
6 changed files with 160 additions and 0 deletions
|
@ -624,3 +624,84 @@ Object Protocol
|
|||
be immortal in another.
|
||||
|
||||
.. versionadded:: next
|
||||
|
||||
.. c:function:: int PyUnstable_TryIncRef(PyObject *obj)
|
||||
|
||||
Increments the reference count of *obj* if it is not zero. Returns ``1``
|
||||
if the object's reference count was successfully incremented. Otherwise,
|
||||
this function returns ``0``.
|
||||
|
||||
:c:func:`PyUnstable_EnableTryIncRef` must have been called
|
||||
earlier on *obj* or this function may spuriously return ``0`` in the
|
||||
:term:`free threading` build.
|
||||
|
||||
This function is logically equivalent to the following C code, except that
|
||||
it behaves atomically in the :term:`free threading` build::
|
||||
|
||||
if (Py_REFCNT(op) > 0) {
|
||||
Py_INCREF(op);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
This is intended as a building block for managing weak references
|
||||
without the overhead of a Python :ref:`weak reference object <weakrefobjects>`.
|
||||
|
||||
Typically, correct use of this function requires support from *obj*'s
|
||||
deallocator (:c:member:`~PyTypeObject.tp_dealloc`).
|
||||
For example, the following sketch could be adapted to implement a
|
||||
"weakmap" that works like a :py:class:`~weakref.WeakValueDictionary`
|
||||
for a specific type:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
PyMutex mutex;
|
||||
|
||||
PyObject *
|
||||
add_entry(weakmap_key_type *key, PyObject *value)
|
||||
{
|
||||
PyUnstable_EnableTryIncRef(value);
|
||||
weakmap_type weakmap = ...;
|
||||
PyMutex_Lock(&mutex);
|
||||
weakmap_add_entry(weakmap, key, value);
|
||||
PyMutex_Unlock(&mutex);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
get_value(weakmap_key_type *key)
|
||||
{
|
||||
weakmap_type weakmap = ...;
|
||||
PyMutex_Lock(&mutex);
|
||||
PyObject *result = weakmap_find(weakmap, key);
|
||||
if (PyUnstable_TryIncRef(result)) {
|
||||
// `result` is safe to use
|
||||
PyMutex_Unlock(&mutex);
|
||||
return result;
|
||||
}
|
||||
// if we get here, `result` is starting to be garbage-collected,
|
||||
// but has not been removed from the weakmap yet
|
||||
PyMutex_Unlock(&mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// tp_dealloc function for weakmap values
|
||||
void
|
||||
value_dealloc(PyObject *value)
|
||||
{
|
||||
weakmap_type weakmap = ...;
|
||||
PyMutex_Lock(&mutex);
|
||||
weakmap_remove_value(weakmap, value);
|
||||
|
||||
...
|
||||
PyMutex_Unlock(&mutex);
|
||||
}
|
||||
|
||||
.. versionadded:: 3.14
|
||||
|
||||
.. c:function:: void PyUnstable_EnableTryIncRef(PyObject *obj)
|
||||
|
||||
Enables subsequent uses of :c:func:`PyUnstable_TryIncRef` on *obj*. The
|
||||
caller must hold a :term:`strong reference` to *obj* when calling this.
|
||||
|
||||
.. versionadded:: 3.14
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue