138 lines · plain
1// -*- C++ -*-2//===----------------------------------------------------------------------===//3//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-exception7//8//===----------------------------------------------------------------------===//9 10#ifndef _LIBCPP_LATCH11#define _LIBCPP_LATCH12 13/*14 latch synopsis15 16namespace std17{18 19 class latch // since C++2020 {21 public:22 static constexpr ptrdiff_t max() noexcept;23 24 constexpr explicit latch(ptrdiff_t __expected);25 ~latch();26 27 latch(const latch&) = delete;28 latch& operator=(const latch&) = delete;29 30 void count_down(ptrdiff_t __update = 1);31 bool try_wait() const noexcept;32 void wait() const;33 void arrive_and_wait(ptrdiff_t __update = 1);34 35 private:36 ptrdiff_t __counter; // exposition only37 };38 39}40 41*/42 43#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)44# include <__cxx03/__config>45#else46# include <__config>47 48# if _LIBCPP_HAS_THREADS49 50# include <__assert>51# include <__atomic/atomic.h>52# include <__atomic/atomic_sync.h>53# include <__atomic/memory_order.h>54# include <__cstddef/ptrdiff_t.h>55# include <limits>56# include <version>57 58# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)59# pragma GCC system_header60# endif61 62_LIBCPP_PUSH_MACROS63# include <__undef_macros>64 65# if _LIBCPP_STD_VER >= 2066 67_LIBCPP_BEGIN_NAMESPACE_STD68 69class latch {70 atomic<ptrdiff_t> __a_;71 72public:73 [[nodiscard]] static _LIBCPP_HIDE_FROM_ABI constexpr ptrdiff_t max() noexcept {74 return numeric_limits<ptrdiff_t>::max();75 }76 77 inline _LIBCPP_HIDE_FROM_ABI constexpr explicit latch(ptrdiff_t __expected) : __a_(__expected) {78 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(79 __expected >= 0,80 "latch::latch(ptrdiff_t): latch cannot be "81 "initialized with a negative value");82 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(83 __expected <= max(),84 "latch::latch(ptrdiff_t): latch cannot be "85 "initialized with a value greater than max()");86 }87 88 _LIBCPP_HIDE_FROM_ABI ~latch() = default;89 latch(const latch&) = delete;90 latch& operator=(const latch&) = delete;91 92 inline _LIBCPP_HIDE_FROM_ABI void count_down(ptrdiff_t __update = 1) {93 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__update >= 0, "latch::count_down called with a negative value");94 auto const __old = __a_.fetch_sub(__update, memory_order_release);95 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(96 __update <= __old,97 "latch::count_down called with a value greater "98 "than the internal counter");99 if (__old == __update)100 __a_.notify_all();101 }102 [[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool try_wait() const noexcept {103 auto __value = __a_.load(memory_order_acquire);104 return try_wait_impl(__value);105 }106 inline _LIBCPP_HIDE_FROM_ABI void wait() const {107 std::__atomic_wait_unless(__a_, memory_order_acquire, [this](ptrdiff_t& __value) -> bool {108 return try_wait_impl(__value);109 });110 }111 inline _LIBCPP_HIDE_FROM_ABI void arrive_and_wait(ptrdiff_t __update = 1) {112 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__update >= 0, "latch::arrive_and_wait called with a negative value");113 // other preconditions on __update are checked in count_down()114 115 count_down(__update);116 wait();117 }118 119private:120 _LIBCPP_HIDE_FROM_ABI bool try_wait_impl(ptrdiff_t& __value) const noexcept { return __value == 0; }121};122 123_LIBCPP_END_NAMESPACE_STD124 125# endif // _LIBCPP_STD_VER >= 20126 127_LIBCPP_POP_MACROS128 129# endif // _LIBCPP_HAS_THREADS130 131# if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20132# include <atomic>133# include <cstddef>134# endif135#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)136 137#endif // _LIBCPP_LATCH138