source: mainline/uspace/lib/cpp/include/__bits/thread/promise.hpp@ e49d0ac

Last change on this file since e49d0ac was b57ba05, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 3 years ago

Update headers in C++ files

  • Property mode set to 100644
File size: 12.2 KB
Line 
1/*
2 * SPDX-FileCopyrightText: 2019 Jaroslav Jindrak
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#ifndef LIBCPP_BITS_THREAD_PROMISE
8#define LIBCPP_BITS_THREAD_PROMISE
9
10#include <__bits/exception.hpp>
11#include <__bits/memory/allocator_traits.hpp>
12#include <__bits/thread/future.hpp>
13#include <__bits/thread/shared_state.hpp>
14#include <__bits/aux.hpp>
15#include <utility>
16
17namespace std
18{
19 /**
20 * 30.6.5, class template promise:
21 */
22
23 namespace aux
24 {
25 template<class R>
26 class promise_base
27 {
28 public:
29 promise_base()
30 : state_{new aux::shared_state<R>{}}
31 { /* DUMMY BODY */ }
32
33 template<class Allocator>
34 promise_base(allocator_arg_t, const Allocator& a)
35 : state_{}
36 {
37 typename allocator_traits<
38 Allocator
39 >::template rebind_alloc<aux::shared_state<R>> rebound{a};
40
41 state_ = rebound.allocate(1);
42 rebound.construct(state_);
43 }
44
45 promise_base(promise_base&& rhs) noexcept
46 : state_{}
47 {
48 state_ = rhs.state_;
49 rhs.state_ = nullptr;
50 }
51
52 promise_base(const promise_base&) = delete;
53
54 virtual ~promise_base()
55 {
56 this->abandon_state_();
57 }
58
59 promise_base& operator=(promise_base&& rhs) noexcept
60 {
61 abandon_state_();
62 promise_base{move(rhs)}.swap(*this);
63
64 return *this;
65 }
66
67 promise_base& operator=(const promise_base&) = delete;
68
69 void swap(promise_base& other) noexcept
70 {
71 std::swap(state_, other.state_);
72 }
73
74 void set_exception(exception_ptr ptr)
75 {
76 assert(state_);
77
78 state_->set_exception(ptr);
79 }
80
81 void set_exception_at_thread_exit(exception_ptr ptr)
82 {
83 assert(state_);
84
85 state_->set_exception_ptr(ptr, false);
86 aux::set_state_exception_at_thread_exit(state_);
87 }
88
89 /**
90 * Useful for testing as we can check some information
91 * otherwise unavailable to us without waiting, e.g.
92 * to check whether the state is ready, its reference
93 * count etc.
94 */
95 aux::shared_state<R>* __state()
96 {
97 return state_;
98 }
99
100 protected:
101 void abandon_state_()
102 {
103 if (!state_)
104 return;
105
106 /**
107 * Note: This is the 'abandon' move described in
108 * 30.6.4 (7).
109 * 1) If state is not ready:
110 * a) Store exception of type future_error with
111 * error condition broken_promise.
112 * b) Mark state as ready.
113 * 2) Release the state.
114 */
115
116 if (!state_->is_set())
117 {
118 state_->set_exception(make_exception_ptr(
119 future_error{make_error_code(future_errc::broken_promise)}
120 ));
121 state_->mark_set(true);
122 }
123
124 if (state_->decrement())
125 {
126 state_->destroy();
127 delete state_;
128 state_ = nullptr;
129 }
130 }
131
132 aux::shared_state<R>* state_;
133 };
134 }
135
136 template<class R>
137 class promise: public aux::promise_base<R>
138 {
139 public:
140 promise()
141 : aux::promise_base<R>{}
142 { /* DUMMY BODY */ }
143
144 template<class Allocator>
145 promise(allocator_arg_t tag, const Allocator& a)
146 : aux::promise_base<R>{tag, a}
147 { /* DUMMY BODY */ }
148
149 promise(promise&& rhs) noexcept
150 : aux::promise_base<R>{move(rhs)}
151 { /* DUMMY BODY */ }
152
153 promise(const promise&) = delete;
154
155 ~promise() override = default;
156
157 promise& operator=(promise&& rhs) noexcept = default;
158
159 promise& operator=(const promise&) = delete;
160
161 future<R> get_future()
162 {
163 assert(this->state_);
164
165 /**
166 * Note: Future constructor that takes a shared
167 * state as its argument does not call increment
168 * because a future can be created as the only
169 * owner of that state (e.g. when created by
170 * std::async), so we have to do it here.
171 */
172 this->state_->increment();
173
174 return future<R>{this->state_};
175 }
176
177 void set_value(const R& val)
178 {
179 if (!this->state_)
180 throw future_error{make_error_code(future_errc::no_state)};
181 if (this->state_->is_set())
182 {
183 throw future_error{
184 make_error_code(future_errc::promise_already_satisfied)
185 };
186 }
187
188 this->state_->set_value(val, true);
189 }
190
191 void set_value(R&& val)
192 {
193 if (!this->state_)
194 throw future_error{make_error_code(future_errc::no_state)};
195 if (this->state_->is_set())
196 {
197 throw future_error{
198 make_error_code(future_errc::promise_already_satisfied)
199 };
200 }
201
202 this->state_->set_value(forward<R>(val), true);
203 }
204
205 void set_value_at_thread_exit(const R& val)
206 {
207 if (!this->state_)
208 throw future_error{make_error_code(future_errc::no_state)};
209 if (this->state_->is_set())
210 {
211 throw future_error{
212 make_error_code(future_errc::promise_already_satisfied)
213 };
214 }
215
216 try
217 {
218 this->state_->set_value(val, false);
219 aux::set_state_value_at_thread_exit(this->state_);
220 }
221 catch(const exception& __exception)
222 {
223 this->state_->set_exception(make_exception_ptr(__exception), false);
224 aux::set_state_exception_at_thread_exit(this->state_);
225 }
226 }
227
228 void set_value_at_thread_exit(R&& val)
229 {
230 if (!this->state_)
231 throw future_error{make_error_code(future_errc::no_state)};
232 if (this->state_->is_set())
233 {
234 throw future_error{
235 make_error_code(future_errc::promise_already_satisfied)
236 };
237 }
238
239 try
240 {
241 this->state_->set_value(forward<R>(val), false);
242 aux::set_state_value_at_thread_exit(this->state_);
243 }
244 catch(const exception& __exception)
245 {
246 this->state_->set_exception(make_exception_ptr(__exception), false);
247 aux::set_state_exception_at_thread_exit(this->state_);
248 }
249 }
250 };
251
252 template<class R>
253 class promise<R&>: public aux::promise_base<R*>
254 {
255 public:
256 promise()
257 : aux::promise_base<R*>{}
258 { /* DUMMY BODY */ }
259
260 template<class Allocator>
261 promise(allocator_arg_t tag, const Allocator& a)
262 : aux::promise_base<R*>{tag, a}
263 { /* DUMMY BODY */ }
264
265 promise(promise&& rhs) noexcept
266 : aux::promise_base<R*>{move(rhs)}
267 { /* DUMMY BODY */ }
268
269 promise(const promise&) = delete;
270
271 ~promise() override = default;
272
273 promise& operator=(promise&& rhs) noexcept = default;
274
275 promise& operator=(const promise&) = delete;
276
277 future<R&> get_future()
278 {
279 assert(this->state_);
280
281 /**
282 * Note: Future constructor that takes a shared
283 * state as its argument does not call increment
284 * because a future can be created as the only
285 * owner of that state (e.g. when created by
286 * std::async), so we have to do it here.
287 */
288 this->state_->increment();
289
290 return future<R&>{this->state_};
291 }
292
293 void set_value(R& val)
294 {
295 if (!this->state_)
296 throw future_error{make_error_code(future_errc::no_state)};
297 if (this->state_->is_set())
298 {
299 throw future_error{
300 make_error_code(future_errc::promise_already_satisfied)
301 };
302 }
303
304 this->state_->set_value(&val, true);
305 }
306
307 void set_value_at_thread_exit(R& val)
308 {
309 if (!this->state_)
310 throw future_error{make_error_code(future_errc::no_state)};
311 if (this->state_->is_set())
312 {
313 throw future_error{
314 make_error_code(future_errc::promise_already_satisfied)
315 };
316 }
317
318 try
319 {
320 this->state_->set_value(&val, false);
321 aux::set_state_value_at_thread_exit(this->state_);
322 }
323 catch(const exception& __exception)
324 {
325 this->state_->set_exception(make_exception_ptr(__exception), false);
326 aux::set_state_exception_at_thread_exit(this->state_);
327 }
328 }
329 };
330
331 template<>
332 class promise<void>: public aux::promise_base<void>
333 {
334 public:
335 promise()
336 : aux::promise_base<void>{}
337 { /* DUMMY BODY */ }
338
339 template<class Allocator>
340 promise(allocator_arg_t tag, const Allocator& a)
341 : aux::promise_base<void>{tag, a}
342 { /* DUMMY BODY */ }
343
344 promise(promise&& rhs) noexcept
345 : aux::promise_base<void>{move(rhs)}
346 { /* DUMMY BODY */ }
347
348 promise(const promise&) = delete;
349
350 ~promise() override = default;
351
352 promise& operator=(promise&& rhs) noexcept = default;
353
354 promise& operator=(const promise&) = delete;
355
356 future<void> get_future()
357 {
358 assert(this->state_);
359
360 /**
361 * Note: Future constructor that takes a shared
362 * state as its argument does not call increment
363 * because a future can be created as the only
364 * owner of that state (e.g. when created by
365 * std::async), so we have to do it here.
366 */
367 this->state_->increment();
368
369 return future<void>{this->state_};
370 }
371
372 void set_value()
373 {
374 if (!this->state_)
375 throw future_error{make_error_code(future_errc::no_state)};
376 if (this->state_->is_set())
377 {
378 throw future_error{
379 make_error_code(future_errc::promise_already_satisfied)
380 };
381 }
382
383 this->state_->set_value();
384 }
385 };
386
387 template<class R>
388 void swap(promise<R>& lhs, promise<R>& rhs) noexcept
389 {
390 lhs.swap(rhs);
391 }
392
393 template<class R, class Alloc>
394 struct uses_allocator<promise<R>, Alloc>: true_type
395 { /* DUMMY BODY */ };
396}
397
398#endif
Note: See TracBrowser for help on using the repository browser.