source: mainline/uspace/lib/cpp/include/__bits/thread/future.hpp@ 6e97265

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 6e97265 was 6e97265, checked in by Jaroslav Jindrak <dzejrou@…>, 6 years ago

cpp: refactor future to avoid code duplication, fix wait_for and wait_until, synchronization and compilation

  • Property mode set to 100644
File size: 6.5 KB
Line 
1/*
2 * Copyright (c) 2019 Jaroslav Jindrak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef LIBCPP_BITS_THREAD_FUTURE
30#define LIBCPP_BITS_THREAD_FUTURE
31
32#include <__bits/thread/future_common.hpp>
33#include <__bits/thread/shared_state.hpp>
34#include <__bits/utility/forward_move.hpp>
35#include <cassert>
36
37namespace std
38{
39 /**
40 * 30.6.6, class template future:
41 */
42
43 namespace aux
44 {
45 template<class R>
46 class future_base
47 {
48 public:
49 future_base() noexcept
50 : state_{nullptr}
51 { /* DUMMY BODY */ }
52
53 future_base(const future_base&) = delete;
54
55 future_base(future_base&& rhs) noexcept
56 : state_{std::move(rhs.state_)}
57 {
58 rhs.state_ = nullptr;
59 }
60
61 future_base(aux::shared_state<R>* state)
62 : state_{state}
63 {
64 /**
65 * Note: This is a custom non-standard constructor that allows
66 * us to create a future directly from a shared state. This
67 * should never be a problem as aux::shared_state is a private
68 * type and future has no constructor templates.
69 */
70 }
71
72 virtual ~future_base()
73 {
74 release_state_();
75 }
76
77 future_base& operator=(const future_base&) = delete;
78
79 future_base& operator=(future_base&& rhs) noexcept
80 {
81 release_state_();
82 state_ = std::move(rhs.state_);
83 rhs.state_ = nullptr;
84 }
85
86 bool valid() const noexcept
87 {
88 return state_ != nullptr;
89 }
90
91 void wait() const noexcept
92 {
93 assert(state_);
94
95 state_->wait();
96 }
97
98 template<class Rep, class Period>
99 future_status
100 wait_for(const chrono::duration<Rep, Period>& rel_time) const
101 {
102 assert(state_);
103
104 return state_->wait_for(rel_time);
105 }
106
107 template<class Clock, class Duration>
108 future_status
109 wait_until(
110 const chrono::time_point<Clock, Duration>& abs_time
111 ) const
112 {
113 assert(state_);
114
115 return state_->wait_until(abs_time);
116 }
117
118 protected:
119 void release_state_()
120 {
121 if (!state_)
122 return;
123
124 /**
125 * Note: This is the 'release' move described in
126 * 30.6.4 (5).
127 * Last reference to state -> destroy state.
128 * Decrement refcount of state otherwise.
129 * Will not block, unless all following hold:
130 * 1) State was created by call to std::async.
131 * 2) State is not yet ready.
132 * 3) This was the last reference to the shared state.
133 */
134 if (state_->decrement())
135 {
136 /**
137 * The destroy call handles the special case
138 * when 1) - 3) hold.
139 */
140 state_->destroy();
141 delete state_;
142 state_ = nullptr;
143 }
144 }
145
146 aux::shared_state<R>* state_;
147 };
148 }
149
150 template<class R>
151 class shared_future;
152
153 template<class R>
154 class future: public aux::future_base<R>
155 {
156 public:
157 future() noexcept
158 : aux::future_base<R>{}
159 { /* DUMMY BODY */ }
160
161 future(const future&) = delete;
162
163 future(future&& rhs) noexcept
164 : aux::future_base<R>{std::move(rhs.state_)}
165 { /* DUMMY BODY */ }
166
167 future(aux::shared_state<R>* state)
168 : aux::future_base<R>{state}
169 { /* DUMMY BODY */ }
170
171 future& operator=(const future&) = delete;
172
173 future& operator=(future&& rhs) noexcept
174 {
175 return aux::future_base<R>::operator=(std::move(rhs));
176 }
177
178 shared_future<R> share()
179 {
180 return shared_future<R>(std::move(*this));
181 }
182
183 R get()
184 {
185 assert(this->state_);
186
187 this->wait();
188
189 if (this->state_->has_exception())
190 this->state_->throw_stored_exception();
191 auto res = std::move(this->state_->get());
192
193 this->release_state_();
194
195 return res;
196 }
197 };
198
199 template<class R>
200 class future<R&>
201 {
202 // TODO: Copy & modify once future is done.
203 };
204
205 template<>
206 class future<void>
207 {
208 // TODO: Copy & modify once future is done.
209 };
210}
211
212#endif
Note: See TracBrowser for help on using the repository browser.