llvm-project
129 строк · 3.7 Кб
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/*
14latch synopsis
15
16namespace std
17{
18
19class latch
20{
21public:
22static constexpr ptrdiff_t max() noexcept;
23
24constexpr explicit latch(ptrdiff_t __expected);
25~latch();
26
27latch(const latch&) = delete;
28latch& operator=(const latch&) = delete;
29
30void count_down(ptrdiff_t __update = 1);
31bool try_wait() const noexcept;
32void wait() const;
33void arrive_and_wait(ptrdiff_t __update = 1);
34
35private:
36ptrdiff_t __counter; // exposition only
37};
38
39}
40
41*/
42
43#include <__config>
44
45#ifdef _LIBCPP_HAS_NO_THREADS
46# error "<latch> is not supported since libc++ has been configured without support for threads."
47#endif
48
49#include <__assert>
50#include <__atomic/atomic_base.h>
51#include <__atomic/atomic_sync.h>
52#include <__atomic/memory_order.h>
53#include <cstddef>
54#include <limits>
55#include <version>
56
57#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
58# pragma GCC system_header
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 _LIBCPP_DEPRECATED_ATOMIC_SYNC latch {
69__atomic_base<ptrdiff_t> __a_;
70
71public:
72static _LIBCPP_HIDE_FROM_ABI constexpr ptrdiff_t max() noexcept { return numeric_limits<ptrdiff_t>::max(); }
73
74inline _LIBCPP_HIDE_FROM_ABI constexpr explicit latch(ptrdiff_t __expected) : __a_(__expected) {
75_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
76__expected >= 0,
77"latch::latch(ptrdiff_t): latch cannot be "
78"initialized with a negative value");
79_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
80__expected <= max(),
81"latch::latch(ptrdiff_t): latch cannot be "
82"initialized with a value greater than max()");
83}
84
85_LIBCPP_HIDE_FROM_ABI ~latch() = default;
86latch(const latch&) = delete;
87latch& operator=(const latch&) = delete;
88
89inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void count_down(ptrdiff_t __update = 1) {
90_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__update >= 0, "latch::count_down called with a negative value");
91auto const __old = __a_.fetch_sub(__update, memory_order_release);
92_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
93__update <= __old,
94"latch::count_down called with a value greater "
95"than the internal counter");
96if (__old == __update)
97__a_.notify_all();
98}
99inline _LIBCPP_HIDE_FROM_ABI bool try_wait() const noexcept {
100auto __value = __a_.load(memory_order_acquire);
101return try_wait_impl(__value);
102}
103inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void wait() const {
104std::__atomic_wait_unless(
105__a_, [this](ptrdiff_t& __value) -> bool { return try_wait_impl(__value); }, memory_order_acquire);
106}
107inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void arrive_and_wait(ptrdiff_t __update = 1) {
108_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__update >= 0, "latch::arrive_and_wait called with a negative value");
109// other preconditions on __update are checked in count_down()
110
111count_down(__update);
112wait();
113}
114
115private:
116_LIBCPP_HIDE_FROM_ABI bool try_wait_impl(ptrdiff_t& __value) const noexcept { return __value == 0; }
117};
118
119_LIBCPP_END_NAMESPACE_STD
120
121#endif // _LIBCPP_STD_VER >= 14
122
123_LIBCPP_POP_MACROS
124
125#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
126# include <atomic>
127#endif
128
129#endif //_LIBCPP_LATCH
130