master
  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#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
 44#  include <__cxx03/__config>
 45#else
 46#  include <__config>
 47
 48#  if _LIBCPP_HAS_THREADS
 49
 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_header
 60#    endif
 61
 62_LIBCPP_PUSH_MACROS
 63#    include <__undef_macros>
 64
 65#    if _LIBCPP_STD_VER >= 20
 66
 67_LIBCPP_BEGIN_NAMESPACE_STD
 68
 69class latch {
 70  atomic<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 {
101    auto __value = __a_.load(memory_order_acquire);
102    return try_wait_impl(__value);
103  }
104  inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void wait() const {
105    std::__atomic_wait_unless(__a_, memory_order_acquire, [this](ptrdiff_t& __value) -> bool {
106      return try_wait_impl(__value);
107    });
108  }
109  inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void arrive_and_wait(ptrdiff_t __update = 1) {
110    _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__update >= 0, "latch::arrive_and_wait called with a negative value");
111    // other preconditions on __update are checked in count_down()
112
113    count_down(__update);
114    wait();
115  }
116
117private:
118  _LIBCPP_HIDE_FROM_ABI bool try_wait_impl(ptrdiff_t& __value) const noexcept { return __value == 0; }
119};
120
121_LIBCPP_END_NAMESPACE_STD
122
123#    endif // _LIBCPP_STD_VER >= 20
124
125_LIBCPP_POP_MACROS
126
127#  endif // _LIBCPP_HAS_THREADS
128
129#  if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
130#    include <atomic>
131#    include <cstddef>
132#  endif
133#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
134
135#endif // _LIBCPP_LATCH