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 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#ifdef _LIBCPP_HAS_NO_THREADS 46# error "<latch> is not supported since libc++ has been configured without support for threads." 47#endif 48 49#include <__assert> // all public C++ headers provide the assertion handler 50#include <__atomic/atomic_base.h> 51#include <__atomic/atomic_sync.h> 52#include <__atomic/memory_order.h> 53#include <__availability> 54#include <cstddef> 55#include <limits> 56#include <version> 57 58#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 59# pragma GCC system_header 60#endif 61 62_LIBCPP_PUSH_MACROS 63#include <__undef_macros> 64 65#if _LIBCPP_STD_VER >= 14 66 67_LIBCPP_BEGIN_NAMESPACE_STD 68 69class latch { 70 __atomic_base<ptrdiff_t> __a_; 71 72public: 73 static _LIBCPP_HIDE_FROM_ABI constexpr ptrdiff_t max() noexcept { return numeric_limits<ptrdiff_t>::max(); } 74 75 inline _LIBCPP_HIDE_FROM_ABI constexpr explicit latch(ptrdiff_t __expected) : __a_(__expected) { 76 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( 77 __expected >= 0, 78 "latch::latch(ptrdiff_t): latch cannot be " 79 "initialized with a negative value"); 80 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( 81 __expected <= max(), 82 "latch::latch(ptrdiff_t): latch cannot be " 83 "initialized with a value greater than max()"); 84 } 85 86 _LIBCPP_HIDE_FROM_ABI ~latch() = default; 87 latch(const latch&) = delete; 88 latch& operator=(const latch&) = delete; 89 90 inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void count_down(ptrdiff_t __update = 1) { 91 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__update >= 0, "latch::count_down called with a negative value"); 92 auto const __old = __a_.fetch_sub(__update, memory_order_release); 93 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( 94 __update <= __old, 95 "latch::count_down called with a value greater " 96 "than the internal counter"); 97 if (__old == __update) 98 __a_.notify_all(); 99 } 100 inline _LIBCPP_HIDE_FROM_ABI bool try_wait() const noexcept { return 0 == __a_.load(memory_order_acquire); } 101 inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void wait() const { 102 __cxx_atomic_wait(&__a_.__a_, [this]() -> bool { return try_wait(); }); 103 } 104 inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void arrive_and_wait(ptrdiff_t __update = 1) { 105 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__update >= 0, "latch::arrive_and_wait called with a negative value"); 106 // other preconditions on __update are checked in count_down() 107 108 count_down(__update); 109 wait(); 110 } 111}; 112 113_LIBCPP_END_NAMESPACE_STD 114 115#endif // _LIBCPP_STD_VER >= 14 116 117_LIBCPP_POP_MACROS 118 119#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20 120# include <atomic> 121#endif 122 123#endif //_LIBCPP_LATCH 124