From 184b9839440e63c4074634668fdea1809c6a29a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teodor=20Sp=C3=A6ren?= Date: Wed, 10 Apr 2024 12:11:50 +0200 Subject: [PATCH 2/4] Add atomic waits to atomic_flag --- libstdc++-v3/include/bits/atomic_base.h | 111 +++++++++++++++++++++--- 1 file changed, 100 insertions(+), 11 deletions(-) diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h index 3e12cc917b5..8a2ed65eaf2 100644 --- a/libstdc++-v3/include/bits/atomic_base.h +++ b/libstdc++-v3/include/bits/atomic_base.h @@ -280,16 +280,104 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION notify_all() noexcept { std::__atomic_notify_address(&_M_i, true); } - _GLIBCXX_ALWAYS_INLINE bool - wait_value(bool __old, + template requires std::predicate<__Pred, bool> + _GLIBCXX_ALWAYS_INLINE bool + wait_with_predicate(__Pred &&__stop_waiting, + memory_order __m = memory_order_seq_cst) const { + bool __ret; + std::__atomic_wait_address(&_M_i, [__m, this, &__stop_waiting, &__ret] { + __ret = this->test(__m); + return std::invoke(__stop_waiting, __ret); + }); + return __ret; + } + + template + _GLIBCXX_ALWAYS_INLINE std::optional + wait_for(bool __old, + const std::chrono::duration<__Rep, __Period> &__dur, + memory_order __m = memory_order_seq_cst) const { + // the reson for this, is that we need to ensure that the predicate + // is called, so we are sure the value has changed, and we are able to + // return it. + return this->wait_for_with_predicate([__old](const auto __cur) { + // TODO(rHermes): consider doing atomic comparisons here? + return __old != __cur; + }, __dur, __m); + } + + template + _GLIBCXX_ALWAYS_INLINE std::optional + wait_until(bool __old, + const std::chrono::time_point<__Clock, __Duration> &__deadline, + memory_order __m = memory_order_seq_cst) const { + return this->wait_until_with_predicate([__old](const auto __cur) { + // TODO(rHermes): consider doing atomic comparisons here? + return __old != __cur; + }, __deadline, __m); + } + + _GLIBCXX_ALWAYS_INLINE std::optional + try_wait(bool __old, memory_order __m = memory_order_seq_cst) const noexcept { - bool __ret; - std::__atomic_wait_address_v(&_M_i, __old, [__m, this, &__ret] { - __ret = __atomic_load_n(&_M_i, int(__m)); + // TODO(rHermes): This is really not a good default, I need to + // discuss withsomeone smarter + return wait_for(__old, std::chrono::milliseconds(10), __m); + } + + template + requires std::predicate<__Pred, bool> + _GLIBCXX_ALWAYS_INLINE std::optional wait_for_with_predicate( + __Pred &&__stop_waiting, + const std::chrono::duration<__Rep, __Period> &__dur, + memory_order __m = memory_order_seq_cst) const { + bool __ret; + auto __succeeded = std::__atomic_wait_address_for( + &_M_i, + [__m, this, &__stop_waiting, &__ret] { + __ret = this->test(__m); + return std::invoke(__stop_waiting, __ret); + }, + __dur); + + if (!__succeeded) + return std::nullopt; + return __ret; - }); - return __ret; - } + } + + template + requires std::predicate<__Pred, bool> + _GLIBCXX_ALWAYS_INLINE std::optional + try_wait_with_predicate(__Pred &&__stop_waiting, + memory_order __m = memory_order_seq_cst) const { + + // TODO(rHermes): This needs to be changed out with an actual good value. + return wait_for_with_predicate(std::forward<__Pred>(__stop_waiting), + std::chrono::milliseconds(10), __m); + } + + template + requires std::predicate<__Pred, bool> + _GLIBCXX_ALWAYS_INLINE std::optional + wait_until_with_predicate( + __Pred &&__stop_waiting, + const std::chrono::time_point<__Clock, __Duration> &__deadline, + memory_order __m = memory_order_seq_cst) const { + bool __ret; + auto __succeeded = std::__atomic_wait_address_until( + &_M_i, + [__m, this, &__stop_waiting, &__ret] { + __ret = this->test(__m); + return std::invoke(__stop_waiting, __ret); + }, + __deadline); + + if (!__succeeded) + return std::nullopt; + + return __ret; + } // TODO add const volatile overload #endif // __glibcxx_atomic_wait @@ -694,7 +782,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template - requires std::predicate<__Pred, __int_type> + requires std::predicate<__Pred, __int_type> _GLIBCXX_ALWAYS_INLINE std::optional<__int_type> wait_for_with_predicate( __Pred &&__stop_waiting, const std::chrono::duration<__Rep, __Period> &__dur, @@ -714,7 +802,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __ret; } - template requires std::predicate<__Pred, __int_type> + template + requires std::predicate<__Pred, __int_type> _GLIBCXX_ALWAYS_INLINE std::optional<__int_type> try_wait_with_predicate(__Pred &&__stop_waiting, memory_order __m = memory_order_seq_cst) const { @@ -723,7 +812,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template - requires std::predicate<__Pred, __int_type> + requires std::predicate<__Pred, __int_type> _GLIBCXX_ALWAYS_INLINE std::optional<__int_type> wait_until_with_predicate( __Pred &&__stop_waiting, -- 2.44.0