diff options
Diffstat (limited to 'libstdc++-v3/include/std/latch')
-rw-r--r-- | libstdc++-v3/include/std/latch | 36 |
1 files changed, 27 insertions, 9 deletions
diff --git a/libstdc++-v3/include/std/latch b/libstdc++-v3/include/std/latch index cf64854..9504df0 100644 --- a/libstdc++-v3/include/std/latch +++ b/libstdc++-v3/include/std/latch @@ -62,7 +62,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr explicit latch(ptrdiff_t __expected) noexcept - : _M_a(__expected) + : _M_counter(__expected) { __glibcxx_assert(__expected >= 0 && __expected <= max()); } ~latch() = default; @@ -74,35 +74,53 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION count_down(ptrdiff_t __update = 1) { __glibcxx_assert(__update >= 0 && __update <= max()); - auto const __old = __atomic_impl::fetch_sub(&_M_a, __update, + auto const __old = __atomic_impl::fetch_sub(&_M_counter, __update, memory_order::release); if (std::cmp_equal(__old, __update)) - __atomic_impl::notify_all(&_M_a); + __atomic_impl::notify_all(&_M_counter); else __glibcxx_assert(std::cmp_less(__update, __old)); } _GLIBCXX_ALWAYS_INLINE bool try_wait() const noexcept - { return __atomic_impl::load(&_M_a, memory_order::acquire) == 0; } + { return __atomic_impl::load(&_M_counter, memory_order::acquire) == 0; } _GLIBCXX_ALWAYS_INLINE void wait() const noexcept { - auto const __pred = [this] { return this->try_wait(); }; - std::__atomic_wait_address(&_M_a, __pred); + auto const __vfn = [this] { + return __atomic_impl::load(&_M_counter, memory_order::acquire); + }; + auto const __pred = [](__detail::__platform_wait_t __v) { + return __v == 0; + }; + std::__atomic_wait_address(&_M_counter, __pred, __vfn); } _GLIBCXX_ALWAYS_INLINE void arrive_and_wait(ptrdiff_t __update = 1) noexcept { - count_down(__update); - wait(); + // The standard specifies this functions as count_down(update); wait(); + // but we combine those two calls into one and avoid the wait() if we + // know the counter reached zero. + + __glibcxx_assert(__update >= 0 && __update <= max()); + // Use acq_rel here because an omitted wait() would have used acquire: + auto const __old = __atomic_impl::fetch_sub(&_M_counter, __update, + memory_order::acq_rel); + if (std::cmp_equal(__old, __update)) + __atomic_impl::notify_all(&_M_counter); + else + { + __glibcxx_assert(std::cmp_less(__update, __old)); + wait(); + } } private: alignas(__detail::__platform_wait_alignment) - __detail::__platform_wait_t _M_a; + __detail::__platform_wait_t _M_counter; }; _GLIBCXX_END_NAMESPACE_VERSION } // namespace |