xref: /openbsd-src/gnu/llvm/libcxx/include/latch (revision 4bdff4bed0e3d54e55670334c7d0077db4170f86)
1037e7968Spatrick// -*- C++ -*-
2*4bdff4beSrobert//===----------------------------------------------------------------------===//
3037e7968Spatrick//
4037e7968Spatrick// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5037e7968Spatrick// See https://llvm.org/LICENSE.txt for license information.
6037e7968Spatrick// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7037e7968Spatrick//
8037e7968Spatrick//===----------------------------------------------------------------------===//
9037e7968Spatrick
10037e7968Spatrick#ifndef _LIBCPP_LATCH
11037e7968Spatrick#define _LIBCPP_LATCH
12037e7968Spatrick
13037e7968Spatrick/*
14037e7968Spatrick    latch synopsis
15037e7968Spatrick
16037e7968Spatricknamespace std
17037e7968Spatrick{
18037e7968Spatrick
19037e7968Spatrick  class latch
20037e7968Spatrick  {
21037e7968Spatrick  public:
2276d0caaeSpatrick    static constexpr ptrdiff_t max() noexcept;
2376d0caaeSpatrick
24037e7968Spatrick    constexpr explicit latch(ptrdiff_t __expected);
25037e7968Spatrick    ~latch();
26037e7968Spatrick
27037e7968Spatrick    latch(const latch&) = delete;
28037e7968Spatrick    latch& operator=(const latch&) = delete;
29037e7968Spatrick
30037e7968Spatrick    void count_down(ptrdiff_t __update = 1);
31037e7968Spatrick    bool try_wait() const noexcept;
32037e7968Spatrick    void wait() const;
33037e7968Spatrick    void arrive_and_wait(ptrdiff_t __update = 1);
34037e7968Spatrick
35037e7968Spatrick  private:
36037e7968Spatrick    ptrdiff_t __counter; // exposition only
37037e7968Spatrick  };
38037e7968Spatrick
39037e7968Spatrick}
40037e7968Spatrick
41037e7968Spatrick*/
42037e7968Spatrick
43*4bdff4beSrobert#include <__assert> // all public C++ headers provide the assertion handler
4476d0caaeSpatrick#include <__availability>
45037e7968Spatrick#include <__config>
46037e7968Spatrick#include <atomic>
47*4bdff4beSrobert#include <limits>
48*4bdff4beSrobert#include <version>
49037e7968Spatrick
50037e7968Spatrick#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
51037e7968Spatrick#  pragma GCC system_header
52037e7968Spatrick#endif
53037e7968Spatrick
54037e7968Spatrick#ifdef _LIBCPP_HAS_NO_THREADS
55*4bdff4beSrobert# error "<latch> is not supported since libc++ has been configured without support for threads."
56037e7968Spatrick#endif
57037e7968Spatrick
5876d0caaeSpatrick_LIBCPP_PUSH_MACROS
5976d0caaeSpatrick#include <__undef_macros>
6076d0caaeSpatrick
61037e7968Spatrick#if _LIBCPP_STD_VER >= 14
62037e7968Spatrick
63037e7968Spatrick_LIBCPP_BEGIN_NAMESPACE_STD
64037e7968Spatrick
65037e7968Spatrickclass latch
66037e7968Spatrick{
67*4bdff4beSrobert    __atomic_base<ptrdiff_t> __a_;
68037e7968Spatrick
69037e7968Spatrickpublic:
70037e7968Spatrick    static constexpr ptrdiff_t max() noexcept {
71037e7968Spatrick        return numeric_limits<ptrdiff_t>::max();
72037e7968Spatrick    }
73037e7968Spatrick
74037e7968Spatrick    inline _LIBCPP_INLINE_VISIBILITY
75*4bdff4beSrobert    constexpr explicit latch(ptrdiff_t __expected) : __a_(__expected) { }
76037e7968Spatrick
77037e7968Spatrick    ~latch() = default;
78037e7968Spatrick    latch(const latch&) = delete;
79037e7968Spatrick    latch& operator=(const latch&) = delete;
80037e7968Spatrick
81037e7968Spatrick    inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
82037e7968Spatrick    void count_down(ptrdiff_t __update = 1)
83037e7968Spatrick    {
84*4bdff4beSrobert        auto const __old = __a_.fetch_sub(__update, memory_order_release);
85037e7968Spatrick        if(__old == __update)
86*4bdff4beSrobert            __a_.notify_all();
87037e7968Spatrick    }
88037e7968Spatrick    inline _LIBCPP_INLINE_VISIBILITY
89037e7968Spatrick    bool try_wait() const noexcept
90037e7968Spatrick    {
91*4bdff4beSrobert        return 0 == __a_.load(memory_order_acquire);
92037e7968Spatrick    }
93037e7968Spatrick    inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
94037e7968Spatrick    void wait() const
95037e7968Spatrick    {
96*4bdff4beSrobert        __cxx_atomic_wait(&__a_.__a_, [&]() -> bool {
97037e7968Spatrick            return try_wait();
98*4bdff4beSrobert        });
99037e7968Spatrick    }
100037e7968Spatrick    inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
101037e7968Spatrick    void arrive_and_wait(ptrdiff_t __update = 1)
102037e7968Spatrick    {
103037e7968Spatrick        count_down(__update);
104037e7968Spatrick        wait();
105037e7968Spatrick    }
106037e7968Spatrick};
107037e7968Spatrick
108037e7968Spatrick_LIBCPP_END_NAMESPACE_STD
109037e7968Spatrick
110037e7968Spatrick#endif // _LIBCPP_STD_VER >= 14
111037e7968Spatrick
11276d0caaeSpatrick_LIBCPP_POP_MACROS
11376d0caaeSpatrick
114037e7968Spatrick#endif //_LIBCPP_LATCH
115