Skip to content

Commit 3222eef

Browse files
committed
Address comments
1 parent 6ac15e0 commit 3222eef

File tree

2 files changed

+65
-55
lines changed

2 files changed

+65
-55
lines changed

Lib/test/test_free_threading/test_set.py

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -168,10 +168,14 @@ def writer():
168168
s.discard(i - 1)
169169
i += 1
170170

171-
t1 = Thread(target=reader)
172-
t2 = Thread(target=writer)
173-
t1.start(); t2.start()
174-
t1.join(); t2.join()
171+
threads = [
172+
Thread(target=reader),
173+
Thread(target=writer),
174+
]
175+
for t in threads:
176+
t.start()
177+
for t in threads:
178+
t.join()
175179

176180
def test_length_hint_exhaust_race(self):
177181
NUM_LOOPS = 10_000
@@ -199,10 +203,14 @@ def reader():
199203
it.__length_hint__()
200204
barrier.wait()
201205

202-
t1 = Thread(target=reader)
203-
t2 = Thread(target=exhauster)
204-
t1.start(); t2.start()
205-
t1.join(); t2.join()
206+
threads = [
207+
Thread(target=reader),
208+
Thread(target=exhauster),
209+
]
210+
for t in threads:
211+
t.start()
212+
for t in threads:
213+
t.join()
206214

207215
def test_iternext_concurrent_exhaust_race(self):
208216
NUM_LOOPS = 20_000
@@ -227,11 +235,15 @@ def producer():
227235
barrier.wait()
228236
barrier.wait()
229237

230-
t1 = Thread(target=advancer)
231-
t2 = Thread(target=advancer)
232-
t3 = Thread(target=producer)
233-
t1.start(); t2.start(); t3.start()
234-
t1.join(); t2.join(); t3.join()
238+
threads = [
239+
Thread(target=advancer),
240+
Thread(target=advancer),
241+
Thread(target=producer),
242+
]
243+
for t in threads:
244+
t.start()
245+
for t in threads:
246+
t.join()
235247

236248

237249
@threading_helper.requires_working_threading()

Objects/setobject.c

