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 <__availability>
45#include <__config>
46#include <atomic>
47#include <limits>
48#include <version>
49
50#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
51#  pragma GCC system_header
52#endif
53
54#ifdef _LIBCPP_HAS_NO_THREADS
55# error "<latch> is not supported since libc++ has been configured without support for threads."
56#endif
57
58_LIBCPP_PUSH_MACROS
59#include <__undef_macros>
60
61#if _LIBCPP_STD_VER >= 14
62
63_LIBCPP_BEGIN_NAMESPACE_STD
64
65class latch
66{
67    __atomic_base<ptrdiff_t> __a;
68
69public:
70    static constexpr ptrdiff_t max() noexcept {
71        return numeric_limits<ptrdiff_t>::max();
72    }
73
74    inline _LIBCPP_INLINE_VISIBILITY
75    constexpr explicit latch(ptrdiff_t __expected) : __a(__expected) { }
76
77    ~latch() = default;
78    latch(const latch&) = delete;
79    latch& operator=(const latch&) = delete;
80
81    inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
82    void count_down(ptrdiff_t __update = 1)
83    {
84        auto const __old = __a.fetch_sub(__update, memory_order_release);
85        if(__old == __update)
86            __a.notify_all();
87    }
88    inline _LIBCPP_INLINE_VISIBILITY
89    bool try_wait() const noexcept
90    {
91        return 0 == __a.load(memory_order_acquire);
92    }
93    inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
94    void wait() const
95    {
96        __cxx_atomic_wait(&__a.__a_, [&]() -> bool {
97            return try_wait();
98        });
99    }
100    inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
101    void arrive_and_wait(ptrdiff_t __update = 1)
102    {
103        count_down(__update);
104        wait();
105    }
106};
107
108_LIBCPP_END_NAMESPACE_STD
109
110#endif // _LIBCPP_STD_VER >= 14
111
112_LIBCPP_POP_MACROS
113
114#endif //_LIBCPP_LATCH
115