https://gcc.gnu.org/g:8d97a0dabea1bae3b12ea042f40e3b6528f720d3

commit 8d97a0dabea1bae3b12ea042f40e3b6528f720d3
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
    
    Backport from mainline:
    
    libgomp/ChangeLog:
    
            * plugin/plugin-gcn.c (drain_queue): Execute placeholder entries
            with the queue lock held.
    
    (cherry picked from commit c52ff9699b42104b04865effe4347dfd0911bd41)

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 454d57551945..33e751d2dd29 100644
--- a/libgomp/plugin/plugin-gcn.c
+++ b/libgomp/plugin/plugin-gcn.c
@@ -3009,10 +3009,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