Changeset 6e97265 in mainline
- Timestamp:
- 2019-06-30T14:37:40Z (5 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 3a29607
- Parents:
- d86c00f0
- Location:
- uspace/lib/cpp/include/__bits/thread
- Files:
-
- 1 added
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/cpp/include/__bits/thread/future.hpp
rd86c00f0 r6e97265 30 30 #define LIBCPP_BITS_THREAD_FUTURE 31 31 32 #include <__bits/thread/future_common.hpp> 33 #include <__bits/thread/shared_state.hpp> 34 #include <__bits/utility/forward_move.hpp> 32 35 #include <cassert> 33 #include <memory>34 #include <system_error>35 #include <thread>36 #include <tuple>37 #include <type_traits>38 #include <utility>39 36 40 37 namespace std 41 38 { 42 39 /** 43 * 30.6, futures:44 */45 46 enum class future_errc47 { // The 5001 start is to not collide with system_error's codes.48 broken_promise = 5001,49 future_already_retrieved,50 promise_already_satisfied,51 no_state52 };53 54 enum class future_status55 {56 ready,57 timeout,58 deferred59 };60 61 /**62 * 30.6.2, error handling:63 */64 65 template<>66 struct is_error_code_enum<future_errc>: true_type67 { /* DUMMY BODY */ };68 69 error_code make_error_code(future_errc) noexcept;70 error_condition make_error_condition(future_errc) noexcept;71 72 const error_category& future_category() noexcept;73 74 /**75 * 30.6.3, class future_error:76 */77 78 class future_error: public logic_error79 {80 public:81 future_error(error_code ec);82 83 const error_code& code() const noexcept;84 const char* what() const noexcept;85 86 private:87 error_code code_;88 };89 90 /**91 40 * 30.6.6, class template future: 92 41 */ 93 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 94 150 template<class R> 95 151 class shared_future; 96 152 97 153 template<class R> 98 class future 154 class future: public aux::future_base<R> 99 155 { 100 156 public: 101 157 future() noexcept 102 : state_{nullptr}158 : aux::future_base<R>{} 103 159 { /* DUMMY BODY */ } 104 160 … … 106 162 107 163 future(future&& rhs) noexcept 108 : state_{std::move(rhs.state_)} 109 { 110 rhs.state_ = nullptr; 111 } 164 : aux::future_base<R>{std::move(rhs.state_)} 165 { /* DUMMY BODY */ } 112 166 113 167 future(aux::shared_state<R>* state) 114 : state_{state} 115 { 116 /** 117 * Note: This is a custom non-standard constructor that allows 118 * us to create a future directly from a shared state. This 119 * should never be a problem as aux::shared_state is a private 120 * type and future has no constructor templates. 121 */ 122 } 123 124 ~future() 125 { 126 release_state_(); 127 } 128 129 future& operator=(const future) = delete; 168 : aux::future_base<R>{state} 169 { /* DUMMY BODY */ } 170 171 future& operator=(const future&) = delete; 130 172 131 173 future& operator=(future&& rhs) noexcept 132 174 { 133 release_state_(); 134 state_ = std::move(rhs.state_); 135 rhs.state_ = nullptr; 175 return aux::future_base<R>::operator=(std::move(rhs)); 136 176 } 137 177 … … 143 183 R get() 144 184 { 145 assert( state_);146 147 wait();148 149 if ( state_->has_exception())150 state_->throw_stored_exception();151 auto res = std::move( state_->get());152 153 release_state_();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_(); 154 194 155 195 return res; 156 196 } 157 158 bool valid() const noexcept159 {160 return state_ != nullptr;161 }162 163 void wait() const noexcept164 {165 assert(state_);166 167 state_->wait();168 }169 170 template<class Rep, class Period>171 future_status wait_for(const chrono::duration<Rep, Period>& rel_time) const172 {173 assert(state_);174 175 return state_->wait_for(rel_time);176 }177 178 template<class Clock, class Duration>179 future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) const180 {181 assert(state_);182 183 return state_->wait_until(abs_time);184 }185 186 private:187 void release_state_()188 {189 if (!state_)190 return;191 192 /**193 * Note: This is the 'release' move described in194 * 30.6.4 (5).195 * Last reference to state -> destroy state.196 * Decrement refcount of state otherwise.197 * Will not block, unless all following hold:198 * 1) State was created by call to std::async.199 * 2) State is not yet ready.200 * 3) This was the last reference to the shared state.201 */202 if (state_->decrement())203 {204 /**205 * The destroy call handles the special case206 * when 1) - 3) hold.207 */208 state_->destroy();209 delete state_;210 state_ = nullptr;211 }212 }213 214 aux::shared_state<R>* state_;215 197 }; 216 198 -
uspace/lib/cpp/include/__bits/thread/shared_state.hpp
rd86c00f0 r6e97265 34 34 */ 35 35 36 #include <__bits/exception.hpp> 36 37 #include <__bits/functional/function.hpp> 37 38 #include <__bits/functional/invoke.hpp> 38 39 #include <__bits/refcount_obj.hpp> 40 #include <__bits/thread/future_common.hpp> 39 41 #include <__bits/thread/threading.hpp> 42 #include <cerrno> 43 #include <thread> 44 #include <tuple> 45 46 namespace std 47 { 48 enum class future_status; 49 } 40 50 41 51 namespace std::aux … … 137 147 138 148 template<class Rep, class Period> 139 virtualfuture_status149 future_status 140 150 wait_for(const chrono::duration<Rep, Period>& rel_time) 141 151 { 142 152 aux::threading::mutex::lock(mutex_); 143 auto res = aux::threading::condvar::wait_for( 144 condvar_, mutex_, 153 auto res = timed_wait_( 145 154 aux::threading::time::convert(rel_time) 146 155 ); 147 156 aux::threading::mutex::unlock(mutex_); 148 157 158 return res; 159 } 160 161 template<class Clock, class Duration> 162 future_status 163 wait_until(const chrono::time_point<Clock, Duration>& abs_time) 164 { 165 aux::threading::mutex::lock(mutex_); 166 auto res = timed_wait_( 167 aux::threading::time(convert(abs_time - Clock::now())) 168 ); 169 aux::threading::mutex::unlock(mutex_); 170 171 return res; 172 } 173 174 ~shared_state() override = default; 175 176 protected: 177 aux::mutex_t mutex_; 178 aux::condvar_t condvar_; 179 180 R value_; 181 bool value_set_; 182 183 exception_ptr exception_; 184 bool has_exception_; 185 186 /** 187 * Note: wait_for and wait_until are templates and as such 188 * cannot be virtual and overriden by the deferred_ and 189 * async_ children. However, we are using aux::time_unit_t 190 * in the end anyway, so we can work around that 191 * by using the 'template method' design pattern 192 * (i.e. by providing a virtual function called by these 193 * templates and then overriding that function in the 194 * children). 195 */ 196 virtual future_status timed_wait_(aux::time_unit_t time) 197 { 198 auto res = aux::threading::condvar::wait_for( 199 condvar_, mutex_, time 200 ); 201 149 202 return res == ETIMEOUT ? future_status::timeout 150 203 : future_status::ready; 151 204 } 152 153 template<class Clock, class Duration>154 virtual future_status155 wait_until(const chrono::time_point<Clock, Duration>& abs_time)156 {157 aux::threading::mutex::lock(mutex_);158 auto res = aux::threading::condvar::wait_for(159 condvar_, mutex_,160 aux::threading::time::convert(abs_time - Clock::now())161 );162 aux::threading::mutex::unlock(mutex_);163 164 return res == ETIMEOUT ? future_status::timeout165 : future_status::ready;166 }167 168 ~shared_state() override = default;169 170 private:171 aux::mutex_t mutex_;172 aux::condvar_t condvar_;173 174 R value_;175 bool value_set_;176 177 exception_ptr exception_;178 bool has_exception_;179 205 }; 180 206 … … 224 250 } 225 251 226 template<class Rep, class Period> 227 future_status 228 wait_for(const chrono::duration<Rep, Period>&) override 252 ~async_shared_state() override 253 { 254 destroy(); 255 } 256 257 protected: 258 future_status timed_wait_(aux::time_unit_t) override 229 259 { 230 260 // TODO: have to sleep and check 231 return future_status::ready; 232 } 233 234 template<class Clock, class Duration> 235 future_status 236 wait_until(const chrono::time_point<Clock, Duration>&) override 237 { 238 // TODO: have to sleep and check 239 return future_status::ready; 240 } 241 242 ~async_shared_state() override 243 { 244 destroy(); 261 return future_status::timeout; 245 262 } 246 263 … … 261 278 void destroy() override 262 279 { 263 aux::threading::mutex::lock( mutex_);280 aux::threading::mutex::lock(this->mutex_); 264 281 if (!this->is_set()) 265 282 invoke_(make_index_sequence<sizeof...(Args)>{}); 266 aux::threading::mutex::unlock( mutex_);283 aux::threading::mutex::unlock(this->mutex_); 267 284 } 268 285 269 286 void wait() override 270 287 { 271 aux::threading::mutex::lock(mutex_); 288 /** 289 * Note: Synchronization done in invoke_ -> set_value. 290 */ 272 291 if (!this->is_set()) 273 292 invoke_(make_index_sequence<sizeof...(Args)>{}); 274 aux::threading::mutex::unlock(mutex_);275 }276 277 template<class Rep, class Period>278 future_status279 wait_for(const chrono::duration<Rep, Period>&) override280 {281 /**282 * Note: Neither of the wait_ functions has any effect283 * for deferred functions spawned by async (which284 * are the only users of this state type).285 */286 return future_status::deferred;287 }288 289 template<class Clock, class Duration>290 future_status291 wait_until(const chrono::time_point<Clock, Duration>&) override292 {293 return future_status::deferred;294 293 } 295 294 … … 299 298 } 300 299 301 pr ivate:300 protected: 302 301 function<R(decay_t<Args>...)> func_; 303 302 tuple<decay_t<Args>...> args_; … … 315 314 } 316 315 } 316 317 future_status timed_wait_(aux::time_unit_t) override 318 { 319 /** 320 * Note: Neither of the wait_ functions has any effect 321 * for deferred functions spawned by async (which 322 * are the only users of this state type). 323 */ 324 return future_status::deferred; 325 } 317 326 }; 318 327 }
Note:
See TracChangeset
for help on using the changeset viewer.