Changeset 04c0fc5 in mainline
- Timestamp:
- 2019-06-27T15:55:09Z (5 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 9eea0b7
- Parents:
- 8add15e0
- Location:
- uspace/lib/cpp
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/cpp/include/__bits/thread/future.hpp
r8add15e0 r04c0fc5 30 30 #define LIBCPP_BITS_THREAD_FUTURE 31 31 32 #include <__bits/refcount_obj.hpp> 33 #include <__bits/thread/threading.hpp> 32 34 #include <cassert> 33 35 #include <memory> 34 36 #include <system_error> 35 37 #include <type_traits> 38 #include <utility> 36 39 37 40 namespace std … … 85 88 86 89 const error_code& code() const noexcept; 90 const char* what() const noexcept; 87 91 88 92 private: … … 94 98 */ 95 99 100 namespace aux 101 { 102 template<class R> 103 class shared_state: public aux::refcount_obj 104 { 105 public: 106 const bool is_deferred_function; 107 108 shared_state(bool is_deferred = false) 109 : is_deferred_function{is_deferred}, mutex_{}, 110 condvar_{}, value_{}, value_set_{false}, 111 exception_{}, has_exception_{false} 112 { 113 threading::mutex::init(mutex_); 114 threading::condvar::init(condvar_); 115 } 116 117 void destroy() override 118 { 119 if (this->refs() < 1) 120 { 121 // TODO: what to destroy? just this? 122 } 123 } 124 125 void set_value(const R& val, bool set) 126 { 127 value_ = val; 128 value_set_ = set; 129 } 130 131 void set_value(R&& val, bool set) 132 { 133 aux::threading::mutex::lock(mutex_); 134 value_ = std::move(val); 135 value_set_ = set; 136 aux::threading::mutex::unlock(mutex_); 137 138 aux::threading::condvar::broadcast(condvar_); 139 } 140 141 void set_set(bool set = true) noexcept 142 { 143 value_set_ = set; 144 } 145 146 bool is_set() const noexcept 147 { 148 return value_set_; 149 } 150 151 R& get() 152 { 153 return value_; 154 } 155 156 void set_exception(exception_ptr ptr) 157 { 158 exception_ = ptr; 159 has_exception_ = true; 160 } 161 162 bool has_exception() const noexcept 163 { 164 return has_exception_; 165 } 166 167 void throw_stored_exception() const 168 { 169 // TODO: implement 170 } 171 172 /** 173 * TODO: This member function is supposed to be marked 174 * as 'const'. In such a case, however, we cannot 175 * use the underlying fibril API because these 176 * references get converted to pointers and the API 177 * does not accept e.g. 'const fibril_condvar_t*'. 178 * 179 * The same applies to the wait_for and wait_until 180 * functions. 181 */ 182 void wait() 183 { 184 aux::threading::mutex::lock(mutex_); 185 while (!value_set_) 186 aux::threading::condvar::wait(condvar_, mutex_); 187 aux::threading::mutex::unlock(mutex_); 188 } 189 190 template<class Rep, class Period> 191 bool wait_for(const chrono::duration<Rep, Period>& rel_time) 192 { 193 aux::threading::mutex::lock(mutex_); 194 aux::threading::condvar::wait_for( 195 condvar_, mutex_, 196 aux::threading::time::convert(rel_time) 197 ); 198 aux::threading::mutex::unlock(mutex_); 199 200 return value_set_; 201 } 202 203 template<class Clock, class Duration> 204 bool wait_until(const chrono::time_point<Clock, Duration>& abs_time) 205 { 206 aux::threading::mutex::lock(mutex_); 207 aux::threading::condvar::wait_for( 208 condvar_, mutex_, 209 aux::threading::time::convert(abs_time - Clock::now()) 210 ); 211 aux::threading::mutex::unlock(mutex_); 212 213 return value_set_; 214 } 215 216 ~shared_state() 217 { 218 // TODO: just destroy? 219 } 220 221 private: 222 aux::mutex_t mutex_; 223 aux::condvar_t condvar_; 224 225 R value_; 226 bool value_set_; 227 228 exception_ptr exception_; 229 bool has_exception_; 230 }; 231 } 232 233 template<class R> 234 class future; 235 96 236 template<class R> 97 237 class promise 98 238 { 239 public: 240 promise() 241 : state_{new aux::shared_state<R>{}} 242 { /* DUMMY BODY */ } 243 244 template<class Allocator> 245 promise(allocator_arg_t, const Allocator& a) 246 : promise{} 247 { 248 // TODO: Use the allocator. 249 } 250 251 promise(promise&& rhs) noexcept 252 : state_{} 253 { 254 state_ = rhs.state_; 255 rhs.state_ = nullptr; 256 } 257 258 promise(const promise&) = delete; 259 260 ~promise() 261 { 262 abandon_state_(); 263 } 264 265 promise& operator=(promise&& rhs) noexcept 266 { 267 abandon_state_(); 268 promise{std::move(rhs)}.swap(*this); 269 } 270 271 promise& operator=(const promise&) = delete; 272 273 void swap(promise& other) noexcept 274 { 275 std::swap(state_, other.state_); 276 } 277 278 future<R> get_future() 279 { 280 return future<R>{state_}; 281 } 282 283 void set_value(const R& val) 284 { 285 if (!state_) 286 throw future_error{make_error_code(future_errc::no_state)}; 287 if (state_->is_set()) 288 { 289 throw future_error{ 290 make_error_code(future_errc::promise_already_satisfied) 291 }; 292 } 293 294 state_->set_value(val, true); 295 } 296 297 void set_value(R&& val) 298 { 299 if (!state_) 300 throw future_error{make_error_code(future_errc::no_state)}; 301 if (state_->is_set()) 302 { 303 throw future_error{ 304 make_error_code(future_errc::promise_already_satisfied) 305 }; 306 } 307 308 state_->set_value(std::forward<R>(val), true); 309 } 310 311 void set_exception(exception_ptr ptr) 312 { 313 assert(state_); 314 315 state_->set_exception(ptr); 316 } 317 318 void set_value_at_thread_exit(const R& val) 319 { 320 if (!state_) 321 throw future_error{make_error_code(future_errc::no_state)}; 322 if (state_->is_set()) 323 { 324 throw future_error{ 325 make_error_code(future_errc::promise_already_satisfied) 326 }; 327 } 328 329 state_->set_value(val, false); 330 // TODO: schedule it to be set as ready when thread exits 331 } 332 333 void set_value_at_thread_exit(R&& val) 334 { 335 if (!state_) 336 throw future_error{make_error_code(future_errc::no_state)}; 337 if (state_->is_set()) 338 { 339 throw future_error{ 340 make_error_code(future_errc::promise_already_satisfied) 341 }; 342 } 343 344 state_->set_value(std::forward<R>(val), false); 345 // TODO: schedule it to be set as ready when thread exits 346 } 347 348 void set_exception_at_thread_exit(exception_ptr) 349 { 350 // TODO: No exception handling, no-op at this time. 351 } 352 353 private: 354 void abandon_state_() 355 { 356 /** 357 * 1) If state is not ready: 358 * a) Store exception of type future_error with 359 * error condition broken_promise. 360 * b) Mark state as ready. 361 * 2) Rekease the state. 362 */ 363 } 364 365 aux::shared_state<R>* state_; 99 366 }; 100 367 … … 102 369 class promise<R&> 103 370 { 371 // TODO: Copy & modify once promise is done. 104 372 }; 105 373 … … 107 375 class promise<void> 108 376 { 377 // TODO: Copy & modify once promise is done. 109 378 }; 110 379 … … 120 389 121 390 template<class R> 391 class shared_future; 392 393 template<class R> 122 394 class future 123 395 { 396 public: 397 future() noexcept 398 : state_{nullptr} 399 { /* DUMMY BODY */ } 400 401 future(const future&) = delete; 402 403 future(future&& rhs) noexcept 404 : state_{std::move(rhs.state_)} 405 { 406 rhs.state_ = nullptr; 407 } 408 409 future(aux::shared_state<R>* state) 410 : state_{state} 411 { 412 /** 413 * Note: This is a custom non-standard constructor that allows 414 * us to create a future directly from a shared state. This 415 * should never be a problem as aux::shared_state is a private 416 * type and future has no constructor templates. 417 */ 418 } 419 420 ~future() 421 { 422 release_state_(); 423 } 424 425 future& operator=(const future) = delete; 426 427 future& operator=(future&& rhs) noexcept 428 { 429 release_state_(); 430 state_ = std::move(rhs.state_); 431 rhs.state_ = nullptr; 432 } 433 434 shared_future<R> share() 435 { 436 return shared_future<R>(std::move(*this)); 437 } 438 439 R get() 440 { 441 assert(state_); 442 443 wait(); 444 445 auto state = state_; 446 state_ = nullptr; 447 if (state->has_exception()) 448 state->throw_stored_exception(); 449 450 return std::move(state->get()); 451 } 452 453 bool valid() const noexcept 454 { 455 return state_ != nullptr; 456 } 457 458 void wait() const noexcept 459 { 460 assert(state_); 461 462 state_->wait(); 463 } 464 465 template<class Rep, class Period> 466 future_status wait_for(const chrono::duration<Rep, Period>& rel_time) const 467 { 468 assert(state_); 469 if (state_->is_deffered_function) 470 return future_status::deferred; 471 472 auto res = state_->wait_for(rel_time); 473 474 if (res) 475 return future_status::ready; 476 else 477 return future_status::timeout; 478 } 479 480 template<class Clock, class Duration> 481 future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) const 482 { 483 assert(state_); 484 if (state_->is_deffered_function) 485 return future_status::deferred; 486 487 auto res = state_->wait_until(abs_time); 488 489 if (res) 490 return future_status::ready; 491 else 492 return future_status::timeout; 493 } 494 495 private: 496 void release_state_() 497 { 498 /** 499 * Last reference to state -> destroy state. 500 * Decrement refcount of state otherwise. 501 * Will not block, unless all following hold: 502 * 1) State was created by call to std::async. 503 * 2) State is not yet ready. 504 * 3) This was the last reference to the shared state. 505 */ 506 } 507 508 aux::shared_state<R>* state_; 124 509 }; 125 510 … … 127 512 class future<R&> 128 513 { 514 // TODO: Copy & modify once future is done. 129 515 }; 130 516 … … 132 518 class future<void> 133 519 { 134 }; 135 520 // TODO: Copy & modify once future is done. 521 }; 522 523 // TODO: Make sure the move constructor of shared_future 524 // invalidates the state (i.e. sets to nullptr). 136 525 template<class R> 137 526 class shared_future 138 527 { 528 // TODO: Copy & modify once future is done. 139 529 }; 140 530 … … 142 532 class shared_future<R&> 143 533 { 534 // TODO: Copy & modify once future is done. 144 535 }; 145 536 … … 147 538 class shared_future<void> 148 539 { 540 // TODO: Copy & modify once future is done. 149 541 }; 150 542 … … 155 547 class packaged_task<R(Args...)> 156 548 { 549 packaged_task() noexcept 550 {} 551 552 template<class F> 553 explicit packaged_task(F&& f) 554 {} 555 556 template<class F, class Allocator> 557 explicit packaged_task(allocator_arg_t, const Allocator& a, F&& f) 558 {} 559 560 ~packaged_task() 561 {} 562 563 packaged_task(const packaged_task&) = delete; 564 packaged_task& operator=(const packaged_task&) = delete; 565 566 packaged_task(packaged_task&& rhs) 567 {} 568 569 packaged_task& operator=(packaged_task&& rhs) 570 {} 571 572 void swap(packaged_task& other) noexcept 573 {} 574 575 bool valid() const noexcept 576 {} 577 578 future<R> get_future() 579 {} 580 581 void operator()(Args...) 582 {} 583 584 void make_ready_at_thread_exit(Args...) 585 {} 586 587 void reset() 588 {} 157 589 }; 158 590 -
uspace/lib/cpp/src/future.cpp
r8add15e0 r04c0fc5 81 81 return code_; 82 82 } 83 84 const char* future_error::what() const noexcept 85 { 86 return code().message().c_str(); 87 } 83 88 }
Note:
See TracChangeset
for help on using the changeset viewer.