summaryrefslogtreecommitdiffstats
path: root/Objects/dictobject.c
diff options
context:
space:
mode:
authorSam Gross <colesbury@gmail.com>2024-02-09 22:08:32 (GMT)
committerGitHub <noreply@github.com>2024-02-09 22:08:32 (GMT)
commita3af3cb4f424034b56404704fdf8f18e8c0a9982 (patch)
tree62ee00ea8725669a67c0fb9f7d8692fedf55bbae /Objects/dictobject.c
parenta225520af941fb125a4ede77a617501dfb8b46da (diff)
downloadcpython-a3af3cb4f424034b56404704fdf8f18e8c0a9982.zip
cpython-a3af3cb4f424034b56404704fdf8f18e8c0a9982.tar.gz
cpython-a3af3cb4f424034b56404704fdf8f18e8c0a9982.tar.bz2
gh-110481: Implement inter-thread queue for biased reference counting (#114824)
Biased reference counting maintains two refcount fields in each object: `ob_ref_local` and `ob_ref_shared`. The true refcount is the sum of these two fields. In some cases, when refcounting operations are split across threads, the ob_ref_shared field can be negative (although the total refcount must be at least zero). In this case, the thread that decremented the refcount requests that the owning thread give up ownership and merge the refcount fields.
Diffstat (limited to 'Objects/dictobject.c')
-rw-r--r--Objects/dictobject.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 2df95e9..9b1defa 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -5989,6 +5989,18 @@ _PyObject_MakeDictFromInstanceAttributes(PyObject *obj, PyDictValues *values)
return make_dict_from_instance_attributes(interp, keys, values);
}
+static bool
+has_unique_reference(PyObject *op)
+{
+#ifdef Py_GIL_DISABLED
+ return (_Py_IsOwnedByCurrentThread(op) &&
+ op->ob_ref_local == 1 &&
+ _Py_atomic_load_ssize_relaxed(&op->ob_ref_shared) == 0);
+#else
+ return Py_REFCNT(op) == 1;
+#endif
+}
+
// Return true if the dict was dematerialized, false otherwise.
bool
_PyObject_MakeInstanceAttributesFromDict(PyObject *obj, PyDictOrValues *dorv)
@@ -6005,7 +6017,9 @@ _PyObject_MakeInstanceAttributesFromDict(PyObject *obj, PyDictOrValues *dorv)
return false;
}
assert(_PyType_HasFeature(Py_TYPE(obj), Py_TPFLAGS_HEAPTYPE));
- if (dict->ma_keys != CACHED_KEYS(Py_TYPE(obj)) || Py_REFCNT(dict) != 1) {
+ if (dict->ma_keys != CACHED_KEYS(Py_TYPE(obj)) ||
+ !has_unique_reference((PyObject *)dict))
+ {
return false;
}
assert(dict->ma_values);