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 //===----------------------------------------------------------------------===//
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
43 #include <__assert> // all public C++ headers provide the assertion handler
44 #include <__atomic/atomic_base.h>
45 #include <__atomic/atomic_sync.h>
46 #include <__atomic/memory_order.h>
47 #include <__availability>
53 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
54 # pragma GCC system_header
57 #ifdef _LIBCPP_HAS_NO_THREADS
58 # error "<latch> is not supported since libc++ has been configured without support for threads."
62 #include <__undef_macros>
64 #if _LIBCPP_STD_VER >= 14
66 _LIBCPP_BEGIN_NAMESPACE_STD
70 __atomic_base<ptrdiff_t> __a_;
73 static _LIBCPP_HIDE_FROM_ABI constexpr ptrdiff_t max() noexcept {
74 return numeric_limits<ptrdiff_t>::max();
77 inline _LIBCPP_HIDE_FROM_ABI
78 constexpr explicit latch(ptrdiff_t __expected) : __a_(__expected)
80 _LIBCPP_ASSERT_UNCATEGORIZED(__expected >= 0,
81 "latch::latch(ptrdiff_t): latch cannot be "
82 "initialized with a negative value");
83 _LIBCPP_ASSERT_UNCATEGORIZED(__expected <= max(),
84 "latch::latch(ptrdiff_t): latch cannot be "
85 "initialized with a value greater than max()");
88 _LIBCPP_HIDE_FROM_ABI ~latch() = default;
89 latch(const latch&) = delete;
90 latch& operator=(const latch&) = delete;
92 inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI
93 void count_down(ptrdiff_t __update = 1)
95 _LIBCPP_ASSERT_UNCATEGORIZED(
96 __update >= 0, "latch::count_down called with a negative value");
97 auto const __old = __a_.fetch_sub(__update, memory_order_release);
98 _LIBCPP_ASSERT_UNCATEGORIZED(
99 __update <= __old, "latch::count_down called with a value greater "
100 "than the internal counter");
101 if (__old == __update)
104 inline _LIBCPP_HIDE_FROM_ABI
105 bool try_wait() const noexcept
107 return 0 == __a_.load(memory_order_acquire);
109 inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI
112 __cxx_atomic_wait(&__a_.__a_, [this]() -> bool {
116 inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI
117 void arrive_and_wait(ptrdiff_t __update = 1)
119 _LIBCPP_ASSERT_UNCATEGORIZED(
120 __update >= 0, "latch::arrive_and_wait called with a negative value");
121 // other preconditions on __update are checked in count_down()
123 count_down(__update);
128 _LIBCPP_END_NAMESPACE_STD
130 #endif // _LIBCPP_STD_VER >= 14
134 #if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
138 #endif //_LIBCPP_LATCH