xref: /freebsd/contrib/llvm-project/libcxx/include/latch (revision b64c5a0ace59af62eff52bfe110a521dc73c937b)
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#if !defined(_LIBCPP_HAS_NO_THREADS)
46
47#  include <__assert>
48#  include <__atomic/atomic_base.h>
49#  include <__atomic/atomic_sync.h>
50#  include <__atomic/memory_order.h>
51#  include <cstddef>
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 >= 14
63
64_LIBCPP_BEGIN_NAMESPACE_STD
65
66class _LIBCPP_DEPRECATED_ATOMIC_SYNC latch {
67  __atomic_base<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(
103        __a_, [this](ptrdiff_t& __value) -> bool { return try_wait_impl(__value); }, memory_order_acquire);
104  }
105  inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void arrive_and_wait(ptrdiff_t __update = 1) {
106    _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__update >= 0, "latch::arrive_and_wait called with a negative value");
107    // other preconditions on __update are checked in count_down()
108
109    count_down(__update);
110    wait();
111  }
112
113private:
114  _LIBCPP_HIDE_FROM_ABI bool try_wait_impl(ptrdiff_t& __value) const noexcept { return __value == 0; }
115};
116
117_LIBCPP_END_NAMESPACE_STD
118
119#  endif // _LIBCPP_STD_VER >= 14
120
121_LIBCPP_POP_MACROS
122
123#endif // !defined(_LIBCPP_HAS_NO_THREADS)
124
125#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
126#  include <atomic>
127#endif
128
129#endif //_LIBCPP_LATCH
130