xref: /freebsd/contrib/llvm-project/libcxx/include/latch (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
1*5ffd83dbSDimitry Andric// -*- C++ -*-
2*5ffd83dbSDimitry Andric//===--------------------------- latch -----------------------------------===//
3*5ffd83dbSDimitry Andric//
4*5ffd83dbSDimitry Andric// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5*5ffd83dbSDimitry Andric// See https://llvm.org/LICENSE.txt for license information.
6*5ffd83dbSDimitry Andric// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7*5ffd83dbSDimitry Andric//
8*5ffd83dbSDimitry Andric//===----------------------------------------------------------------------===//
9*5ffd83dbSDimitry Andric
10*5ffd83dbSDimitry Andric#ifndef _LIBCPP_LATCH
11*5ffd83dbSDimitry Andric#define _LIBCPP_LATCH
12*5ffd83dbSDimitry Andric
13*5ffd83dbSDimitry Andric/*
14*5ffd83dbSDimitry Andric    latch synopsis
15*5ffd83dbSDimitry Andric
16*5ffd83dbSDimitry Andricnamespace std
17*5ffd83dbSDimitry Andric{
18*5ffd83dbSDimitry Andric
19*5ffd83dbSDimitry Andric  class latch
20*5ffd83dbSDimitry Andric  {
21*5ffd83dbSDimitry Andric  public:
22*5ffd83dbSDimitry Andric    constexpr explicit latch(ptrdiff_t __expected);
23*5ffd83dbSDimitry Andric    ~latch();
24*5ffd83dbSDimitry Andric
25*5ffd83dbSDimitry Andric    latch(const latch&) = delete;
26*5ffd83dbSDimitry Andric    latch& operator=(const latch&) = delete;
27*5ffd83dbSDimitry Andric
28*5ffd83dbSDimitry Andric    void count_down(ptrdiff_t __update = 1);
29*5ffd83dbSDimitry Andric    bool try_wait() const noexcept;
30*5ffd83dbSDimitry Andric    void wait() const;
31*5ffd83dbSDimitry Andric    void arrive_and_wait(ptrdiff_t __update = 1);
32*5ffd83dbSDimitry Andric
33*5ffd83dbSDimitry Andric  private:
34*5ffd83dbSDimitry Andric    ptrdiff_t __counter; // exposition only
35*5ffd83dbSDimitry Andric  };
36*5ffd83dbSDimitry Andric
37*5ffd83dbSDimitry Andric}
38*5ffd83dbSDimitry Andric
39*5ffd83dbSDimitry Andric*/
40*5ffd83dbSDimitry Andric
41*5ffd83dbSDimitry Andric#include <__config>
42*5ffd83dbSDimitry Andric#include <atomic>
43*5ffd83dbSDimitry Andric
44*5ffd83dbSDimitry Andric#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
45*5ffd83dbSDimitry Andric#pragma GCC system_header
46*5ffd83dbSDimitry Andric#endif
47*5ffd83dbSDimitry Andric
48*5ffd83dbSDimitry Andric#ifdef _LIBCPP_HAS_NO_THREADS
49*5ffd83dbSDimitry Andric# error <latch> is not supported on this single threaded system
50*5ffd83dbSDimitry Andric#endif
51*5ffd83dbSDimitry Andric
52*5ffd83dbSDimitry Andric#if _LIBCPP_STD_VER >= 14
53*5ffd83dbSDimitry Andric
54*5ffd83dbSDimitry Andric_LIBCPP_BEGIN_NAMESPACE_STD
55*5ffd83dbSDimitry Andric
56*5ffd83dbSDimitry Andricclass latch
57*5ffd83dbSDimitry Andric{
58*5ffd83dbSDimitry Andric    __atomic_base<ptrdiff_t> __a;
59*5ffd83dbSDimitry Andric
60*5ffd83dbSDimitry Andricpublic:
61*5ffd83dbSDimitry Andric    static constexpr ptrdiff_t max() noexcept {
62*5ffd83dbSDimitry Andric        return numeric_limits<ptrdiff_t>::max();
63*5ffd83dbSDimitry Andric    }
64*5ffd83dbSDimitry Andric
65*5ffd83dbSDimitry Andric    inline _LIBCPP_INLINE_VISIBILITY
66*5ffd83dbSDimitry Andric    constexpr explicit latch(ptrdiff_t __expected) : __a(__expected) { }
67*5ffd83dbSDimitry Andric
68*5ffd83dbSDimitry Andric    ~latch() = default;
69*5ffd83dbSDimitry Andric    latch(const latch&) = delete;
70*5ffd83dbSDimitry Andric    latch& operator=(const latch&) = delete;
71*5ffd83dbSDimitry Andric
72*5ffd83dbSDimitry Andric    inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
73*5ffd83dbSDimitry Andric    void count_down(ptrdiff_t __update = 1)
74*5ffd83dbSDimitry Andric    {
75*5ffd83dbSDimitry Andric        auto const __old = __a.fetch_sub(__update, memory_order_release);
76*5ffd83dbSDimitry Andric        if(__old == __update)
77*5ffd83dbSDimitry Andric            __a.notify_all();
78*5ffd83dbSDimitry Andric    }
79*5ffd83dbSDimitry Andric    inline _LIBCPP_INLINE_VISIBILITY
80*5ffd83dbSDimitry Andric    bool try_wait() const noexcept
81*5ffd83dbSDimitry Andric    {
82*5ffd83dbSDimitry Andric        return 0 == __a.load(memory_order_acquire);
83*5ffd83dbSDimitry Andric    }
84*5ffd83dbSDimitry Andric    inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
85*5ffd83dbSDimitry Andric    void wait() const
86*5ffd83dbSDimitry Andric    {
87*5ffd83dbSDimitry Andric        auto const __test_fn = [=]() -> bool {
88*5ffd83dbSDimitry Andric            return try_wait();
89*5ffd83dbSDimitry Andric        };
90*5ffd83dbSDimitry Andric        __cxx_atomic_wait(&__a.__a_, __test_fn);
91*5ffd83dbSDimitry Andric    }
92*5ffd83dbSDimitry Andric    inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
93*5ffd83dbSDimitry Andric    void arrive_and_wait(ptrdiff_t __update = 1)
94*5ffd83dbSDimitry Andric    {
95*5ffd83dbSDimitry Andric        count_down(__update);
96*5ffd83dbSDimitry Andric        wait();
97*5ffd83dbSDimitry Andric    }
98*5ffd83dbSDimitry Andric};
99*5ffd83dbSDimitry Andric
100*5ffd83dbSDimitry Andric_LIBCPP_END_NAMESPACE_STD
101*5ffd83dbSDimitry Andric
102*5ffd83dbSDimitry Andric#endif // _LIBCPP_STD_VER >= 14
103*5ffd83dbSDimitry Andric
104*5ffd83dbSDimitry Andric#endif //_LIBCPP_LATCH
105