https://github.com/python/cpython/commit/d2f1b0eb4956b4923f111c7c740ba7ab25f3312d
commit: d2f1b0eb4956b4923f111c7c740ba7ab25f3312d
branch: main
author: Donghee Na <[email protected]>
committer: corona10 <[email protected]>
date: 2024-03-06T08:21:33+09:00
summary:

gh-112087: Update list_get_item_ref to optimistically avoid locking (gh-116353)


Co-authored-by: Sam Gross <[email protected]>

files:
M Objects/listobject.c

diff --git a/Objects/listobject.c b/Objects/listobject.c
index 79d61878c381bc..e013383a712bc8 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

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]

Reply via email to