2 //===----------------------------------------------------------------------===//
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8 //===----------------------------------------------------------------------===//
19 class latch // since C++20
22 static constexpr ptrdiff_t max() noexcept;
24 constexpr explicit latch(ptrdiff_t __expected);
27 latch(const latch&) = delete;
28 latch& operator=(const latch&) = delete;
30 void count_down(ptrdiff_t __update = 1);
31 bool try_wait() const noexcept;
33 void arrive_and_wait(ptrdiff_t __update = 1);
36 ptrdiff_t __counter; // exposition only
45 #if _LIBCPP_HAS_THREADS
48 # include <__atomic/atomic.h>
49 # include <__atomic/atomic_sync.h>
50 # include <__atomic/memory_order.h>
51 # include <__cstddef/ptrdiff_t.h>
55 # if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
56 # pragma GCC system_header
60 # include <__undef_macros>
62 # if _LIBCPP_STD_VER >= 20
64 _LIBCPP_BEGIN_NAMESPACE_STD
67 atomic<ptrdiff_t> __a_;
70 static _LIBCPP_HIDE_FROM_ABI constexpr ptrdiff_t max() noexcept { return numeric_limits<ptrdiff_t>::max(); }
72 inline _LIBCPP_HIDE_FROM_ABI constexpr explicit latch(ptrdiff_t __expected) : __a_(__expected) {
73 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
75 "latch::latch(ptrdiff_t): latch cannot be "
76 "initialized with a negative value");
77 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
79 "latch::latch(ptrdiff_t): latch cannot be "
80 "initialized with a value greater than max()");
83 _LIBCPP_HIDE_FROM_ABI ~latch() = default;
84 latch(const latch&) = delete;
85 latch& operator=(const latch&) = delete;
87 inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void count_down(ptrdiff_t __update = 1) {
88 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__update >= 0, "latch::count_down called with a negative value");
89 auto const __old = __a_.fetch_sub(__update, memory_order_release);
90 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
92 "latch::count_down called with a value greater "
93 "than the internal counter");
94 if (__old == __update)
97 inline _LIBCPP_HIDE_FROM_ABI bool try_wait() const noexcept {
98 auto __value = __a_.load(memory_order_acquire);
99 return try_wait_impl(__value);
101 inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void wait() const {
102 std::__atomic_wait_unless(
103 __a_, [this](ptrdiff_t& __value) -> bool { return try_wait_impl(__value); }, memory_order_acquire);
105 inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void arrive_and_wait(ptrdiff_t __update = 1) {
106 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__update >= 0, "latch::arrive_and_wait called with a negative value");
107 // other preconditions on __update are checked in count_down()
109 count_down(__update);
114 _LIBCPP_HIDE_FROM_ABI bool try_wait_impl(ptrdiff_t& __value) const noexcept { return __value == 0; }
117 _LIBCPP_END_NAMESPACE_STD
119 # endif // _LIBCPP_STD_VER >= 20
123 #endif // _LIBCPP_HAS_THREADS
125 #if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
130 #endif // _LIBCPP_LATCH