From 81e2424d093148d7ba05a471d39b51e5f390aafb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teodor=20Sp=C3=A6ren?= Date: Wed, 10 Apr 2024 17:45:11 +0200 Subject: [PATCH 3/4] Add atomic wait for floating points. --- libstdc++-v3/include/bits/atomic_base.h | 107 ++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/libstdc++-v3/include/bits/atomic_base.h b/libstdc++-v3/include/bits/atomic_base.h index 8a2ed65eaf2..50037a84ed2 100644 --- a/libstdc++-v3/include/bits/atomic_base.h +++ b/libstdc++-v3/include/bits/atomic_base.h @@ -1656,6 +1656,113 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { __atomic_impl::notify_all(&_M_fp); } // TODO add const volatile overload + + _GLIBCXX_ALWAYS_INLINE _Fp + wait_value(_Fp __old, + memory_order __m = memory_order_seq_cst) const noexcept { + return this->wait_with_predicate([__old](const auto __cur) { + // TODO(rHermes): consider doing atomic comparisons here? + return __old != __cur; + }, __m); + } + + template requires std::predicate<__Pred, _Fp> + _GLIBCXX_ALWAYS_INLINE _Fp + wait_with_predicate(__Pred &&__stop_waiting, + memory_order __m = memory_order_seq_cst) const { + _Fp __ret; + std::__atomic_wait_address(&_M_fp, [__m, this, &__stop_waiting, &__ret] { + __ret = this->load(__m); + return std::invoke(__stop_waiting, __ret); + }); + return __ret; + } + + template + _GLIBCXX_ALWAYS_INLINE std::optional<_Fp> + wait_for(_Fp __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](_Fp __cur) { + // TODO(rHermes): consider doing atomic comparisons here? + return __old != __cur; + }, __dur, __m); + } + + template + _GLIBCXX_ALWAYS_INLINE std::optional<_Fp> + wait_until(_Fp __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<_Fp> + try_wait(_Fp __old, + memory_order __m = memory_order_seq_cst) const noexcept { + // 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, _Fp> + _GLIBCXX_ALWAYS_INLINE std::optional<_Fp> wait_for_with_predicate( + __Pred &&__stop_waiting, + const std::chrono::duration<__Rep, __Period> &__dur, + memory_order __m = memory_order_seq_cst) const { + _Fp __ret; + auto __succeeded = std::__atomic_wait_address_for( + &_M_fp, + [__m, this, &__stop_waiting, &__ret] { + __ret = this->load(__m); + return std::invoke(__stop_waiting, __ret); + }, + __dur); + + if (!__succeeded) + return std::nullopt; + + return __ret; + } + + template + requires std::predicate<__Pred, _Fp> + _GLIBCXX_ALWAYS_INLINE std::optional<_Fp> + try_wait_with_predicate(__Pred &&__stop_waiting, + memory_order __m = memory_order_seq_cst) const { + return wait_for_with_predicate(std::forward<__Pred>(__stop_waiting), + std::chrono::milliseconds(10), __m); + } + + template + requires std::predicate<__Pred, _Fp> + _GLIBCXX_ALWAYS_INLINE std::optional<_Fp> + wait_until_with_predicate( + __Pred &&__stop_waiting, + const std::chrono::time_point<__Clock, __Duration> &__deadline, + memory_order __m = memory_order_seq_cst) const { + _Fp __ret; + auto __succeeded = std::__atomic_wait_address_until( + &_M_fp, + [__m, this, &__stop_waiting, &__ret] { + __ret = this->load(__m); + return std::invoke(__stop_waiting, __ret); + }, + __deadline); + + if (!__succeeded) + return std::nullopt; + + return __ret; + } + #endif // __glibcxx_atomic_wait value_type -- 2.44.0