Skip to content

Commit c916f01

Browse files
committed
fix gc_generation.count race
1 parent 038495d commit c916f01

2 files changed

Lines changed: 32 additions & 3 deletions

File tree

Lib/test/test_free_threading/test_gc.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,35 @@ def setter():
124124
finally:
125125
gc.set_threshold(*current_threshold)
126126

127+
def test_get_count(self):
128+
class CyclicReference:
129+
def __init__(self):
130+
self.ref = self
131+
132+
NUM_ALLOCATORS = 7
133+
NUM_READERS = 1
134+
NUM_THREADS = NUM_ALLOCATORS + NUM_READERS
135+
NUM_ITERS = 200_000
136+
137+
barrier = threading.Barrier(NUM_THREADS)
138+
139+
def allocator():
140+
barrier.wait()
141+
for _ in range(NUM_ITERS):
142+
CyclicReference()
143+
144+
145+
def reader():
146+
barrier.wait()
147+
for _ in range(NUM_ITERS):
148+
gc.get_count()
149+
150+
threads = [Thread(target=allocator) for _ in range(NUM_ALLOCATORS)]
151+
threads.extend(Thread(target=reader) for _ in range(NUM_READERS))
152+
153+
with threading_helper.start_threads(threads):
154+
pass
155+
127156

128157
if __name__ == "__main__":
129158
unittest.main()

Modules/gcmodule.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -233,9 +233,9 @@ gc_get_count_impl(PyObject *module)
233233
gcstate->generations[2].count);
234234
#else
235235
return Py_BuildValue("(iii)",
236-
gcstate->young.count,
237-
gcstate->old[0].count,
238-
gcstate->old[1].count);
236+
_Py_atomic_load_int_relaxed(&gcstate->young.count),
237+
_Py_atomic_load_int_relaxed(&gcstate->old[0].count),
238+
_Py_atomic_load_int_relaxed(&gcstate->old[1].count));
239239
#endif
240240
}
241241

0 commit comments

Comments
 (0)