summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorDonghee Na <donghee.na@python.org>2024-03-05 23:21:33 (GMT)
committerGitHub <noreply@github.com>2024-03-05 23:21:33 (GMT)
commitd2f1b0eb4956b4923f111c7c740ba7ab25f3312d (patch)
treefa3a452a9e99fa6aa07ea95da64aef0c3b1e5667 /Objects
parent990a5f17d05214abe8aafedf8e6418a0fb5ffd50 (diff)
downloadcpython-d2f1b0eb4956b4923f111c7c740ba7ab25f3312d.zip
cpython-d2f1b0eb4956b4923f111c7c740ba7ab25f3312d.tar.gz
cpython-d2f1b0eb4956b4923f111c7c740ba7ab25f3312d.tar.bz2
gh-112087: Update list_get_item_ref to optimistically avoid locking (gh-116353)
Co-authored-by: Sam Gross <colesbury@gmail.com>
Diffstat (limited to 'Objects')
-rw-r--r--Objects/listobject.c71
1 files changed, 60 insertions, 11 deletions
diff --git a/Objects/listobject.c b/Objects/listobject.c
index 79d6187..e013383 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -233,6 +233,63 @@ valid_index(Py_ssize_t i, Py_ssize_t limit)
return (size_t) i < (size_t) limit;
}
+#ifdef Py_GIL_DISABLED
+
+static PyObject *
+list_item_impl(PyListObject *self, Py_ssize_t idx)
+{
+ PyObject *item = NULL;
+ Py_BEGIN_CRITICAL_SECTION(self);
+ if (!_PyObject_GC_IS_SHARED(self)) {
+ _PyObject_GC_SET_SHARED(self);
+ }
+ Py_ssize_t size = Py_SIZE(self);
+ if (!valid_index(idx, size)) {
+ goto exit;
+ }
+ item = Py_NewRef(self->ob_item[idx]);
+exit:
+ Py_END_CRITICAL_SECTION();
+ return item;
+}
+
+static inline PyObject*
+list_get_item_ref(PyListObject *op, Py_ssize_t i)
+{
+ if (!_Py_IsOwnedByCurrentThread((PyObject *)op) && !_PyObject_GC_IS_SHARED(op)) {
+ return list_item_impl(op, i);
+ }
+ // Need atomic operation for the getting size.
+ Py_ssize_t size = PyList_GET_SIZE(op);
+ if (!valid_index(i, size)) {
+ return NULL;
+ }
+ PyObject **ob_item = _Py_atomic_load_ptr(&op->ob_item);
+ if (ob_item == NULL) {
+ return NULL;
+ }
+ Py_ssize_t cap = _Py_atomic_load_ssize_relaxed(&op->allocated);
+ assert(cap != -1 && cap >= size);
+ if (!valid_index(i, cap)) {
+ return NULL;
+ }
+ PyObject *item = _Py_TryXGetRef(&ob_item[i]);
+ if (item == NULL) {
+ return list_item_impl(op, i);
+ }
+ return item;
+}
+#else
+static inline PyObject*
+list_get_item_ref(PyListObject *op, Py_ssize_t i)
+{
+ if (!valid_index(i, Py_SIZE(op))) {
+ return NULL;
+ }
+ return Py_NewRef(PyList_GET_ITEM(op, i));
+}
+#endif
+
PyObject *
PyList_GetItem(PyObject *op, Py_ssize_t i)
{
@@ -255,21 +312,13 @@ PyList_GetItemRef(PyObject *op, Py_ssize_t i)
PyErr_SetString(PyExc_TypeError, "expected a list");
return NULL;
}
- if (!valid_index(i, Py_SIZE(op))) {
+ PyObject *item = list_get_item_ref((PyListObject *)op, i);
+ if (item == NULL) {
_Py_DECLARE_STR(list_err, "list index out of range");
PyErr_SetObject(PyExc_IndexError, &_Py_STR(list_err));
return NULL;
}
- return Py_NewRef(PyList_GET_ITEM(op, i));
-}
-
-static inline PyObject*
-list_get_item_ref(PyListObject *op, Py_ssize_t i)
-{
- if (!valid_index(i, Py_SIZE(op))) {
- return NULL;
- }
- return Py_NewRef(PyList_GET_ITEM(op, i));
+ return item;
}
int