[3.13] gh-117657: Fix TSAN race in free-threaded GC (GH-119883) (#119903)

Only call `gc_restore_tid()` from stop-the-world contexts.
`worklist_pop()` can be called while other threads are running, so use a
relaxed atomic to modify `ob_tid`.
(cherry picked from commit 60593b2052)

Co-authored-by: Sam Gross <colesbury@gmail.com>
This commit is contained in:
Miss Islington (bot) 2024-06-01 16:26:12 +02:00 committed by GitHub
parent a0559849ac
commit 48f3378d6c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 2 additions and 6 deletions

View file

@ -86,7 +86,7 @@ worklist_pop(struct worklist *worklist)
PyObject *op = (PyObject *)worklist->head;
if (op != NULL) {
worklist->head = op->ob_tid;
op->ob_tid = 0;
_Py_atomic_store_uintptr_relaxed(&op->ob_tid, 0);
}
return op;
}
@ -189,6 +189,7 @@ merge_refcount(PyObject *op, Py_ssize_t extra)
static void
gc_restore_tid(PyObject *op)
{
assert(_PyInterpreterState_GET()->stoptheworld.world_stopped);
mi_segment_t *segment = _mi_ptr_segment(op);
if (_Py_REF_IS_MERGED(op->ob_ref_shared)) {
op->ob_tid = 0;
@ -676,7 +677,6 @@ call_weakref_callbacks(struct collection_state *state)
Py_DECREF(temp);
}
gc_restore_tid(op);
Py_DECREF(op); // drop worklist reference
}
}
@ -986,7 +986,6 @@ cleanup_worklist(struct worklist *worklist)
{
PyObject *op;
while ((op = worklist_pop(worklist)) != NULL) {
gc_restore_tid(op);
gc_clear_unreachable(op);
Py_DECREF(op);
}