Skip to content

Commit 5916897

Browse files
committed
More list
1 parent 9ac81d7 commit 5916897

File tree

3 files changed

+54
-7
lines changed

3 files changed

+54
-7
lines changed

Include/internal/pycore_list.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,11 @@ _PyList_AppendTakeRef(PyListObject *self, PyObject *newitem)
2828
Py_ssize_t allocated = self->allocated;
2929
assert((size_t)len + 1 < PY_SSIZE_T_MAX);
3030
if (allocated > len) {
31+
#ifdef Py_GIL_DISABLED
32+
_Py_atomic_store_ptr_release(&self->ob_item[len], newitem);
33+
#else
3134
PyList_SET_ITEM(self, len, newitem);
35+
#endif
3236
Py_SET_SIZE(self, len + 1);
3337
return 0;
3438
}

Lib/test/test_free_threading/test_list.py

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,27 @@
33
from threading import Thread
44
from unittest import TestCase
55

6+
7+
class C:
8+
def __init__(self, v):
9+
self.v = v
10+
11+
612
class TestList(TestCase):
713
def test_racing_iter_append(self):
814

915
l = []
1016
OBJECT_COUNT = 10000
17+
1118
def writer_func():
1219
for i in range(OBJECT_COUNT):
13-
l.append(i + OBJECT_COUNT)
20+
l.append(C(i + OBJECT_COUNT))
1421

1522
def reader_func():
1623
while True:
1724
count = len(l)
1825
for i, x in enumerate(l):
19-
self.assertEqual(x, i + OBJECT_COUNT)
26+
self.assertEqual(x.v, i + OBJECT_COUNT)
2027
if count == OBJECT_COUNT:
2128
break
2229

@@ -29,10 +36,42 @@ def reader_func():
2936

3037
writer.start()
3138
writer.join()
32-
print('writer done')
3339
for reader in readers:
3440
reader.join()
35-
print('reader done')
41+
42+
def test_racing_iter_extend(self):
43+
iters = [
44+
lambda x: [x],
45+
]
46+
for iter_case in iters:
47+
with self.subTest(iter=iter_case):
48+
l = []
49+
OBJECT_COUNT = 10000
50+
51+
def writer_func():
52+
for i in range(OBJECT_COUNT):
53+
l.extend(iter_case(C(i + OBJECT_COUNT)))
54+
55+
def reader_func():
56+
while True:
57+
count = len(l)
58+
for i, x in enumerate(l):
59+
self.assertEqual(x.v, i + OBJECT_COUNT)
60+
if count == OBJECT_COUNT:
61+
break
62+
63+
writer = Thread(target=writer_func)
64+
readers = []
65+
for x in range(30):
66+
reader = Thread(target=reader_func)
67+
readers.append(reader)
68+
reader.start()
69+
70+
writer.start()
71+
writer.join()
72+
for reader in readers:
73+
reader.join()
74+
3675

3776
if __name__ == "__main__":
3877
unittest.main()

Objects/listobject.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ list_allocate_array(size_t capacity)
4545
if (capacity > PY_SSIZE_T_MAX/sizeof(PyObject*) - 1) {
4646
return NULL;
4747
}
48+
4849
_PyListArray *array = PyMem_Malloc(sizeof(_PyListArray) + capacity * sizeof(PyObject *));
4950
if (array == NULL) {
5051
return NULL;
@@ -141,6 +142,9 @@ list_resize(PyListObject *self, Py_ssize_t newsize)
141142
target_bytes = allocated * sizeof(PyObject*);
142143
}
143144
memcpy(array->ob_item, self->ob_item, target_bytes);
145+
}
146+
if (new_allocated > (size_t)allocated) {
147+
memset(array->ob_item + allocated, 0, sizeof(PyObject *) * (new_allocated - allocated));
144148
}
145149
_Py_atomic_store_ptr_release(&self->ob_item, &array->ob_item);
146150
self->allocated = new_allocated;
@@ -502,7 +506,7 @@ _PyList_AppendTakeRefListResize(PyListObject *self, PyObject *newitem)
502506
Py_DECREF(newitem);
503507
return -1;
504508
}
505-
PyList_SET_ITEM(self, len, newitem);
509+
FT_ATOMIC_STORE_PTR_RELEASE(self->ob_item[len], newitem);
506510
return 0;
507511
}
508512

@@ -1181,7 +1185,7 @@ list_extend_fast(PyListObject *self, PyObject *iterable)
11811185
PyObject **dest = self->ob_item + m;
11821186
for (Py_ssize_t i = 0; i < n; i++) {
11831187
PyObject *o = src[i];
1184-
dest[i] = Py_NewRef(o);
1188+
FT_ATOMIC_STORE_PTR_RELEASE(dest[i], Py_NewRef(o));
11851189
}
11861190
return 0;
11871191
}
@@ -1238,7 +1242,7 @@ list_extend_iter_lock_held(PyListObject *self, PyObject *iterable)
12381242

12391243
if (Py_SIZE(self) < self->allocated) {
12401244
Py_ssize_t len = Py_SIZE(self);
1241-
PyList_SET_ITEM(self, len, item); // steals item ref
1245+
FT_ATOMIC_STORE_PTR_RELEASE(self->ob_item[len], item);
12421246
Py_SET_SIZE(self, len + 1);
12431247
}
12441248
else {

0 commit comments

Comments
 (0)