xref: /llvm-project/libcxx/include/latch (revision b9a2658a3e8bd13b0f9e7a8a440832a95b377216)
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/latch>
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
136