mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +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.
|
caller must hold a :term:`strong reference` to *obj* when calling this.
|
||||||
|
|
||||||
.. versionadded:: 3.14
|
.. 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,6 +23,13 @@ of Python objects.
|
||||||
|
|
||||||
Use the :c:func:`Py_SET_REFCNT()` function to set an object reference count.
|
Use the :c:func:`Py_SET_REFCNT()` function to set an object reference count.
|
||||||
|
|
||||||
|
.. 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()`.
|
See also the function :c:func:`PyUnstable_Object_IsUniqueReferencedTemporary()`.
|
||||||
|
|
||||||
.. versionchanged:: 3.10
|
.. versionchanged:: 3.10
|
||||||
|
|
|
@ -2469,6 +2469,10 @@ New features
|
||||||
be used in some cases as a replacement for checking if :c:func:`Py_REFCNT`
|
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.
|
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
|
Limited C API changes
|
||||||
---------------------
|
---------------------
|
||||||
|
|
|
@ -501,3 +501,5 @@ PyAPI_FUNC(int) PyUnstable_IsImmortal(PyObject *);
|
||||||
// before calling this function in order to avoid spurious failures.
|
// before calling this function in order to avoid spurious failures.
|
||||||
PyAPI_FUNC(int) PyUnstable_TryIncRef(PyObject *);
|
PyAPI_FUNC(int) PyUnstable_TryIncRef(PyObject *);
|
||||||
PyAPI_FUNC(void) PyUnstable_EnableTryIncRef(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))
|
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):
|
class CAPITest(unittest.TestCase):
|
||||||
def check_negative_refcount(self, code):
|
def check_negative_refcount(self, code):
|
||||||
# bpo-35059: Check that Py_DECREF() reports the correct filename
|
# 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[] = {
|
static PyMethodDef test_methods[] = {
|
||||||
{"call_pyobject_print", call_pyobject_print, METH_VARARGS},
|
{"call_pyobject_print", call_pyobject_print, METH_VARARGS},
|
||||||
{"pyobject_print_null", pyobject_print_null, 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_macros", test_py_is_macros, METH_NOARGS},
|
||||||
{"test_py_is_funcs", test_py_is_funcs, METH_NOARGS},
|
{"test_py_is_funcs", test_py_is_funcs, METH_NOARGS},
|
||||||
{"clear_managed_dict", clear_managed_dict, METH_O, NULL},
|
{"clear_managed_dict", clear_managed_dict, METH_O, NULL},
|
||||||
|
{"is_uniquely_referenced", is_uniquely_referenced, METH_O},
|
||||||
{NULL},
|
{NULL},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3275,3 +3275,11 @@ PyUnstable_IsImmortal(PyObject *op)
|
||||||
assert(op != NULL);
|
assert(op != NULL);
|
||||||
return _Py_IsImmortal(op);
|
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