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 "__config"
10 
11 #ifndef _LIBCPP_HAS_NO_THREADS
12 
13 #include "future"
14 #include "string"
15 
16 _LIBCPP_BEGIN_NAMESPACE_STD
17 
18 class _LIBCPP_HIDDEN __future_error_category
19     : public __do_message
20 {
21 public:
22     virtual const char* name() const noexcept;
23     virtual string message(int ev) const;
24 };
25 
26 const char*
27 __future_error_category::name() const noexcept
28 {
29     return "future";
30 }
31 
32 #if defined(__clang__)
33 #pragma clang diagnostic push
34 #pragma clang diagnostic ignored "-Wswitch"
35 #elif defined(__GNUC__) || defined(__GNUG__)
36 #pragma GCC diagnostic push
37 #pragma GCC diagnostic ignored "-Wswitch"
38 #endif
39 
40 string
41 __future_error_category::message(int ev) const
42 {
43     switch (static_cast<future_errc>(ev))
44     {
45     case future_errc(0):  // For backwards compatibility with C++11 (LWG 2056)
46     case future_errc::broken_promise:
47         return string("The associated promise has been destructed prior "
48                       "to the associated state becoming ready.");
49     case future_errc::future_already_retrieved:
50         return string("The future has already been retrieved from "
51                       "the promise or packaged_task.");
52     case future_errc::promise_already_satisfied:
53         return string("The state of the promise has already been set.");
54     case future_errc::no_state:
55         return string("Operation not permitted on an object without "
56                       "an associated state.");
57     }
58     return string("unspecified future_errc value\n");
59 }
60 
61 #if defined(__clang__)
62 #pragma clang diagnostic pop
63 #elif defined(__GNUC__) || defined(__GNUG__)
64 #pragma GCC diagnostic pop
65 #endif
66 
67 const error_category&
68 future_category() noexcept
69 {
70     static __future_error_category __f;
71     return __f;
72 }
73 
74 future_error::future_error(error_code __ec)
75     : logic_error(__ec.message()),
76       __ec_(__ec)
77 {
78 }
79 
80 future_error::~future_error() noexcept
81 {
82 }
83 
84 void
85 __assoc_sub_state::__on_zero_shared() noexcept
86 {
87     delete this;
88 }
89 
90 void
91 __assoc_sub_state::set_value()
92 {
93     unique_lock<mutex> __lk(__mut_);
94     if (__has_value())
95         __throw_future_error(future_errc::promise_already_satisfied);
96     __state_ |= __constructed | ready;
97     __cv_.notify_all();
98 }
99 
100 void
101 __assoc_sub_state::set_value_at_thread_exit()
102 {
103     unique_lock<mutex> __lk(__mut_);
104     if (__has_value())
105         __throw_future_error(future_errc::promise_already_satisfied);
106     __state_ |= __constructed;
107     __thread_local_data()->__make_ready_at_thread_exit(this);
108 }
109 
110 void
111 __assoc_sub_state::set_exception(exception_ptr __p)
112 {
113     unique_lock<mutex> __lk(__mut_);
114     if (__has_value())
115         __throw_future_error(future_errc::promise_already_satisfied);
116     __exception_ = __p;
117     __state_ |= ready;
118     __cv_.notify_all();
119 }
120 
121 void
122 __assoc_sub_state::set_exception_at_thread_exit(exception_ptr __p)
123 {
124     unique_lock<mutex> __lk(__mut_);
125     if (__has_value())
126         __throw_future_error(future_errc::promise_already_satisfied);
127     __exception_ = __p;
128     __thread_local_data()->__make_ready_at_thread_exit(this);
129 }
130 
131 void
132 __assoc_sub_state::__make_ready()
133 {
134     unique_lock<mutex> __lk(__mut_);
135     __state_ |= ready;
136     __cv_.notify_all();
137 }
138 
139 void
140 __assoc_sub_state::copy()
141 {
142     unique_lock<mutex> __lk(__mut_);
143     __sub_wait(__lk);
144     if (__exception_ != nullptr)
145         rethrow_exception(__exception_);
146 }
147 
148 void
149 __assoc_sub_state::wait()
150 {
151     unique_lock<mutex> __lk(__mut_);
152     __sub_wait(__lk);
153 }
154 
155 void
156 __assoc_sub_state::__sub_wait(unique_lock<mutex>& __lk)
157 {
158     if (!__is_ready())
159     {
160         if (__state_ & static_cast<unsigned>(deferred))
161         {
162             __state_ &= ~static_cast<unsigned>(deferred);
163             __lk.unlock();
164             __execute();
165         }
166         else
167             while (!__is_ready())
168                 __cv_.wait(__lk);
169     }
170 }
171 
172 void
173 __assoc_sub_state::__execute()
174 {
175     __throw_future_error(future_errc::no_state);
176 }
177 
178 future<void>::future(__assoc_sub_state* __state)
179     : __state_(__state)
180 {
181     __state_->__attach_future();
182 }
183 
184 future<void>::~future()
185 {
186     if (__state_)
187         __state_->__release_shared();
188 }
189 
190 void
191 future<void>::get()
192 {
193     unique_ptr<__shared_count, __release_shared_count> __(__state_);
194     __assoc_sub_state* __s = __state_;
195     __state_ = nullptr;
196     __s->copy();
197 }
198 
199 promise<void>::promise()
200     : __state_(new __assoc_sub_state)
201 {
202 }
203 
204 promise<void>::~promise()
205 {
206     if (__state_)
207     {
208 #ifndef _LIBCPP_NO_EXCEPTIONS
209         if (!__state_->__has_value() && __state_->use_count() > 1)
210             __state_->set_exception(make_exception_ptr(
211                       future_error(make_error_code(future_errc::broken_promise))
212                                                       ));
213 #endif // _LIBCPP_NO_EXCEPTIONS
214         __state_->__release_shared();
215     }
216 }
217 
218 future<void>
219 promise<void>::get_future()
220 {
221     if (__state_ == nullptr)
222         __throw_future_error(future_errc::no_state);
223     return future<void>(__state_);
224 }
225 
226 void
227 promise<void>::set_value()
228 {
229     if (__state_ == nullptr)
230         __throw_future_error(future_errc::no_state);
231     __state_->set_value();
232 }
233 
234 void
235 promise<void>::set_exception(exception_ptr __p)
236 {
237     if (__state_ == nullptr)
238         __throw_future_error(future_errc::no_state);
239     __state_->set_exception(__p);
240 }
241 
242 void
243 promise<void>::set_value_at_thread_exit()
244 {
245     if (__state_ == nullptr)
246         __throw_future_error(future_errc::no_state);
247     __state_->set_value_at_thread_exit();
248 }
249 
250 void
251 promise<void>::set_exception_at_thread_exit(exception_ptr __p)
252 {
253     if (__state_ == nullptr)
254         __throw_future_error(future_errc::no_state);
255     __state_->set_exception_at_thread_exit(__p);
256 }
257 
258 shared_future<void>::~shared_future()
259 {
260     if (__state_)
261         __state_->__release_shared();
262 }
263 
264 shared_future<void>&
265 shared_future<void>::operator=(const shared_future& __rhs)
266 {
267     if (__rhs.__state_)
268         __rhs.__state_->__add_shared();
269     if (__state_)
270         __state_->__release_shared();
271     __state_ = __rhs.__state_;
272     return *this;
273 }
274 
275 _LIBCPP_END_NAMESPACE_STD
276 
277 #endif // !_LIBCPP_HAS_NO_THREADS
278