Skip to content

Commit 6afdbb8

Browse files
committed
gh-132657: revert lock-free set contains
This change is causing ARM64 refleaks tests to hang. Revert until we can diagnosis it. This reverts commits: 3f56186 c98182b
1 parent d844d22 commit 6afdbb8

File tree

5 files changed

+123
-451
lines changed

5 files changed

+123
-451
lines changed

Include/internal/pycore_pyatomic_ft_wrappers.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,6 @@ extern "C" {
5757
_Py_atomic_store_uintptr_release(&value, new_value)
5858
#define FT_ATOMIC_STORE_SSIZE_RELAXED(value, new_value) \
5959
_Py_atomic_store_ssize_relaxed(&value, new_value)
60-
#define FT_ATOMIC_STORE_SSIZE_RELEASE(value, new_value) \
61-
_Py_atomic_store_ssize_release(&value, new_value)
6260
#define FT_ATOMIC_STORE_UINT8_RELAXED(value, new_value) \
6361
_Py_atomic_store_uint8_relaxed(&value, new_value)
6462
#define FT_ATOMIC_STORE_UINT16_RELAXED(value, new_value) \
@@ -142,7 +140,6 @@ extern "C" {
142140
#define FT_ATOMIC_STORE_PTR_RELEASE(value, new_value) value = new_value
143141
#define FT_ATOMIC_STORE_UINTPTR_RELEASE(value, new_value) value = new_value
144142
#define FT_ATOMIC_STORE_SSIZE_RELAXED(value, new_value) value = new_value
145-
#define FT_ATOMIC_STORE_SSIZE_RELEASE(value, new_value) value = new_value
146143
#define FT_ATOMIC_STORE_UINT8_RELAXED(value, new_value) value = new_value
147144
#define FT_ATOMIC_STORE_UINT16_RELAXED(value, new_value) value = new_value
148145
#define FT_ATOMIC_STORE_UINT32_RELAXED(value, new_value) value = new_value
Lines changed: 7 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
import unittest
2-
from threading import Thread, Barrier, Event
2+
3+
from threading import Thread, Barrier
4+
from unittest import TestCase
5+
36
from test.support import threading_helper
47

58

6-
class TestSetRepr(unittest.TestCase):
9+
@threading_helper.requires_working_threading()
10+
class TestSet(TestCase):
711
def test_repr_clear(self):
812
"""Test repr() of a set while another thread is calling clear()"""
913
NUM_ITERS = 10
1014
NUM_REPR_THREADS = 10
11-
barrier = Barrier(NUM_REPR_THREADS + 1, timeout=2)
15+
barrier = Barrier(NUM_REPR_THREADS + 1)
1216
s = {1, 2, 3, 4, 5, 6, 7, 8}
1317

1418
def clear_set():
@@ -33,131 +37,5 @@ def repr_set():
3337
self.assertIn(set_repr, ("set()", "{1, 2, 3, 4, 5, 6, 7, 8}"))
3438

3539

36-
class RaceTestBase:
37-
def test_contains_mutate(self):
38-
"""Test set contains operation combined with mutation."""
39-
barrier = Barrier(2, timeout=2)
40-
s = set()
41-
done = Event()
42-
43-
NUM_LOOPS = 1000
44-
45-
def read_set():
46-
barrier.wait()
47-
while not done.is_set():
48-
for i in range(self.SET_SIZE):
49-
item = i >> 1
50-
result = item in s
51-
52-
def mutate_set():
53-
barrier.wait()
54-
for i in range(NUM_LOOPS):
55-
s.clear()
56-
for j in range(self.SET_SIZE):
57-
s.add(j)
58-
for j in range(self.SET_SIZE):
59-
s.discard(j)
60-
# executes the set_swap_bodies() function
61-
s.__iand__(set(k for k in range(10, 20)))
62-
done.set()
63-
64-
threads = [Thread(target=read_set), Thread(target=mutate_set)]
65-
for t in threads:
66-
t.start()
67-
for t in threads:
68-
t.join()
69-
70-
def test_contains_frozenset(self):
71-
barrier = Barrier(3, timeout=2)
72-
done = Event()
73-
74-
NUM_LOOPS = 1_000
75-
76-
# This mutates the key used for contains test, not the container
77-
# itself. This works because frozenset allows the key to be a set().
78-
s = set()
79-
80-
def mutate_set():
81-
barrier.wait()
82-
while not done.is_set():
83-
s.add(0)
84-
s.add(1)
85-
s.clear()
86-
87-
def read_set():
88-
barrier.wait()
89-
container = frozenset([frozenset([0])])
90-
self.assertTrue(set([0]) in container)
91-
for _ in range(NUM_LOOPS):
92-
# Will return True when {0} is the key and False otherwise
93-
result = s in container
94-
done.set()
95-
96-
threads = [
97-
Thread(target=read_set),
98-
Thread(target=read_set),
99-
Thread(target=mutate_set),
100-
]
101-
for t in threads:
102-
t.start()
103-
for t in threads:
104-
t.join()
105-
106-
def test_contains_hash_mutate(self):
107-
"""Test set contains operation with mutating hash method."""
108-
barrier = Barrier(2, timeout=2)
109-
110-
NUM_LOOPS = 1_000
111-
SET_SIZE = self.SET_SIZE
112-
113-
s = set(range(SET_SIZE))
114-
115-
class Key:
116-
def __init__(self):
117-
self.count = 0
118-
self.value = 0
119-
120-
def __hash__(self):
121-
self.count += 1
122-
# This intends to trigger the SET_LOOKKEY_CHANGED case
123-
# of set_lookkey_threadsafe() since calling clear()
124-
# will cause the 'table' pointer to change.
125-
if self.count % 2 == 0:
126-
s.clear()
127-
else:
128-
s.update(range(SET_SIZE))
129-
return hash(self.value)
130-
131-
def __eq__(self, other):
132-
return self.value == other
133-
134-
key = Key()
135-
self.assertTrue(key in s)
136-
self.assertFalse(key in s)
137-
self.assertTrue(key in s)
138-
self.assertFalse(key in s)
139-
140-
def read_set():
141-
barrier.wait()
142-
for i in range(NUM_LOOPS):
143-
result = key in s
144-
145-
threads = [Thread(target=read_set), Thread(target=read_set)]
146-
for t in threads:
147-
t.start()
148-
for t in threads:
149-
t.join()
150-
151-
152-
@threading_helper.requires_working_threading()
153-
class SmallSetTest(RaceTestBase, unittest.TestCase):
154-
SET_SIZE = 6 # smaller than PySet_MINSIZE
155-
156-
157-
@threading_helper.requires_working_threading()
158-
class LargeSetTest(RaceTestBase, unittest.TestCase):
159-
SET_SIZE = 20 # larger than PySet_MINSIZE
160-
161-
16240
if __name__ == "__main__":
16341
unittest.main()

Misc/NEWS.d/next/Core_and_Builtins/2025-07-11-19-57-27.gh-issue-132657.vwDuO2.rst

Lines changed: 0 additions & 2 deletions
This file was deleted.

Objects/clinic/setobject.c.h

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)