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--;

Reply via email to