[libcxx-commits] [libcxx] [libc++] Refactor the predicate taking variant of `__cxx_atomic_wait` (PR #80596)
Jan Kokemüller via libcxx-commits
libcxx-commits at lists.llvm.org
Sun Feb 4 05:40:14 PST 2024
https://github.com/jiixyj updated https://github.com/llvm/llvm-project/pull/80596
>From dcf55e78a67de63357af04a095e7e7de3d33b65c Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Wed, 24 Jan 2024 08:38:00 +0000
Subject: [PATCH 1/6] [libc++] fix `counting_semaphore` lost wakeups
---
libcxx/include/__atomic/atomic_sync.h | 16 +++--
libcxx/include/semaphore | 21 ++++--
.../thread.semaphore/lost_wakeup.pass.cpp | 65 +++++++++++++++++++
3 files changed, 92 insertions(+), 10 deletions(-)
create mode 100644 libcxx/test/std/thread/thread.semaphore/lost_wakeup.pass.cpp
diff --git a/libcxx/include/__atomic/atomic_sync.h b/libcxx/include/__atomic/atomic_sync.h
index 93527958b2e1c..ba83396189edf 100644
--- a/libcxx/include/__atomic/atomic_sync.h
+++ b/libcxx/include/__atomic/atomic_sync.h
@@ -46,12 +46,12 @@ __libcpp_atomic_wait(__cxx_atomic_contention_t const volatile*, __cxx_contention
template <class _Atp, class _Fn>
struct __libcpp_atomic_wait_backoff_impl {
_Atp* __a;
- _Fn __test_fn;
+ _Fn __test_with_old;
_LIBCPP_AVAILABILITY_SYNC
_LIBCPP_HIDE_FROM_ABI bool operator()(chrono::nanoseconds __elapsed) const {
if (__elapsed > chrono::microseconds(64)) {
- auto const __monitor = std::__libcpp_atomic_monitor(__a);
- if (__test_fn())
+ auto __monitor = std::__libcpp_atomic_monitor(__a);
+ if (__test_with_old(__monitor))
return true;
std::__libcpp_atomic_wait(__a, __monitor);
} else if (__elapsed > chrono::microseconds(4))
@@ -62,9 +62,17 @@ struct __libcpp_atomic_wait_backoff_impl {
}
};
+template <class _Atp, class _Fn, class _Fn2>
+_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool
+__cxx_atomic_wait(_Atp* __a, _Fn&& __test_fn, _Fn2&& __test_with_old) {
+ __libcpp_atomic_wait_backoff_impl<_Atp, __decay_t<_Fn2> > __backoff_fn = {__a, __test_with_old};
+ return std::__libcpp_thread_poll_with_backoff(__test_fn, __backoff_fn);
+}
+
template <class _Atp, class _Fn>
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_wait(_Atp* __a, _Fn&& __test_fn) {
- __libcpp_atomic_wait_backoff_impl<_Atp, __decay_t<_Fn> > __backoff_fn = {__a, __test_fn};
+ auto __test_with_old = [&](auto&) { return __test_fn(); };
+ __libcpp_atomic_wait_backoff_impl<_Atp, decltype(__test_with_old)> __backoff_fn{__a, __test_with_old};
return std::__libcpp_thread_poll_with_backoff(__test_fn, __backoff_fn);
}
diff --git a/libcxx/include/semaphore b/libcxx/include/semaphore
index 649705f45b049..c4d9ee1ab63e8 100644
--- a/libcxx/include/semaphore
+++ b/libcxx/include/semaphore
@@ -54,6 +54,7 @@ using binary_semaphore = counting_semaphore<1>;
#include <__assert> // all public C++ headers provide the assertion handler
#include <__atomic/atomic_base.h>
#include <__atomic/atomic_sync.h>
+#include <__atomic/contention_t.h>
#include <__atomic/memory_order.h>
#include <__availability>
#include <__chrono/time_point.h>
@@ -95,19 +96,22 @@ public:
_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
__update <= _LIBCPP_SEMAPHORE_MAX - __old, "update is greater than the expected value");
- if (__old > 0) {
- // Nothing to do
- } else if (__update > 1)
+ if (__old == 0) {
__a_.notify_all();
- else
- __a_.notify_one();
+ }
}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void acquire() {
auto const __test_fn = [this]() -> bool {
auto __old = __a_.load(memory_order_relaxed);
return (__old != 0) && __a_.compare_exchange_strong(__old, __old - 1, memory_order_acquire, memory_order_relaxed);
};
- __cxx_atomic_wait(&__a_.__a_, __test_fn);
+ auto const __test_with_old = [this](__cxx_contention_t& __monitor) -> bool {
+ ptrdiff_t __old = __monitor;
+ bool __r = __try_acquire_impl(__old);
+ __monitor = static_cast<__cxx_contention_t>(__old);
+ return __r;
+ };
+ __cxx_atomic_wait(&__a_.__a_, __test_fn, __test_with_old);
}
template <class _Rep, class _Period>
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool
@@ -119,6 +123,11 @@ public:
}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool try_acquire() {
auto __old = __a_.load(memory_order_acquire);
+ return __try_acquire_impl(__old);
+ }
+
+private:
+ _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY bool __try_acquire_impl(ptrdiff_t& __old) {
while (true) {
if (__old == 0)
return false;
diff --git a/libcxx/test/std/thread/thread.semaphore/lost_wakeup.pass.cpp b/libcxx/test/std/thread/thread.semaphore/lost_wakeup.pass.cpp
new file mode 100644
index 0000000000000..aa21e93221b31
--- /dev/null
+++ b/libcxx/test/std/thread/thread.semaphore/lost_wakeup.pass.cpp
@@ -0,0 +1,65 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: libcpp-has-no-threads
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+// This test requires the dylib support introduced in D68480, which shipped in macOS 11.0.
+// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12|13|14|15}}
+
+// This is a regression test for https://llvm.org/PR47013.
+
+// <semaphore>
+
+#include <barrier>
+#include <semaphore>
+#include <thread>
+#include <vector>
+
+#include "make_test_thread.h"
+
+static std::counting_semaphore<> s(0);
+static std::barrier<> b(8 + 1);
+
+void acquire() {
+ for (int i = 0; i < 10'000; ++i) {
+ s.acquire();
+ b.arrive_and_wait();
+ }
+}
+
+void release() {
+ for (int i = 0; i < 10'000; ++i) {
+ s.release(1);
+ s.release(1);
+ s.release(1);
+ s.release(1);
+
+ s.release(1);
+ s.release(1);
+ s.release(1);
+ s.release(1);
+
+ b.arrive_and_wait();
+ }
+}
+
+int main(int, char**) {
+ for (int run = 0; run < 20; ++run) {
+ std::vector<std::thread> threads;
+ for (int i = 0; i < 8; ++i)
+ threads.push_back(support::make_test_thread(acquire));
+
+ threads.push_back(support::make_test_thread(release));
+
+ for (auto& thread : threads)
+ thread.join();
+ }
+
+ return 0;
+}
>From dfd86fdc9c990bf32a74c532097a54758806138a Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Wed, 31 Jan 2024 16:17:28 +0000
Subject: [PATCH 2/6] address feedback
---
libcxx/include/__atomic/atomic_sync.h | 38 ++++++++++++++++-----------
libcxx/include/semaphore | 8 +++---
2 files changed, 28 insertions(+), 18 deletions(-)
diff --git a/libcxx/include/__atomic/atomic_sync.h b/libcxx/include/__atomic/atomic_sync.h
index ba83396189edf..e1994ddde86c1 100644
--- a/libcxx/include/__atomic/atomic_sync.h
+++ b/libcxx/include/__atomic/atomic_sync.h
@@ -43,17 +43,17 @@ __libcpp_atomic_monitor(__cxx_atomic_contention_t const volatile*);
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void
__libcpp_atomic_wait(__cxx_atomic_contention_t const volatile*, __cxx_contention_t);
-template <class _Atp, class _Fn>
+template <class _Atp, class _BackoffTest>
struct __libcpp_atomic_wait_backoff_impl {
- _Atp* __a;
- _Fn __test_with_old;
+ _Atp* __a_;
+ _BackoffTest __backoff_test_;
_LIBCPP_AVAILABILITY_SYNC
_LIBCPP_HIDE_FROM_ABI bool operator()(chrono::nanoseconds __elapsed) const {
if (__elapsed > chrono::microseconds(64)) {
- auto __monitor = std::__libcpp_atomic_monitor(__a);
- if (__test_with_old(__monitor))
+ auto __monitor = std::__libcpp_atomic_monitor(__a_);
+ if (__backoff_test_(__monitor))
return true;
- std::__libcpp_atomic_wait(__a, __monitor);
+ std::__libcpp_atomic_wait(__a_, __monitor);
} else if (__elapsed > chrono::microseconds(4))
__libcpp_thread_yield();
else {
@@ -62,18 +62,26 @@ struct __libcpp_atomic_wait_backoff_impl {
}
};
-template <class _Atp, class _Fn, class _Fn2>
+template <class _Atp, class _Poll, class _BackoffTest>
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool
-__cxx_atomic_wait(_Atp* __a, _Fn&& __test_fn, _Fn2&& __test_with_old) {
- __libcpp_atomic_wait_backoff_impl<_Atp, __decay_t<_Fn2> > __backoff_fn = {__a, __test_with_old};
- return std::__libcpp_thread_poll_with_backoff(__test_fn, __backoff_fn);
+__cxx_atomic_wait(_Atp* __a, _Poll&& __poll, _BackoffTest&& __backoff_test) {
+ __libcpp_atomic_wait_backoff_impl<_Atp, __decay_t<_BackoffTest> > __backoff_fn = {__a, __backoff_test};
+ return std::__libcpp_thread_poll_with_backoff(__poll, __backoff_fn);
}
-template <class _Atp, class _Fn>
-_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_wait(_Atp* __a, _Fn&& __test_fn) {
- auto __test_with_old = [&](auto&) { return __test_fn(); };
- __libcpp_atomic_wait_backoff_impl<_Atp, decltype(__test_with_old)> __backoff_fn{__a, __test_with_old};
- return std::__libcpp_thread_poll_with_backoff(__test_fn, __backoff_fn);
+template <class _Poll>
+struct __libcpp_atomic_wait_poll_as_backoff_test {
+ _Poll __poll_;
+
+ _LIBCPP_AVAILABILITY_SYNC
+ _LIBCPP_HIDE_FROM_ABI bool operator()(__cxx_contention_t&) const { return __poll_(); }
+};
+
+template <class _Atp, class _Poll>
+_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_wait(_Atp* __a, _Poll&& __poll) {
+ __libcpp_atomic_wait_backoff_impl<_Atp, __libcpp_atomic_wait_poll_as_backoff_test<_Poll&> > __backoff_fn = {
+ __a, {__poll}};
+ return std::__libcpp_thread_poll_with_backoff(__poll, __backoff_fn);
}
#else // _LIBCPP_HAS_NO_THREADS
diff --git a/libcxx/include/semaphore b/libcxx/include/semaphore
index c4d9ee1ab63e8..2b317daa7fead 100644
--- a/libcxx/include/semaphore
+++ b/libcxx/include/semaphore
@@ -95,9 +95,11 @@ public:
auto __old = __a_.fetch_add(__update, memory_order_release);
_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
__update <= _LIBCPP_SEMAPHORE_MAX - __old, "update is greater than the expected value");
-
- if (__old == 0) {
+ (void)__old;
+ if (__update > 1) {
__a_.notify_all();
+ } else {
+ __a_.notify_one();
}
}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void acquire() {
@@ -127,7 +129,7 @@ public:
}
private:
- _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY bool __try_acquire_impl(ptrdiff_t& __old) {
+ _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool __try_acquire_impl(ptrdiff_t& __old) {
while (true) {
if (__old == 0)
return false;
>From 817e8c9b78bdb82808814f457a153a81c7c38416 Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Wed, 31 Jan 2024 22:26:32 +0000
Subject: [PATCH 3/6] rename
---
libcxx/include/semaphore | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/libcxx/include/semaphore b/libcxx/include/semaphore
index 2b317daa7fead..5fd06ed09e4df 100644
--- a/libcxx/include/semaphore
+++ b/libcxx/include/semaphore
@@ -103,25 +103,25 @@ public:
}
}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void acquire() {
- auto const __test_fn = [this]() -> bool {
+ auto const __poll_fn = [this]() -> bool {
auto __old = __a_.load(memory_order_relaxed);
return (__old != 0) && __a_.compare_exchange_strong(__old, __old - 1, memory_order_acquire, memory_order_relaxed);
};
- auto const __test_with_old = [this](__cxx_contention_t& __monitor) -> bool {
+ auto const __backoff_test = [this](__cxx_contention_t& __monitor) -> bool {
ptrdiff_t __old = __monitor;
bool __r = __try_acquire_impl(__old);
__monitor = static_cast<__cxx_contention_t>(__old);
return __r;
};
- __cxx_atomic_wait(&__a_.__a_, __test_fn, __test_with_old);
+ __cxx_atomic_wait(&__a_.__a_, __poll_fn, __backoff_test);
}
template <class _Rep, class _Period>
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool
try_acquire_for(chrono::duration<_Rep, _Period> const& __rel_time) {
if (__rel_time == chrono::duration<_Rep, _Period>::zero())
return try_acquire();
- auto const __test_fn = [this]() { return try_acquire(); };
- return std::__libcpp_thread_poll_with_backoff(__test_fn, __libcpp_timed_backoff_policy(), __rel_time);
+ auto const __poll_fn = [this]() { return try_acquire(); };
+ return std::__libcpp_thread_poll_with_backoff(__poll_fn, __libcpp_timed_backoff_policy(), __rel_time);
}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool try_acquire() {
auto __old = __a_.load(memory_order_acquire);
>From 90dc01242b24c0483e59cdd0803ca51dfab7ef67 Mon Sep 17 00:00:00 2001
From: Hui <hui.xie0621 at gmail.com>
Date: Sat, 3 Feb 2024 13:36:50 +0000
Subject: [PATCH 4/6] CI
---
libcxx/include/semaphore | 5 +----
libcxx/test/std/thread/thread.semaphore/lost_wakeup.pass.cpp | 5 ++---
2 files changed, 3 insertions(+), 7 deletions(-)
diff --git a/libcxx/include/semaphore b/libcxx/include/semaphore
index 5fd06ed09e4df..5235d720bf6fe 100644
--- a/libcxx/include/semaphore
+++ b/libcxx/include/semaphore
@@ -95,11 +95,8 @@ public:
auto __old = __a_.fetch_add(__update, memory_order_release);
_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
__update <= _LIBCPP_SEMAPHORE_MAX - __old, "update is greater than the expected value");
- (void)__old;
- if (__update > 1) {
+ if (__old == 0) {
__a_.notify_all();
- } else {
- __a_.notify_one();
}
}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void acquire() {
diff --git a/libcxx/test/std/thread/thread.semaphore/lost_wakeup.pass.cpp b/libcxx/test/std/thread/thread.semaphore/lost_wakeup.pass.cpp
index aa21e93221b31..dca3c01cf0103 100644
--- a/libcxx/test/std/thread/thread.semaphore/lost_wakeup.pass.cpp
+++ b/libcxx/test/std/thread/thread.semaphore/lost_wakeup.pass.cpp
@@ -6,11 +6,10 @@
//
//===----------------------------------------------------------------------===//
-// UNSUPPORTED: libcpp-has-no-threads
+// UNSUPPORTED: no-threads
// UNSUPPORTED: c++03, c++11, c++14, c++17
-// This test requires the dylib support introduced in D68480, which shipped in macOS 11.0.
-// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12|13|14|15}}
+// XFAIL: availability-synchronization_library-missing
// This is a regression test for https://llvm.org/PR47013.
>From f9234755b437e6de6848288c957da588fb843777 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Sun, 4 Feb 2024 13:43:19 +0100
Subject: [PATCH 5/6] refactor the predicate taking variant of
'__cxx_atomic_wait'
---
libcxx/include/__atomic/atomic_sync.h | 101 +++++++++++++++++---------
libcxx/include/latch | 11 ++-
libcxx/include/semaphore | 17 +----
libcxx/src/atomic.cpp | 1 +
4 files changed, 80 insertions(+), 50 deletions(-)
diff --git a/libcxx/include/__atomic/atomic_sync.h b/libcxx/include/__atomic/atomic_sync.h
index e1994ddde86c1..1eca545afb99f 100644
--- a/libcxx/include/__atomic/atomic_sync.h
+++ b/libcxx/include/__atomic/atomic_sync.h
@@ -43,15 +43,53 @@ __libcpp_atomic_monitor(__cxx_atomic_contention_t const volatile*);
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void
__libcpp_atomic_wait(__cxx_atomic_contention_t const volatile*, __cxx_contention_t);
-template <class _Atp, class _BackoffTest>
+template <class _Atp, class _Poll>
+struct __libcpp_atomic_wait_poll_impl {
+ _Atp* __a_;
+ _Poll __poll_;
+ memory_order __order_;
+
+ _LIBCPP_AVAILABILITY_SYNC
+ _LIBCPP_HIDE_FROM_ABI bool operator()() const {
+ auto __current_val = __cxx_atomic_load(__a_, __order_);
+ return __poll_(__current_val);
+ }
+};
+
+template <class _Atp, class _Poll>
struct __libcpp_atomic_wait_backoff_impl {
_Atp* __a_;
- _BackoffTest __backoff_test_;
+ _Poll __poll_;
+ memory_order __order_;
+
+ _LIBCPP_AVAILABILITY_SYNC
+ _LIBCPP_HIDE_FROM_ABI bool
+ __poll_or_get_monitor(__cxx_atomic_contention_t const volatile*, __cxx_contention_t& __monitor) const {
+ // In case the atomic can be waited on directly, the monitor value is just
+ // the value of the atomic.
+ // `__poll_` takes the current value of the atomic as an in-out argument
+ // to potentially modify it. After it returns, `__monitor` has a value
+ // which can be safely waited on by `std::__libcpp_atomic_wait` without any
+ // ABA style issues.
+ __monitor = __cxx_atomic_load(__a_, __order_);
+ return __poll_(__monitor);
+ }
+
+ _LIBCPP_AVAILABILITY_SYNC
+ _LIBCPP_HIDE_FROM_ABI bool __poll_or_get_monitor(void const volatile*, __cxx_contention_t& __monitor) const {
+ // In case we must wait on an atomic from the pool, the monitor comes from
+ // `std::__libcpp_atomic_monitor`.
+ // Only then we may read from `__a_`. This is the "event count" pattern.
+ __monitor = std::__libcpp_atomic_monitor(__a_);
+ auto __current_val = __cxx_atomic_load(__a_, __order_);
+ return __poll_(__current_val);
+ }
+
_LIBCPP_AVAILABILITY_SYNC
_LIBCPP_HIDE_FROM_ABI bool operator()(chrono::nanoseconds __elapsed) const {
if (__elapsed > chrono::microseconds(64)) {
- auto __monitor = std::__libcpp_atomic_monitor(__a_);
- if (__backoff_test_(__monitor))
+ __cxx_contention_t __monitor;
+ if (__poll_or_get_monitor(__a_, __monitor))
return true;
std::__libcpp_atomic_wait(__a_, __monitor);
} else if (__elapsed > chrono::microseconds(4))
@@ -62,26 +100,20 @@ struct __libcpp_atomic_wait_backoff_impl {
}
};
-template <class _Atp, class _Poll, class _BackoffTest>
-_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool
-__cxx_atomic_wait(_Atp* __a, _Poll&& __poll, _BackoffTest&& __backoff_test) {
- __libcpp_atomic_wait_backoff_impl<_Atp, __decay_t<_BackoffTest> > __backoff_fn = {__a, __backoff_test};
- return std::__libcpp_thread_poll_with_backoff(__poll, __backoff_fn);
-}
-
-template <class _Poll>
-struct __libcpp_atomic_wait_poll_as_backoff_test {
- _Poll __poll_;
-
- _LIBCPP_AVAILABILITY_SYNC
- _LIBCPP_HIDE_FROM_ABI bool operator()(__cxx_contention_t&) const { return __poll_(); }
-};
-
+// The semantics of this function are similar to `atomic`'s
+// `.wait(T old, std::memory_order order)`, but instead of having a hardcoded
+// predicate (is the loaded value unequal to `old`?), the predicate function is
+// specified as an argument. The loaded value is given as an in-out argument to
+// the predicate. If the predicate function returns `true`,
+// `_cxx_atomic_wait_fn` will return. If the predicate function returns
+// `false`, it must set the argument to its current understanding of the atomic
+// value. The predicate function must not return `false` spuriously.
template <class _Atp, class _Poll>
-_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_wait(_Atp* __a, _Poll&& __poll) {
- __libcpp_atomic_wait_backoff_impl<_Atp, __libcpp_atomic_wait_poll_as_backoff_test<_Poll&> > __backoff_fn = {
- __a, {__poll}};
- return std::__libcpp_thread_poll_with_backoff(__poll, __backoff_fn);
+_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void
+__cxx_atomic_wait_fn(_Atp* __a, _Poll&& __poll, memory_order __order) {
+ __libcpp_atomic_wait_poll_impl<_Atp, __decay_t<_Poll> > __poll_fn = {__a, __poll, __order};
+ __libcpp_atomic_wait_backoff_impl<_Atp, __decay_t<_Poll> > __backoff_fn = {__a, __poll, __order};
+ (void)std::__libcpp_thread_poll_with_backoff(__poll_fn, __backoff_fn);
}
#else // _LIBCPP_HAS_NO_THREADS
@@ -90,9 +122,10 @@ template <class _Tp>
_LIBCPP_HIDE_FROM_ABI void __cxx_atomic_notify_all(__cxx_atomic_impl<_Tp> const volatile*) {}
template <class _Tp>
_LIBCPP_HIDE_FROM_ABI void __cxx_atomic_notify_one(__cxx_atomic_impl<_Tp> const volatile*) {}
-template <class _Atp, class _Fn>
-_LIBCPP_HIDE_FROM_ABI bool __cxx_atomic_wait(_Atp*, _Fn&& __test_fn) {
- return std::__libcpp_thread_poll_with_backoff(__test_fn, __spinning_backoff_policy());
+template <class _Atp, class _Poll>
+_LIBCPP_HIDE_FROM_ABI void __cxx_atomic_wait_fn(_Atp*, _Poll&& __poll, memory_order __order) {
+ __libcpp_atomic_wait_poll_impl<_Atp, __decay_t<_Poll> > __poll_fn = {__a, __poll, __order};
+ (void)std::__libcpp_thread_poll_with_backoff(__poll_fn, __spinning_backoff_policy());
}
#endif // _LIBCPP_HAS_NO_THREADS
@@ -102,21 +135,19 @@ _LIBCPP_HIDE_FROM_ABI bool __cxx_nonatomic_compare_equal(_Tp const& __lhs, _Tp c
return std::memcmp(std::addressof(__lhs), std::addressof(__rhs), sizeof(_Tp)) == 0;
}
-template <class _Atp, class _Tp>
-struct __cxx_atomic_wait_test_fn_impl {
- _Atp* __a;
+template <class _Tp>
+struct __cxx_atomic_wait_poll_fn_impl {
_Tp __val;
- memory_order __order;
- _LIBCPP_HIDE_FROM_ABI bool operator()() const {
- return !std::__cxx_nonatomic_compare_equal(std::__cxx_atomic_load(__a, __order), __val);
+ _LIBCPP_HIDE_FROM_ABI bool operator()(_Tp& __current_val) const {
+ return !std::__cxx_nonatomic_compare_equal(__current_val, __val);
}
};
template <class _Atp, class _Tp>
-_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool
+_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void
__cxx_atomic_wait(_Atp* __a, _Tp const __val, memory_order __order) {
- __cxx_atomic_wait_test_fn_impl<_Atp, _Tp> __test_fn = {__a, __val, __order};
- return std::__cxx_atomic_wait(__a, __test_fn);
+ __cxx_atomic_wait_poll_fn_impl<_Tp> __poll_fn = {__val};
+ std::__cxx_atomic_wait_fn(__a, __poll_fn, __order);
}
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/latch b/libcxx/include/latch
index ad7b35579913b..45c1b5c91e6cd 100644
--- a/libcxx/include/latch
+++ b/libcxx/include/latch
@@ -97,9 +97,13 @@ public:
if (__old == __update)
__a_.notify_all();
}
- inline _LIBCPP_HIDE_FROM_ABI bool try_wait() const noexcept { return 0 == __a_.load(memory_order_acquire); }
+ inline _LIBCPP_HIDE_FROM_ABI bool try_wait() const noexcept {
+ auto __value = __a_.load(memory_order_acquire);
+ return try_wait_impl(__value);
+ }
inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void wait() const {
- __cxx_atomic_wait(&__a_.__a_, [this]() -> bool { return try_wait(); });
+ __cxx_atomic_wait_fn(
+ &__a_.__a_, [this](ptrdiff_t& __value) -> bool { return try_wait_impl(__value); }, memory_order_acquire);
}
inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void arrive_and_wait(ptrdiff_t __update = 1) {
_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__update >= 0, "latch::arrive_and_wait called with a negative value");
@@ -108,6 +112,9 @@ public:
count_down(__update);
wait();
}
+
+private:
+ inline _LIBCPP_HIDE_FROM_ABI bool try_wait_impl(ptrdiff_t& __value) const noexcept { return __value == 0; }
};
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/semaphore b/libcxx/include/semaphore
index 5235d720bf6fe..27e5951e7d982 100644
--- a/libcxx/include/semaphore
+++ b/libcxx/include/semaphore
@@ -100,17 +100,8 @@ public:
}
}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void acquire() {
- auto const __poll_fn = [this]() -> bool {
- auto __old = __a_.load(memory_order_relaxed);
- return (__old != 0) && __a_.compare_exchange_strong(__old, __old - 1, memory_order_acquire, memory_order_relaxed);
- };
- auto const __backoff_test = [this](__cxx_contention_t& __monitor) -> bool {
- ptrdiff_t __old = __monitor;
- bool __r = __try_acquire_impl(__old);
- __monitor = static_cast<__cxx_contention_t>(__old);
- return __r;
- };
- __cxx_atomic_wait(&__a_.__a_, __poll_fn, __backoff_test);
+ __cxx_atomic_wait_fn(
+ &__a_.__a_, [this](ptrdiff_t& __old) { return __try_acquire_impl(__old); }, memory_order_relaxed);
}
template <class _Rep, class _Period>
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool
@@ -121,7 +112,7 @@ public:
return std::__libcpp_thread_poll_with_backoff(__poll_fn, __libcpp_timed_backoff_policy(), __rel_time);
}
_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool try_acquire() {
- auto __old = __a_.load(memory_order_acquire);
+ auto __old = __a_.load(memory_order_relaxed);
return __try_acquire_impl(__old);
}
@@ -130,7 +121,7 @@ private:
while (true) {
if (__old == 0)
return false;
- if (__a_.compare_exchange_strong(__old, __old - 1, memory_order_acquire, memory_order_relaxed))
+ if (__a_.compare_exchange_weak(__old, __old - 1, memory_order_acquire, memory_order_relaxed))
return true;
}
}
diff --git a/libcxx/src/atomic.cpp b/libcxx/src/atomic.cpp
index 2f0389ae6974a..2b67685c8a0a1 100644
--- a/libcxx/src/atomic.cpp
+++ b/libcxx/src/atomic.cpp
@@ -178,6 +178,7 @@ _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_one(__cxx_atomic_contention_t
_LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_all(__cxx_atomic_contention_t const volatile* __location) {
__libcpp_contention_notify(&__libcpp_contention_state(__location)->__contention_state, __location, false);
}
+// This function is never used, but still exported for ABI compatibility.
_LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t
__libcpp_atomic_monitor(__cxx_atomic_contention_t const volatile* __location) {
return __libcpp_contention_monitor_for_wait(&__libcpp_contention_state(__location)->__contention_state, __location);
>From fcb5679c21f0d37ce9875b90ea55fde61a411607 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kokem=C3=BCller?= <jan.kokemueller at gmail.com>
Date: Sun, 4 Feb 2024 14:39:47 +0100
Subject: [PATCH 6/6] remove unneeded include of '__atomic/contention_t.h'
---
libcxx/include/semaphore | 1 -
1 file changed, 1 deletion(-)
diff --git a/libcxx/include/semaphore b/libcxx/include/semaphore
index 27e5951e7d982..ae5af24e99e32 100644
--- a/libcxx/include/semaphore
+++ b/libcxx/include/semaphore
@@ -54,7 +54,6 @@ using binary_semaphore = counting_semaphore<1>;
#include <__assert> // all public C++ headers provide the assertion handler
#include <__atomic/atomic_base.h>
#include <__atomic/atomic_sync.h>
-#include <__atomic/contention_t.h>
#include <__atomic/memory_order.h>
#include <__availability>
#include <__chrono/time_point.h>
More information about the libcxx-commits
mailing list