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-exception 7// 8//===----------------------------------------------------------------------===// 9 10#ifndef _LIBCPP_LATCH 11#define _LIBCPP_LATCH 12 13/* 14 latch synopsis 15 16namespace std 17{ 18 19 class latch // since C++20 20 { 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 only 37 }; 38 39} 40 41*/ 42 43#include <__config> 44 45#if _LIBCPP_HAS_THREADS 46 47# include <__assert> 48# include <__atomic/atomic.h> 49# include <__atomic/atomic_sync.h> 50# include <__atomic/memory_order.h> 51# include <__cstddef/ptrdiff_t.h> 52# include <limits> 53# include <version> 54 55# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 56# pragma GCC system_header 57# endif 58 59_LIBCPP_PUSH_MACROS 60# include <__undef_macros> 61 62# if _LIBCPP_STD_VER >= 20 63 64_LIBCPP_BEGIN_NAMESPACE_STD 65 66class latch { 67 atomic<ptrdiff_t> __a_; 68 69public: 70 static _LIBCPP_HIDE_FROM_ABI constexpr ptrdiff_t max() noexcept { return numeric_limits<ptrdiff_t>::max(); } 71 72 inline _LIBCPP_HIDE_FROM_ABI constexpr explicit latch(ptrdiff_t __expected) : __a_(__expected) { 73 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( 74 __expected >= 0, 75 "latch::latch(ptrdiff_t): latch cannot be " 76 "initialized with a negative value"); 77 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( 78 __expected <= max(), 79 "latch::latch(ptrdiff_t): latch cannot be " 80 "initialized with a value greater than max()"); 81 } 82 83 _LIBCPP_HIDE_FROM_ABI ~latch() = default; 84 latch(const latch&) = delete; 85 latch& operator=(const latch&) = delete; 86 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( 91 __update <= __old, 92 "latch::count_down called with a value greater " 93 "than the internal counter"); 94 if (__old == __update) 95 __a_.notify_all(); 96 } 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); 100 } 101 inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void wait() const { 102 std::__atomic_wait_unless(__a_, memory_order_acquire, [this](ptrdiff_t& __value) -> bool { 103 return try_wait_impl(__value); 104 }); 105 } 106 inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void arrive_and_wait(ptrdiff_t __update = 1) { 107 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__update >= 0, "latch::arrive_and_wait called with a negative value"); 108 // other preconditions on __update are checked in count_down() 109 110 count_down(__update); 111 wait(); 112 } 113 114private: 115 _LIBCPP_HIDE_FROM_ABI bool try_wait_impl(ptrdiff_t& __value) const noexcept { return __value == 0; } 116}; 117 118_LIBCPP_END_NAMESPACE_STD 119 120# endif // _LIBCPP_STD_VER >= 20 121 122_LIBCPP_POP_MACROS 123 124#endif // _LIBCPP_HAS_THREADS 125 126#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20 127# include <atomic> 128# include <cstddef> 129#endif 130 131#endif // _LIBCPP_LATCH 132