Skip to content

Commit d2f1b0e

Browse files
corona10colesbury
andauthored
gh-112087: Update list_get_item_ref to optimistically avoid locking (gh-116353)
Co-authored-by: Sam Gross <[email protected]>
1 parent 990a5f1 commit d2f1b0e

File tree

1 file changed

+60
-11
lines changed

1 file changed

+60
-11
lines changed

Diff for: Objects/listobject.c

+60-11
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,63 @@ valid_index(Py_ssize_t i, Py_ssize_t limit)
233233
return (size_t) i < (size_t) limit;
234234
}
235235

236+
#ifdef Py_GIL_DISABLED
237+
238+
static PyObject *
239+
list_item_impl(PyListObject *self, Py_ssize_t idx)
240+
{
241+
PyObject *item = NULL;
242+
Py_BEGIN_CRITICAL_SECTION(self);
243+
if (!_PyObject_GC_IS_SHARED(self)) {
244+
_PyObject_GC_SET_SHARED(self);
245+
}
246+
Py_ssize_t size = Py_SIZE(self);
247+
if (!valid_index(idx, size)) {
248+
goto exit;
249+
}
250+
item = Py_NewRef(self->ob_item[idx]);
251+
exit:
252+
Py_END_CRITICAL_SECTION();
253+
return item;
254+
}
255+
256+
static inline PyObject*
257+
list_get_item_ref(PyListObject *op, Py_ssize_t i)
258+
{
259+
if (!_Py_IsOwnedByCurrentThread((PyObject *)op) && !_PyObject_GC_IS_SHARED(op)) {
260+
return list_item_impl(op, i);
261+
}
262+
// Need atomic operation for the getting size.
263+
Py_ssize_t size = PyList_GET_SIZE(op);
264+
if (!valid_index(i, size)) {
265+
return NULL;
266+
}
267+
PyObject **ob_item = _Py_atomic_load_ptr(&op->ob_item);
268+
if (ob_item == NULL) {
269+
return NULL;
270+
}
271+
Py_ssize_t cap = _Py_atomic_load_ssize_relaxed(&op->allocated);
272+
assert(cap != -1 && cap >= size);
273+
if (!valid_index(i, cap)) {
274+
return NULL;
275+
}
276+
PyObject *item = _Py_TryXGetRef(&ob_item[i]);
277+
if (item == NULL) {
278+
return list_item_impl(op, i);
279+
}
280+
return item;
281+
}
282+
#else
283+
static inline PyObject*
284+
list_get_item_ref(PyListObject *op, Py_ssize_t i)
285+
{
286+
if (!valid_index(i, Py_SIZE(op))) {
287+
return NULL;
288+
}
289+
return Py_NewRef(PyList_GET_ITEM(op, i));
290+
}
291+
#endif
292+
236293
PyObject *
237294
PyList_GetItem(PyObject *op, Py_ssize_t i)
238295
{
@@ -255,21 +312,13 @@ PyList_GetItemRef(PyObject *op, Py_ssize_t i)
255312
PyErr_SetString(PyExc_TypeError, "expected a list");
256313
return NULL;
257314
}
258-
if (!valid_index(i, Py_SIZE(op))) {
315+
PyObject *item = list_get_item_ref((PyListObject *)op, i);
316+
if (item == NULL) {
259317
_Py_DECLARE_STR(list_err, "list index out of range");
260318
PyErr_SetObject(PyExc_IndexError, &_Py_STR(list_err));
261319
return NULL;
262320
}
263-
return Py_NewRef(PyList_GET_ITEM(op, i));
264-
}
265-
266-
static inline PyObject*
267-
list_get_item_ref(PyListObject *op, Py_ssize_t i)
268-
{
269-
if (!valid_index(i, Py_SIZE(op))) {
270-
return NULL;
271-
}
272-
return Py_NewRef(PyList_GET_ITEM(op, i));
321+
return item;
273322
}
274323

275324
int

0 commit comments

Comments
 (0)