Skip to content

Commit 382b230

Browse files
committed
Revert "[3.15] gh-155811: Add a seqcount to gc_stats to prevent torn reads (GH-155828) (#158829)"
This reverts commit 0281240.
1 parent aec825d commit 382b230

5 files changed

Lines changed: 8 additions & 55 deletions

File tree

‎Include/internal/pycore_interp_structs.h‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,6 @@ struct gc_old_stats_buffer {
219219
struct gc_stats {
220220
struct gc_young_stats_buffer young;
221221
struct gc_old_stats_buffer old[2];
222-
uint32_t update_seq;
223222
};
224223

225224
struct _gc_runtime_state {

‎Misc/NEWS.d/next/Library/2026-08-15-10-20-40.gh-issue-155811.knP-YB.rst‎

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

‎Modules/_remote_debugging/gc_stats.c‎

Lines changed: 6 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -103,42 +103,12 @@ get_gc_stats_from_interpreter_state(RuntimeOffsets *offsets,
103103
}
104104

105105
struct gc_stats stats;
106-
uintptr_t sequence_address = gc_stats_addr
107-
+ offsetof(struct gc_stats, update_seq);
108-
/* A short GC update may finish before a second attempt. */
109-
for (int attempt = 0; attempt < 2; attempt++) {
110-
uint32_t before;
111-
if (_Py_RemoteDebug_ReadRemoteMemory(&offsets->handle,
112-
sequence_address,
113-
sizeof(before), &before) < 0) {
114-
set_exception_cause(offsets, PyExc_RuntimeError,
115-
"Failed to read GC update sequence");
116-
return -1;
117-
}
118-
if (_Py_RemoteDebug_ReadRemoteMemory(&offsets->handle,
119-
gc_stats_addr,
120-
sizeof(stats),
121-
&stats) < 0) {
122-
set_exception_cause(offsets, PyExc_RuntimeError, "Failed to read GC state");
123-
return -1;
124-
}
125-
126-
uint32_t after;
127-
if (_Py_RemoteDebug_ReadRemoteMemory(&offsets->handle,
128-
sequence_address,
129-
sizeof(after), &after) < 0) {
130-
set_exception_cause(offsets, PyExc_RuntimeError,
131-
"Failed to read GC update sequence");
132-
return -1;
133-
}
134-
if (before == after && before == stats.update_seq && !(after & 1)) {
135-
break;
136-
}
137-
if (attempt == 1) {
138-
PyErr_SetString(PyExc_RuntimeError,
139-
"GC stats changed while being read; retry later");
140-
return -1;
141-
}
106+
if (_Py_RemoteDebug_ReadRemoteMemory(&offsets->handle,
107+
gc_stats_addr,
108+
sizeof(stats),
109+
&stats) < 0) {
110+
set_exception_cause(offsets, PyExc_RuntimeError, "Failed to read GC state");
111+
return -1;
142112
}
143113

144114
if (read_gc_stats(&stats, iid, ctx->result,

‎Python/gc.c‎

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,13 +1399,6 @@ gc_get_prev_stats(GCState *gcstate, int gen)
13991399
static void
14001400
add_stats(GCState *gcstate, int gen, struct gc_generation_stats *stats)
14011401
{
1402-
struct gc_stats *generation_stats = gcstate->generation_stats;
1403-
uint32_t seq = _Py_atomic_load_uint32_relaxed(&generation_stats->update_seq);
1404-
assert((seq & 1) == 0);
1405-
/* Odd seq tells the reader that an update is in progress. */
1406-
_Py_atomic_store_uint32_relaxed(&generation_stats->update_seq, seq + 1);
1407-
_Py_atomic_fence_seq_cst();
1408-
14091402
struct gc_generation_stats *prev_stats = gc_get_prev_stats(gcstate, gen);
14101403
struct gc_generation_stats *cur_stats = gc_get_stats(gcstate, gen);
14111404

@@ -1419,8 +1412,9 @@ add_stats(GCState *gcstate, int gen, struct gc_generation_stats *stats)
14191412

14201413
cur_stats->duration += stats->duration;
14211414
cur_stats->heap_size = stats->heap_size;
1415+
/* Publish ts_stop last so remote readers do not select a partially
1416+
updated stats record as the latest collection. */
14221417
cur_stats->ts_stop = stats->ts_stop;
1423-
_Py_atomic_store_uint32_release(&generation_stats->update_seq, seq + 2);
14241418
}
14251419

14261420
/* This is the main function. Read this to understand how the

‎Python/gc_free_threading.c‎

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2282,12 +2282,6 @@ gc_collect_main(PyThreadState *tstate, int generation, _PyGC_Reason reason)
22822282
}
22832283

22842284
/* Update stats */
2285-
struct gc_stats *generation_stats = gcstate->generation_stats;
2286-
uint32_t seq = _Py_atomic_load_uint32_relaxed(&generation_stats->update_seq);
2287-
assert((seq & 1) == 0);
2288-
/* Odd seq tells the reader that an update is in progress. */
2289-
_Py_atomic_store_uint32_relaxed(&generation_stats->update_seq, seq + 1);
2290-
_Py_atomic_fence_seq_cst();
22912285
struct gc_generation_stats *stats = get_stats(gcstate, generation);
22922286
stats->ts_start = start;
22932287
stats->ts_stop = stop;
@@ -2296,7 +2290,6 @@ gc_collect_main(PyThreadState *tstate, int generation, _PyGC_Reason reason)
22962290
stats->uncollectable += n;
22972291
stats->duration += duration;
22982292
stats->candidates += state.candidates;
2299-
_Py_atomic_store_uint32_release(&generation_stats->update_seq, seq + 2);
23002293

23012294
GC_STAT_ADD(generation, objects_collected, m);
23022295
#ifdef Py_STATS

0 commit comments

Comments
 (0)