1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include <future>
10#include <string>
11
12_LIBCPP_BEGIN_NAMESPACE_STD
13_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
14
15class _LIBCPP_HIDDEN __future_error_category : public __do_message {
16public:
17 virtual const char* name() const noexcept;
18 virtual string message(int ev) const;
19};
20
21const char* __future_error_category::name() const noexcept { return "future"; }
22
23_LIBCPP_DIAGNOSTIC_PUSH
24_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wswitch")
25_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wswitch")
26
27string __future_error_category::message(int ev) const {
28 switch (static_cast<future_errc>(ev)) {
29 case future_errc(0): // For backwards compatibility with C++11 (LWG 2056)
30 case future_errc::broken_promise:
31 return string("The associated promise has been destructed prior "
32 "to the associated state becoming ready.");
33 case future_errc::future_already_retrieved:
34 return string("The future has already been retrieved from "
35 "the promise or packaged_task.");
36 case future_errc::promise_already_satisfied:
37 return string("The state of the promise has already been set.");
38 case future_errc::no_state:
39 return string("Operation not permitted on an object without "
40 "an associated state.");
41 }
42 return string("unspecified future_errc value\n");
43}
44
45_LIBCPP_DIAGNOSTIC_POP
46
47const error_category& future_category() noexcept {
48 union AvoidDestroyingFutureCategory {
49 __future_error_category future_error_category;
50 constexpr explicit AvoidDestroyingFutureCategory() : future_error_category() {}
51 ~AvoidDestroyingFutureCategory() {}
52 };
53 constinit static AvoidDestroyingFutureCategory helper;
54 return helper.future_error_category;
55}
56
57future_error::future_error(error_code __ec) : logic_error(__ec.message()), __ec_(__ec) {}
58
59future_error::~future_error() noexcept {}
60
61void __assoc_sub_state::__on_zero_shared() noexcept { delete this; }
62
63void __assoc_sub_state::set_value() {
64 unique_lock<mutex> __lk(__mut_);
65 if (__has_value())
66 std::__throw_future_error(ev: future_errc::promise_already_satisfied);
67 __state_ |= __constructed | ready;
68 __cv_.notify_all();
69}
70
71void __assoc_sub_state::set_value_at_thread_exit() {
72 unique_lock<mutex> __lk(__mut_);
73 if (__has_value())
74 std::__throw_future_error(ev: future_errc::promise_already_satisfied);
75 __state_ |= __constructed;
76 __thread_local_data()->__make_ready_at_thread_exit(this);
77}
78
79void __assoc_sub_state::set_exception(exception_ptr __p) {
80 unique_lock<mutex> __lk(__mut_);
81 if (__has_value())
82 std::__throw_future_error(ev: future_errc::promise_already_satisfied);
83 __exception_ = __p;
84 __state_ |= ready;
85 __cv_.notify_all();
86}
87
88void __assoc_sub_state::set_exception_at_thread_exit(exception_ptr __p) {
89 unique_lock<mutex> __lk(__mut_);
90 if (__has_value())
91 std::__throw_future_error(ev: future_errc::promise_already_satisfied);
92 __exception_ = __p;
93 __thread_local_data()->__make_ready_at_thread_exit(this);
94}
95
96void __assoc_sub_state::__make_ready() {
97 unique_lock<mutex> __lk(__mut_);
98 __state_ |= ready;
99 __cv_.notify_all();
100}
101
102void __assoc_sub_state::copy() {
103 unique_lock<mutex> __lk(__mut_);
104 __sub_wait(__lk);
105 if (__exception_ != nullptr)
106 rethrow_exception(__exception_);
107}
108
109void __assoc_sub_state::wait() {
110 unique_lock<mutex> __lk(__mut_);
111 __sub_wait(__lk);
112}
113
114void __assoc_sub_state::__sub_wait(unique_lock<mutex>& __lk) {
115 if (!__is_ready()) {
116 if (__state_ & static_cast<unsigned>(deferred)) {
117 __state_ &= ~static_cast<unsigned>(deferred);
118 __lk.unlock();
119 __execute();
120 } else
121 while (!__is_ready())
122 __cv_.wait(__lk);
123 }
124}
125
126void __assoc_sub_state::__execute() { std::__throw_future_error(ev: future_errc::no_state); }
127
128future<void>::future(__assoc_sub_state* __state) : __state_(__state) { __state_->__attach_future(); }
129
130future<void>::~future() {
131 if (__state_)
132 __state_->__release_shared();
133}
134
135void future<void>::get() {
136 unique_ptr<__shared_count, __release_shared_count> __(__state_);
137 __assoc_sub_state* __s = __state_;
138 __state_ = nullptr;
139 __s->copy();
140}
141
142promise<void>::promise() : __state_(new __assoc_sub_state) {}
143
144promise<void>::~promise() {
145 if (__state_) {
146#if _LIBCPP_HAS_EXCEPTIONS
147 if (!__state_->__has_value() && __state_->use_count() > 1)
148 __state_->set_exception(make_exception_ptr(e: future_error(future_errc::broken_promise)));
149#endif // _LIBCPP_HAS_EXCEPTIONS
150 __state_->__release_shared();
151 }
152}
153
154future<void> promise<void>::get_future() {
155 if (__state_ == nullptr)
156 std::__throw_future_error(ev: future_errc::no_state);
157 return future<void>(__state_);
158}
159
160void promise<void>::set_value() {
161 if (__state_ == nullptr)
162 std::__throw_future_error(ev: future_errc::no_state);
163 __state_->set_value();
164}
165
166void promise<void>::set_exception(exception_ptr __p) {
167 if (__state_ == nullptr)
168 std::__throw_future_error(ev: future_errc::no_state);
169 __state_->set_exception(__p);
170}
171
172void promise<void>::set_value_at_thread_exit() {
173 if (__state_ == nullptr)
174 std::__throw_future_error(ev: future_errc::no_state);
175 __state_->set_value_at_thread_exit();
176}
177
178void promise<void>::set_exception_at_thread_exit(exception_ptr __p) {
179 if (__state_ == nullptr)
180 std::__throw_future_error(ev: future_errc::no_state);
181 __state_->set_exception_at_thread_exit(__p);
182}
183
184shared_future<void>::~shared_future() {
185 if (__state_)
186 __state_->__release_shared();
187}
188
189shared_future<void>& shared_future<void>::operator=(const shared_future& __rhs) {
190 if (__rhs.__state_)
191 __rhs.__state_->__add_shared();
192 if (__state_)
193 __state_->__release_shared();
194 __state_ = __rhs.__state_;
195 return *this;
196}
197
198_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
199_LIBCPP_END_NAMESPACE_STD
200