Skip to content

Commit 266bb9d

Browse files
WIP: another way
1 parent d496c63 commit 266bb9d

File tree

5 files changed

+211
-574
lines changed

5 files changed

+211
-574
lines changed

Include/internal/pycore_gc.h

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,6 @@ static inline void _PyObject_GC_SET_SHARED(PyObject *op) {
131131
* When object are moved from the pending space, old[gcstate->visited_space^1]
132132
* into the increment, the old space bit is flipped.
133133
*/
134-
#define _PyGC_NEXT_MASK_OLD_SPACE_1 1
135134

136135
#define _PyGC_PREV_SHIFT 2
137136
#define _PyGC_PREV_MASK (((uintptr_t) -1) << _PyGC_PREV_SHIFT)
@@ -159,13 +158,11 @@ typedef enum {
159158
// Lowest bit of _gc_next is used for flags only in GC.
160159
// But it is always 0 for normal code.
161160
static inline PyGC_Head* _PyGCHead_NEXT(PyGC_Head *gc) {
162-
uintptr_t next = gc->_gc_next & _PyGC_PREV_MASK;
161+
uintptr_t next = gc->_gc_next;
163162
return (PyGC_Head*)next;
164163
}
165164
static inline void _PyGCHead_SET_NEXT(PyGC_Head *gc, PyGC_Head *next) {
166-
uintptr_t unext = (uintptr_t)next;
167-
assert((unext & ~_PyGC_PREV_MASK) == 0);
168-
gc->_gc_next = (gc->_gc_next & ~_PyGC_PREV_MASK) | unext;
165+
gc->_gc_next = (uintptr_t)next;
169166
}
170167

171168
// Lowest two bits of _gc_prev is used for _PyGC_PREV_MASK_* flags.
@@ -249,8 +246,7 @@ static inline void _PyObject_GC_TRACK(
249246
PyGC_Head *last = (PyGC_Head*)(generation0->_gc_prev);
250247
_PyGCHead_SET_NEXT(last, gc);
251248
_PyGCHead_SET_PREV(gc, last);
252-
uintptr_t not_visited = 1 ^ gcstate->visited_space;
253-
gc->_gc_next = ((uintptr_t)generation0) | not_visited;
249+
_PyGCHead_SET_NEXT(gc, generation0);
254250
generation0->_gc_prev = (uintptr_t)gc;
255251
gcstate->young.count++; /* number of tracked GC objects */
256252
gcstate->heap_size++;

Include/internal/pycore_interp_structs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,6 @@ struct _gc_runtime_state {
233233
int visited_space;
234234
int phase;
235235

236-
#ifdef Py_GIL_DISABLED
237236
/* This is the number of objects that survived the last full
238237
collection. It approximates the number of long lived objects
239238
tracked by the GC.
@@ -246,6 +245,7 @@ struct _gc_runtime_state {
246245
the first time. */
247246
Py_ssize_t long_lived_pending;
248247

248+
#ifdef Py_GIL_DISABLED
249249
/* True if gc.freeze() has been used. */
250250
int freeze_active;
251251

Lib/test/test_gc.py

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
Py_GIL_DISABLED)
88
from test.support.import_helper import import_module
99
from test.support.os_helper import temp_dir, TESTFN, unlink
10-
from test.support.script_helper import assert_python_ok, make_script, run_test_script
10+
from test.support.script_helper import assert_python_ok, make_script
1111
from test.support import threading_helper, gc_threshold
1212

1313
import gc
@@ -399,11 +399,19 @@ def test_collect_generations(self):
399399
# each call to collect(N)
400400
x = []
401401
gc.collect(0)
402-
# x is now in the old gen
402+
# x is now in gen 1
403403
a, b, c = gc.get_count()
404-
# We don't check a since its exact values depends on
404+
gc.collect(1)
405+
# x is now in gen 2
406+
d, e, f = gc.get_count()
407+
gc.collect(2)
408+
# x is now in gen 3
409+
g, h, i = gc.get_count()
410+
# We don't check a, d, g since their exact values depends on
405411
# internal implementation details of the interpreter.
406412
self.assertEqual((b, c), (1, 0))
413+
self.assertEqual((e, f), (0, 1))
414+
self.assertEqual((h, i), (0, 0))
407415

408416
def test_trashcan(self):
409417
class Ouch:
@@ -870,10 +878,42 @@ def test_get_objects_generations(self):
870878
self.assertTrue(
871879
any(l is element for element in gc.get_objects(generation=0))
872880
)
873-
gc.collect()
881+
self.assertFalse(
882+
any(l is element for element in gc.get_objects(generation=1))
883+
)
884+
self.assertFalse(
885+
any(l is element for element in gc.get_objects(generation=2))
886+
)
887+
gc.collect(generation=0)
888+
self.assertFalse(
889+
any(l is element for element in gc.get_objects(generation=0))
890+
)
891+
self.assertTrue(
892+
any(l is element for element in gc.get_objects(generation=1))
893+
)
894+
self.assertFalse(
895+
any(l is element for element in gc.get_objects(generation=2))
896+
)
897+
gc.collect(generation=1)
874898
self.assertFalse(
875899
any(l is element for element in gc.get_objects(generation=0))
876900
)
901+
self.assertFalse(
902+
any(l is element for element in gc.get_objects(generation=1))
903+
)
904+
self.assertTrue(
905+
any(l is element for element in gc.get_objects(generation=2))
906+
)
907+
gc.collect(generation=2)
908+
self.assertFalse(
909+
any(l is element for element in gc.get_objects(generation=0))
910+
)
911+
self.assertFalse(
912+
any(l is element for element in gc.get_objects(generation=1))
913+
)
914+
self.assertTrue(
915+
any(l is element for element in gc.get_objects(generation=2))
916+
)
877917
del l
878918
gc.collect()
879919

@@ -1181,17 +1221,6 @@ def test_tuple_untrack_counts(self):
11811221
self.assertTrue(new_count - count > (n // 2))
11821222

11831223

1184-
class IncrementalGCTests(unittest.TestCase):
1185-
@unittest.skipIf(_testinternalcapi is None, "requires _testinternalcapi")
1186-
@requires_gil_enabled("Free threading does not support incremental GC")
1187-
def test_incremental_gc_handles_fast_cycle_creation(self):
1188-
# Run this test in a fresh process. The number of alive objects (which can
1189-
# be from unit tests run before this one) can influence how quickly cyclic
1190-
# garbage is found.
1191-
script = support.findfile("_test_gc_fast_cycles.py")
1192-
run_test_script(script)
1193-
1194-
11951224
class GCCallbackTests(unittest.TestCase):
11961225
def setUp(self):
11971226
# Save gc state and disable it.

Modules/gcmodule.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ gc_get_threshold_impl(PyObject *module)
183183
return Py_BuildValue("(iii)",
184184
gcstate->young.threshold,
185185
gcstate->old[0].threshold,
186-
0);
186+
gcstate->old[1].threshold);
187187
}
188188

189189
/*[clinic input]
@@ -209,8 +209,8 @@ gc_get_count_impl(PyObject *module)
209209

210210
return Py_BuildValue("(iii)",
211211
gcstate->young.count,
212-
gcstate->old[gcstate->visited_space].count,
213-
gcstate->old[gcstate->visited_space^1].count);
212+
gcstate->old[0].count,
213+
gcstate->old[1].count);
214214
}
215215

216216
/*[clinic input]

0 commit comments

Comments
 (0)