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