Lines changed: 40 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,23 +1056,24 @@ setiter_len(PyObject *op, PyObject *Py_UNUSED(ignored))
10561056
{
10571057
setiterobject *si = (setiterobject*)op;
10581058
Py_ssize_t len = 0;
1059+
10591060
#ifdef Py_GIL_DISABLED
10601061
PySetObject *so = si->si_set;
10611062
if (so != NULL) {
1062-
Py_BEGIN_CRITICAL_SECTION(so);
1063-
Py_ssize_t pos = FT_ATOMIC_LOAD_SSIZE_RELAXED(si->si_pos);
1064-
if (pos >= 0 &&
1063+
Py_BEGIN_CRITICAL_SECTION2(op, so);
1064+
if (si->si_pos >= 0 &&
10651065
si->si_used == FT_ATOMIC_LOAD_SSIZE_RELAXED(so->used))
10661066
{
10671067
len = si->len;
10681068
}
1069-
Py_END_CRITICAL_SECTION();
1069+
Py_END_CRITICAL_SECTION2();
10701070
}
10711071
#else
10721072
if (si->si_set != NULL && si->si_used == si->si_set->used) {
10731073
len = si->len;
10741074
}
10751075
#endif
1076+
10761077
return PyLong_FromSsize_t(len);
10771078
}
10781079

@@ -1104,18 +1105,22 @@ static PyMethodDef setiter_methods[] = {
11041105
{NULL, NULL} /* sentinel */
11051106
};
11061107

1107-
static PyObject *setiter_iternext(PyObject *self)
1108+
static PyObject *
1109+
setiter_iternext(PyObject *self)
11081110
{
11091111
setiterobject *si = (setiterobject*)self;
11101112
PyObject *key = NULL;
11111113
Py_ssize_t i, mask;
11121114
setentry *entry;
11131115
PySetObject *so = si->si_set;
1114-
int exhausted = 0;
1116+
#ifndef Py_GIL_DISABLED
1117+
int decref_so = 0;
1118+
#endif
11151119

1116-
if (so == NULL)
1120+
if (so == NULL) {
11171121
return NULL;
1118-
assert (PyAnySet_Check(so));
1122+
}
1123+
assert(PyAnySet_Check(so));
11191124

11201125
Py_ssize_t so_used = FT_ATOMIC_LOAD_SSIZE_RELAXED(so->used);
11211126
Py_ssize_t si_used = FT_ATOMIC_LOAD_SSIZE_RELAXED(si->si_used);
@@ -1126,61 +1131,54 @@ static PyObject *setiter_iternext(PyObject *self)
11261131
return NULL;
11271132
}
11281133

1129-
Py_BEGIN_CRITICAL_SECTION(so);
11301134
#ifdef Py_GIL_DISABLED
1131-
/* si_pos may be read outside the lock; keep it atomic in FT builds */
1132-
i = FT_ATOMIC_LOAD_SSIZE_RELAXED(si->si_pos);
1133-
if (i < 0) {
1134-
/* iterator already exhausted */
1135-
goto done;
1136-
}
1137-
#else
1135+
Py_BEGIN_CRITICAL_SECTION2(self, so);
11381136
i = si->si_pos;
1139-
if (i < 0) {
1140-
/* iterator already exhausted */
1141-
exhausted = 1;
1142-
}
1143-
#endif
1144-
1145-
if (!exhausted) {
1146-
assert(i >= 0);
1137+
if (i >= 0) {
11471138
entry = so->table;
11481139
mask = so->mask;
1149-
while (i <= mask && (entry[i].key == NULL || entry[i].key == dummy)) {
1140+
while (i <= mask &&
1141+
(entry[i].key == NULL || entry[i].key == dummy)) {
11501142
i++;
11511143
}
11521144
if (i <= mask) {
11531145
key = Py_NewRef(entry[i].key);
1154-
#ifdef Py_GIL_DISABLED
1155-
FT_ATOMIC_STORE_SSIZE_RELAXED(si->si_pos, i + 1);
1156-
#else
11571146
si->si_pos = i + 1;
1158-
#endif
11591147
si->len--;
11601148
}
11611149
else {
1162-
#ifdef Py_GIL_DISABLED
1163-
/* free-threaded: keep si_set; just mark exhausted */
1164-
FT_ATOMIC_STORE_SSIZE_RELAXED(si->si_pos, -1);
1150+
si->si_pos = -1;
11651151
si->len = 0;
1166-
#else
1167-
si->si_set = NULL;
1168-
#endif
11691152
}
11701153
}
1171-
1172-
#ifdef Py_GIL_DISABLED
1173-
done:
1174-
#endif
1154+
Py_END_CRITICAL_SECTION2();
1155+
return key;
1156+
#else
1157+
Py_BEGIN_CRITICAL_SECTION(so);
1158+
i = si->si_pos;
1159+
entry = so->table;
1160+
mask = so->mask;
1161+
while (i <= mask &&
1162+
(entry[i].key == NULL || entry[i].key == dummy)) {
1163+
i++;
1164+
}
1165+
if (i <= mask) {
1166+
key = Py_NewRef(entry[i].key);
1167+
si->si_pos = i + 1;
1168+
si->len--;
1169+
}
1170+
else {
1171+
si->si_set = NULL;
1172+
decref_so = 1;
1173+
}
11751174
Py_END_CRITICAL_SECTION();
11761175

1177-
if (key == NULL) {
1178-
#ifndef Py_GIL_DISABLED
1176+
if (decref_so) {
11791177
Py_DECREF(so);
1180-
#endif
11811178
return NULL;
11821179
}
11831180
return key;
1181+
#endif
11841182
}
11851183

11861184
PyTypeObject PySetIter_Type = {

0 commit comments

Comments
 (0)