https://gcc.gnu.org/g:c52ff9699b42104b04865effe4347dfd0911bd41
commit r17-5733-gc52ff9699b42104b04865effe4347dfd0911bd41 Author: Andrew Stubbs <[email protected]> Date: Thu Oct 15 10:07:47 2026 +0000 amdgcn, libgomp: Fix async placeholder race in GCN plugin When an OpenACC async queue reaches a placeholder entry (created by acc_wait_async, or a "wait" clause on an async construct), the queue's drain thread signals the placeholder and only afterwards dequeues the entry. In between, the thread waiting on the placeholder can wake, finish its own queue, and allow the host to observe that queue as complete. The queue holding the placeholder still appears to be busy at that point, so an acc_async_test on it may return false even though everything it was waiting for has finished. This caused intermittent failures of libgomp.oacc-fortran/lib-12.f90 ("STOP 2"). Inserting a usleep (0) between signalling and dequeueing makes it fail every time. Fix this by keeping the queue lock held while signalling a placeholder, so that the signal and the dequeue appear atomic to any thread inspecting the queue. Assisted-By: Claude Opus 5.5 libgomp/ChangeLog: * plugin/plugin-gcn.c (drain_queue): Execute placeholder entries with the queue lock held. Diff: --- libgomp/plugin/plugin-gcn.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/libgomp/plugin/plugin-gcn.c b/libgomp/plugin/plugin-gcn.c index 9d36178f33f1..dc64c53c70dd 100644 --- a/libgomp/plugin/plugin-gcn.c +++ b/libgomp/plugin/plugin-gcn.c @@ -3007,10 +3007,22 @@ drain_queue (void *thread_arg) if (aq->queue_n > 0) { - pthread_mutex_unlock (&aq->mutex); - execute_queue_entry (aq, aq->queue_first); + int index = aq->queue_first; + + /* Signal placeholders with the queue lock held, so that the signal + and the dequeue appear atomic to any thread inspecting this queue. + Otherwise, a thread waiting on the placeholder (and hence any host + thread waiting on that thread's queue) can proceed while this queue + still appears to be busy, and an acc_async_test on this queue will + spuriously fail. */ + bool unlock_p = aq->queue[index].type != ASYNC_PLACEHOLDER; + + if (unlock_p) + pthread_mutex_unlock (&aq->mutex); + execute_queue_entry (aq, index); + if (unlock_p) + pthread_mutex_lock (&aq->mutex); - pthread_mutex_lock (&aq->mutex); aq->queue_first = ((aq->queue_first + 1) % ASYNC_QUEUE_SIZE); aq->queue_n--;
