diff options
author | Sam Gross <colesbury@gmail.com> | 2024-10-15 16:09:35 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-15 16:09:35 (GMT) |
commit | 54c6fcbefd33a8d8bf8c004cf1aad3be3d37b933 (patch) | |
tree | c6e949380952257bcfa9c852682ce544915e1965 /Python | |
parent | e97910cdb76c1f1dadfc4721b828611e4f4b6449 (diff) | |
download | cpython-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.c | 18 |
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(¤t_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. |