Skip to content

Commit 104b4e6

Browse files
committed
add unit test
1 parent 4f57f14 commit 104b4e6

3 files changed

Lines changed: 33 additions & 5 deletions

File tree

Lib/test/test_free_threading/test_gc.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import unittest
22

33
import threading
4-
from threading import Thread
4+
from threading import Barrier, Thread
55
from unittest import TestCase
66
import gc
77

@@ -94,6 +94,34 @@ def evil():
9494
thread.start()
9595
thread.join()
9696

97+
def test_set_threshold(self):
98+
# GH-148613: Setting the GC threshold from another thread could causes
99+
# race between the `gc_should_collect` and `gc_set_threshold` functions.
100+
NUM_THREADS = 8
101+
NUM_ITERS = 100_000
102+
barrier = Barrier(NUM_THREADS)
103+
104+
class CyclicReference:
105+
def __init__(self):
106+
self.r = self
107+
108+
def allocator():
109+
barrier.wait()
110+
for _ in range(NUM_ITERS):
111+
CyclicReference()
112+
113+
def setter():
114+
barrier.wait()
115+
for i in range(NUM_ITERS):
116+
gc.set_threshold(100 + (i % 100), 10 + (i % 10), 10 + (i % 10))
117+
118+
threads = [Thread(target=allocator) for _ in range(NUM_THREADS - 1)]
119+
threads.append(Thread(target=setter))
120+
for t in threads:
121+
t.start()
122+
for t in threads:
123+
t.join()
124+
97125

98126
if __name__ == "__main__":
99127
unittest.main()

Modules/gcmodule.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,12 +167,12 @@ gc_set_threshold_impl(PyObject *module, int threshold0, int group_right_1,
167167
gcstate->generations[2].threshold = threshold2;
168168
}
169169
#else
170-
_Py_atomic_exchange_int(&gcstate->young.threshold, threshold0);
170+
_Py_atomic_store_int(&gcstate->young.threshold, threshold0);
171171
if (group_right_1) {
172-
_Py_atomic_exchange_int(&gcstate->old[0].threshold, threshold1);
172+
_Py_atomic_store_int(&gcstate->old[0].threshold, threshold1);
173173
}
174174
if (group_right_2) {
175-
_Py_atomic_exchange_int(&gcstate->old[1].threshold, threshold2);
175+
_Py_atomic_store_int(&gcstate->old[1].threshold, threshold2);
176176
}
177177
#endif
178178
Py_RETURN_NONE;

Python/gc_free_threading.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1665,7 +1665,7 @@ void
16651665
_PyGC_InitState(GCState *gcstate)
16661666
{
16671667
// TODO: move to pycore_runtime_init.h once the incremental GC lands.
1668-
_Py_atomic_exchange_int(&gcstate->young.threshold, 2000);
1668+
gcstate->young.threshold = 2000;
16691669
}
16701670

16711671

0 commit comments

Comments
 (0)