[05/10] libstdc++: Fix race condition in new atomic notify code

Message ID 20250110212810.832494-6-jwakely@redhat.com
State New
Headers
Series C++20 atomic wait/notify ABI stabilization |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-arm fail Test failed
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 fail Test failed

Commit Message

Jonathan Wakely Jan. 10, 2025, 9:23 p.m. UTC
  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.
---
 libstdc++-v3/include/bits/atomic_wait.h | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)
  

Patch

diff --git a/libstdc++-v3/include/bits/atomic_wait.h b/libstdc++-v3/include/bits/atomic_wait.h
index 29b83cad6e6c..4a9652ed8f1d 100644
--- a/libstdc++-v3/include/bits/atomic_wait.h
+++ b/libstdc++-v3/include/bits/atomic_wait.h
@@ -392,13 +392,6 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __wait_args __args{ *__a };
       __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)
 	{
@@ -416,6 +409,13 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       else // Use the atomic variable's own address.
 	__wait_addr = __addr;
 
+      if (__args & __wait_flags::__track_contention)
+	{
+	  __pool = &__waiter_pool_impl::_S_impl_for(__addr);
+	  if (!__pool->_M_waiting())
+	    return;
+	}
+
 #ifdef _GLIBCXX_HAVE_PLATFORM_WAIT
       __platform_notify(__wait_addr, __all);
 #else