Skip to content

Conversation

@huixie90
Copy link
Member

@huixie90 huixie90 commented Jun 29, 2025

Fixes #109290

See the GH issue for the details. In conclusion, we have two issues in the atomic<T>::wait when T does not match our contention_t:

  • We don't have a total single order which can leads to missed notification based on the Herd7 simulation on relaxed architectural like PowerPC
  • We assumed the platform wait (futex_wait/__ulock_wait) has seq_cst barrier internally but there is no such guarantee

@huixie90 huixie90 requested a review from a team as a code owner June 29, 2025 10:44
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Jun 29, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 29, 2025

@llvm/pr-subscribers-libcxx

Author: Hui (huixie90)

Changes

Full diff: https://github.com/llvm/llvm-project/pull/146267.diff

1 Files Affected:

  • (modified) libcxx/src/atomic.cpp (+3-2)
diff --git a/libcxx/src/atomic.cpp b/libcxx/src/atomic.cpp
index c1af8d6f95aae..585fd1f538e46 100644
--- a/libcxx/src/atomic.cpp
+++ b/libcxx/src/atomic.cpp
@@ -151,8 +151,9 @@ __libcpp_contention_monitor_for_wait(__cxx_atomic_contention_t volatile* /*__con
 static void __libcpp_contention_wait(__cxx_atomic_contention_t volatile* __contention_state,
                                      __cxx_atomic_contention_t const volatile* __platform_state,
                                      __cxx_contention_t __old_value) {
-  __cxx_atomic_fetch_add(__contention_state, __cxx_contention_t(1), memory_order_seq_cst);
+  __cxx_atomic_fetch_add(__contention_state, __cxx_contention_t(1), memory_order_relaxed);
   // We sleep as long as the monitored value hasn't changed.
+  __cxx_atomic_thread_fence(memory_order_seq_cst);
   __libcpp_platform_wait_on_address(__platform_state, __old_value);
   __cxx_atomic_fetch_sub(__contention_state, __cxx_contention_t(1), memory_order_release);
 }
@@ -163,7 +164,7 @@ static void __libcpp_contention_wait(__cxx_atomic_contention_t volatile* __conte
 static void __libcpp_atomic_notify(void const volatile* __location) {
   auto const __entry = __libcpp_contention_state(__location);
   // The value sequence laundering happens on the next line below.
-  __cxx_atomic_fetch_add(&__entry->__platform_state, __cxx_contention_t(1), memory_order_release);
+  __cxx_atomic_fetch_add(&__entry->__platform_state, __cxx_contention_t(1), memory_order_seq_cst);
   __libcpp_contention_notify(
       &__entry->__contention_state,
       &__entry->__platform_state,

@aharrison24
Copy link

Thanks for taking this issue on! This looks like a correct implementation of "Option 1a" from the original issue I raised. That's been verified by three separate people using Herd, Dartagnan and GenMC respectively, so we're relatively sure it's doing the right thing at this point!

Copy link
Member

@ldionne ldionne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but +1 about adding a comment.

@huixie90 huixie90 force-pushed the hxie/atomic_wait_fix branch from 290927e to 64d2844 Compare July 5, 2025 08:15
@huixie90 huixie90 merged commit c358979 into llvm:main Jul 6, 2025
128 of 132 checks passed
__cxx_atomic_fetch_add(__contention_state, __cxx_contention_t(1), memory_order_relaxed);
// https://github.com/llvm/llvm-project/issues/109290
// There are no platform guarantees of a memory barrier in the platform wait implementation
__cxx_atomic_thread_fence(memory_order_seq_cst);
Copy link
Contributor

@gonzalobg gonzalobg Aug 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@huixie90 why seq_cst? Could we add a comment explaining that? e.g. why doesn't acquire or acq_rel suffice.

auto const __entry = __libcpp_contention_state(__location);
// The value sequence laundering happens on the next line below.
__cxx_atomic_fetch_add(&__entry->__platform_state, __cxx_contention_t(1), memory_order_release);
__cxx_atomic_fetch_add(&__entry->__platform_state, __cxx_contention_t(1), memory_order_seq_cst);
Copy link
Contributor

@gonzalobg gonzalobg Aug 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar as above, why is seq_cst required? e.g. why doesn't release or acq_rel suffice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[libc++] Incorrect memory order in atomic wait

5 participants