summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorSam Gross <colesbury@gmail.com>2024-10-15 16:09:35 (GMT)
committerGitHub <noreply@github.com>2024-10-15 16:09:35 (GMT)
commit54c6fcbefd33a8d8bf8c004cf1aad3be3d37b933 (patch)
treec6e949380952257bcfa9c852682ce544915e1965 /Python
parente97910cdb76c1f1dadfc4721b828611e4f4b6449 (diff)
downloadcpython-54c6fcbefd33a8d8bf8c004cf1aad3be3d37b933.zip
cpython-54c6fcbefd33a8d8bf8c004cf1aad3be3d37b933.tar.gz
cpython-54c6fcbefd33a8d8bf8c004cf1aad3be3d37b933.tar.bz2
gh-124375: Avoid calling `_PyMem_ProcessDelayed` on other thread states (#124459)
This fixes a crash when running the PyO3 test suite on the free-threaded build. The `qsbr` field is initialized after the `PyThreadState` is added to the interpreter's linked list -- it might still be NULL. Instead, we "steal" the queue of to-be-freed memory blocks. This is always initialized (possibly empty) and protected by the stop the world pause.
Diffstat (limited to 'Python')
-rw-r--r--Python/gc_free_threading.c18
1 files changed, 12 insertions, 6 deletions
diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c
index 38564d9..3814cd4 100644
--- a/Python/gc_free_threading.c
+++ b/Python/gc_free_threading.c
@@ -420,18 +420,24 @@ merge_queued_objects(_PyThreadStateImpl *tstate, struct collection_state *state)
static void
process_delayed_frees(PyInterpreterState *interp)
{
- // In STW status, we can observe the latest write sequence by
- // advancing the write sequence immediately.
+ // While we are in a "stop the world" pause, we can observe the latest
+ // write sequence by advancing the write sequence immediately.
_Py_qsbr_advance(&interp->qsbr);
_PyThreadStateImpl *current_tstate = (_PyThreadStateImpl *)_PyThreadState_GET();
_Py_qsbr_quiescent_state(current_tstate->qsbr);
+
+ // Merge the queues from other threads into our own queue so that we can
+ // process all of the pending delayed free requests at once.
HEAD_LOCK(&_PyRuntime);
- PyThreadState *tstate = interp->threads.head;
- while (tstate != NULL) {
- _PyMem_ProcessDelayed(tstate);
- tstate = (PyThreadState *)tstate->next;
+ for (PyThreadState *p = interp->threads.head; p != NULL; p = p->next) {
+ _PyThreadStateImpl *other = (_PyThreadStateImpl *)p;
+ if (other != current_tstate) {
+ llist_concat(&current_tstate->mem_free_queue, &other->mem_free_queue);
+ }
}
HEAD_UNLOCK(&_PyRuntime);
+
+ _PyMem_ProcessDelayed((PyThreadState *)current_tstate);
}
// Subtract an incoming reference from the computed "gc_refs" refcount.