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