[gcc r16-989] libstdc++: Fix race condition in new atomic notify code

Jonathan Wakely redi@gcc.gnu.org
Fri May 30 09:08:07 GMT 2025


https://gcc.gnu.org/g:97ea9d7b021c3e9f8d0c7e371d40ded811f76dac

commit r16-989-g97ea9d7b021c3e9f8d0c7e371d40ded811f76dac
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Jan 9 22:32:02 2025 +0000

    libstdc++: Fix race condition in new atomic notify code
    
    When using a proxy object for atomic waiting and notifying operations,
    we need to ensure that the _M_ver value is always incremented by a
    notifying operation, even if we return early without doing the futex
    wake syscall. Otherwise we get missed wake-ups because the notifying
    thread doesn't modify the value that other threads are doing a futex
    wait on.
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/atomic_wait.h (__notify_impl): Increment the
            proxy value before returning early for the uncontended case.

Diff:
---
 libstdc++-v3/include/bits/atomic_wait.h | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/libstdc++-v3/include/bits/atomic_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
index 172910a4e34f..725ea030245d 100644
--- a/libstdc++-v3/include/bits/atomic_wait.h
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -406,18 +406,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     {
       __waiter_pool_impl* __pool = nullptr;
 
-      if (__args & __wait_flags::__track_contention)
-	{
-	  __pool = &__waiter_pool_impl::_S_impl_for(__addr);
-	  if (!__pool->_M_waiting())
-	    return;
-	}
-
       const __platform_wait_t* __wait_addr;
       if (__args & __wait_flags::__proxy_wait)
 	{
-	  if (!__pool)
-	    __pool = &__waiter_pool_impl::_S_impl_for(__addr);
+	  __pool = &__waiter_pool_impl::_S_impl_for(__addr);
 	  // Waiting for *__addr is actually done on the proxy's _M_ver.
 	  __wait_addr = &__pool->_M_ver;
 	  __atomic_fetch_add(&__pool->_M_ver, 1, __ATOMIC_RELAXED);
@@ -430,6 +422,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       else // Use the atomic variable's own address.
 	__wait_addr = __addr;
 
+      if (__args & __wait_flags::__track_contention)
+	{
+	  if (!__pool)
+	    __pool = &__waiter_pool_impl::_S_impl_for(__addr);
+	  if (!__pool->_M_waiting())
+	    return;
+	}
+
 #ifdef _GLIBCXX_HAVE_PLATFORM_WAIT
       __platform_notify(__wait_addr, __all);
 #else


More information about the Libstdc++-cvs mailing list