gh-148613: Fix race in `gc_set_threshold` and `gc_get_threshold` (#15… · python/cpython@41eb8ee

GitHub

File tree

Lib/test/test_free_threading

Misc/NEWS.d/next/Core_and_Builtins

Modules

Original file line numberDiff line numberDiff line change@@ -94,6 +94,36 @@ def evil():

9494thread.start()

9595thread.join()

969697+deftest_set_threshold(self):

98+# GH-148613: Setting the GC threshold from another thread could cause a

99+# race between the `gc_should_collect` and `gc_set_threshold` functions.

100+NUM_THREADS=8

101+NUM_ITERS=100_000

102+barrier=threading.Barrier(NUM_THREADS)

103+104+classCyclicReference:

105+def__init__(self):

106+self.r=self

107+108+defallocator():

109+barrier.wait()

110+for_inrange(NUM_ITERS):

111+CyclicReference()

112+113+defsetter():

114+barrier.wait()

115+foriinrange(NUM_ITERS):

116+gc.set_threshold(100+ (i%100), 10+ (i%10), 10+ (i%10))

117+118+current_threshold=gc.get_threshold()

119+try:

120+threads= [Thread(target=allocator) for_inrange(NUM_THREADS-1)]

121+threads.append(Thread(target=setter))

122+withthreading_helper.start_threads(threads):

123+pass

124+finally:

125+gc.set_threshold(*current_threshold)

126+9712798128if__name__=="__main__":

99129unittest.main()

Original file line numberDiff line numberDiff line change@@ -0,0 +1,2 @@

1+Fix a data race in the free-threaded build between :func:`gc.set_threshold`

2+and garbage collection scheduling during object allocation.

Original file line numberDiff line numberDiff line change@@ -167,13 +167,16 @@ gc_set_threshold_impl(PyObject *module, int threshold0, int group_right_1,

167167gcstate->generations[2].threshold=threshold2;

168168 }

169169#else

170+PyInterpreterState*interp=_PyInterpreterState_GET();

171+_PyEval_StopTheWorld(interp);

170172gcstate->young.threshold=threshold0;

171173if (group_right_1) {

172174gcstate->old[0].threshold=threshold1;

173175 }

174176if (group_right_2) {

175177gcstate->old[1].threshold=threshold2;

176178 }

179+_PyEval_StartTheWorld(interp);

177180#endif

178181Py_RETURN_NONE;

179182}