mirror of
https://github.com/python/cpython.git
synced 2025-07-07 19:35:27 +00:00
gh-133140: Add PyUnstable_Object_IsUniquelyReferenced
for free-threading (#133144)
This commit is contained in:
parent
0eeaa0ef8b
commit
b275b8f342
8 changed files with 61 additions and 1 deletions
|
@ -737,3 +737,21 @@ Object Protocol
|
|||
caller must hold a :term:`strong reference` to *obj* when calling this.
|
||||
|
||||
.. versionadded:: 3.14
|
||||
|
||||
.. c:function:: int PyUnstable_Object_IsUniquelyReferenced(PyObject *op)
|
||||
|
||||
Determine if *op* only has one reference.
|
||||
|
||||
On GIL-enabled builds, this function is equivalent to
|
||||
:c:expr:`Py_REFCNT(op) == 1`.
|
||||
|
||||
On a :term:`free threaded <free threading>` build, this checks if *op*'s
|
||||
:term:`reference count` is equal to one and additionally checks if *op*
|
||||
is only used by this thread. :c:expr:`Py_REFCNT(op) == 1` is **not**
|
||||
thread-safe on free threaded builds; prefer this function.
|
||||
|
||||
The caller must hold an :term:`attached thread state`, despite the fact
|
||||
that this function doesn't call into the Python interpreter. This function
|
||||
cannot fail.
|
||||
|
||||
.. versionadded:: 3.14
|
||||
|
|
|
@ -23,7 +23,14 @@ of Python objects.
|
|||
|
||||
Use the :c:func:`Py_SET_REFCNT()` function to set an object reference count.
|
||||
|
||||
See also the function :c:func:`PyUnstable_Object_IsUniqueReferencedTemporary()`.
|
||||
.. note::
|
||||
|
||||
On :term:`free threaded <free threading>` builds of Python, returning 1
|
||||
isn't sufficient to determine if it's safe to treat *o* as having no
|
||||
access by other threads. Use :c:func:`PyUnstable_Object_IsUniquelyReferenced`
|
||||
for that instead.
|
||||
|
||||
See also the function :c:func:`PyUnstable_Object_IsUniqueReferencedTemporary()`.
|
||||
|
||||
.. versionchanged:: 3.10
|
||||
:c:func:`Py_REFCNT()` is changed to the inline static function.
|
||||
|
|
|
@ -2469,6 +2469,10 @@ New features
|
|||
be used in some cases as a replacement for checking if :c:func:`Py_REFCNT`
|
||||
is ``1`` for Python objects passed as arguments to C API functions.
|
||||
|
||||
* Add :c:func:`PyUnstable_Object_IsUniquelyReferenced` as a replacement for
|
||||
``Py_REFCNT(op) == 1`` on :term:`free threaded <free threading>` builds.
|
||||
(Contributed by Peter Bierma in :gh:`133140`.)
|
||||
|
||||
|
||||
Limited C API changes
|
||||
---------------------
|
||||
|
|
|
@ -501,3 +501,5 @@ PyAPI_FUNC(int) PyUnstable_IsImmortal(PyObject *);
|
|||
// before calling this function in order to avoid spurious failures.
|
||||
PyAPI_FUNC(int) PyUnstable_TryIncRef(PyObject *);
|
||||
PyAPI_FUNC(void) PyUnstable_EnableTryIncRef(PyObject *);
|
||||
|
||||
PyAPI_FUNC(int) PyUnstable_Object_IsUniquelyReferenced(PyObject *);
|
||||
|
|
|
@ -174,6 +174,16 @@ class EnableDeferredRefcountingTest(unittest.TestCase):
|
|||
self.assertTrue(_testinternalcapi.has_deferred_refcount(silly_list))
|
||||
|
||||
|
||||
class IsUniquelyReferencedTest(unittest.TestCase):
|
||||
"""Test PyUnstable_Object_IsUniquelyReferenced"""
|
||||
def test_is_uniquely_referenced(self):
|
||||
self.assertTrue(_testcapi.is_uniquely_referenced(object()))
|
||||
self.assertTrue(_testcapi.is_uniquely_referenced([]))
|
||||
# Immortals
|
||||
self.assertFalse(_testcapi.is_uniquely_referenced("spanish inquisition"))
|
||||
self.assertFalse(_testcapi.is_uniquely_referenced(42))
|
||||
# CRASHES is_uniquely_referenced(NULL)
|
||||
|
||||
class CAPITest(unittest.TestCase):
|
||||
def check_negative_refcount(self, code):
|
||||
# bpo-35059: Check that Py_DECREF() reports the correct filename
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
Add :c:func:`PyUnstable_Object_IsUniquelyReferenced` as a replacement for
|
||||
``Py_REFNCT(op) == 1`` on :term:`free threaded <free threading>`
|
||||
builds of Python.
|
|
@ -478,6 +478,13 @@ clear_managed_dict(PyObject *self, PyObject *obj)
|
|||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
is_uniquely_referenced(PyObject *self, PyObject *op)
|
||||
{
|
||||
return PyBool_FromLong(PyUnstable_Object_IsUniquelyReferenced(op));
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef test_methods[] = {
|
||||
{"call_pyobject_print", call_pyobject_print, METH_VARARGS},
|
||||
{"pyobject_print_null", pyobject_print_null, METH_VARARGS},
|
||||
|
@ -503,6 +510,7 @@ static PyMethodDef test_methods[] = {
|
|||
{"test_py_is_macros", test_py_is_macros, METH_NOARGS},
|
||||
{"test_py_is_funcs", test_py_is_funcs, METH_NOARGS},
|
||||
{"clear_managed_dict", clear_managed_dict, METH_O, NULL},
|
||||
{"is_uniquely_referenced", is_uniquely_referenced, METH_O},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
|
|
|
@ -3275,3 +3275,11 @@ PyUnstable_IsImmortal(PyObject *op)
|
|||
assert(op != NULL);
|
||||
return _Py_IsImmortal(op);
|
||||
}
|
||||
|
||||
int
|
||||
PyUnstable_Object_IsUniquelyReferenced(PyObject *op)
|
||||
{
|
||||
_Py_AssertHoldsTstate();
|
||||
assert(op != NULL);
|
||||
return _PyObject_IsUniquelyReferenced(op);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue