mirror of https://github.com/python/cpython
gh-112087: Update list_get_item_ref to optimistically avoid locking (gh-116353)
Co-authored-by: Sam Gross <colesbury@gmail.com>
This commit is contained in:
parent
990a5f17d0
commit
d2f1b0eb49
|
@ -233,6 +233,63 @@ valid_index(Py_ssize_t i, Py_ssize_t limit)
|
||||||
return (size_t) i < (size_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 *
|
PyObject *
|
||||||
PyList_GetItem(PyObject *op, Py_ssize_t i)
|
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");
|
PyErr_SetString(PyExc_TypeError, "expected a list");
|
||||||
return NULL;
|
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");
|
_Py_DECLARE_STR(list_err, "list index out of range");
|
||||||
PyErr_SetObject(PyExc_IndexError, &_Py_STR(list_err));
|
PyErr_SetObject(PyExc_IndexError, &_Py_STR(list_err));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return Py_NewRef(PyList_GET_ITEM(op, i));
|
return item;
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
Loading…
Reference in New Issue