1349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 981ad6265SDimitry Andric #include <future> 1081ad6265SDimitry Andric #include <string> 110b57cec5SDimitry Andric 120b57cec5SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric class _LIBCPP_HIDDEN __future_error_category 150b57cec5SDimitry Andric : public __do_message 160b57cec5SDimitry Andric { 170b57cec5SDimitry Andric public: 18fe6060f1SDimitry Andric virtual const char* name() const noexcept; 190b57cec5SDimitry Andric virtual string message(int ev) const; 200b57cec5SDimitry Andric }; 210b57cec5SDimitry Andric 220b57cec5SDimitry Andric const char* 23fe6060f1SDimitry Andric __future_error_category::name() const noexcept 240b57cec5SDimitry Andric { 250b57cec5SDimitry Andric return "future"; 260b57cec5SDimitry Andric } 270b57cec5SDimitry Andric 2881ad6265SDimitry Andric _LIBCPP_DIAGNOSTIC_PUSH 2981ad6265SDimitry Andric _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wswitch") 3081ad6265SDimitry Andric _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wswitch") 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric string 330b57cec5SDimitry Andric __future_error_category::message(int ev) const 340b57cec5SDimitry Andric { 350b57cec5SDimitry Andric switch (static_cast<future_errc>(ev)) 360b57cec5SDimitry Andric { 370b57cec5SDimitry Andric case future_errc(0): // For backwards compatibility with C++11 (LWG 2056) 380b57cec5SDimitry Andric case future_errc::broken_promise: 390b57cec5SDimitry Andric return string("The associated promise has been destructed prior " 400b57cec5SDimitry Andric "to the associated state becoming ready."); 410b57cec5SDimitry Andric case future_errc::future_already_retrieved: 420b57cec5SDimitry Andric return string("The future has already been retrieved from " 430b57cec5SDimitry Andric "the promise or packaged_task."); 440b57cec5SDimitry Andric case future_errc::promise_already_satisfied: 450b57cec5SDimitry Andric return string("The state of the promise has already been set."); 460b57cec5SDimitry Andric case future_errc::no_state: 470b57cec5SDimitry Andric return string("Operation not permitted on an object without " 480b57cec5SDimitry Andric "an associated state."); 490b57cec5SDimitry Andric } 500b57cec5SDimitry Andric return string("unspecified future_errc value\n"); 510b57cec5SDimitry Andric } 520b57cec5SDimitry Andric 5381ad6265SDimitry Andric _LIBCPP_DIAGNOSTIC_POP 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric const error_category& 56fe6060f1SDimitry Andric future_category() noexcept 570b57cec5SDimitry Andric { 58*5f757f3fSDimitry Andric union AvoidDestroyingFutureCategory { 59*5f757f3fSDimitry Andric __future_error_category future_error_category; 60*5f757f3fSDimitry Andric constexpr explicit AvoidDestroyingFutureCategory() : future_error_category() {} 61*5f757f3fSDimitry Andric ~AvoidDestroyingFutureCategory() {} 62*5f757f3fSDimitry Andric }; 63*5f757f3fSDimitry Andric constinit static AvoidDestroyingFutureCategory helper; 64*5f757f3fSDimitry Andric return helper.future_error_category; 650b57cec5SDimitry Andric } 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric future_error::future_error(error_code __ec) 680b57cec5SDimitry Andric : logic_error(__ec.message()), 690b57cec5SDimitry Andric __ec_(__ec) 700b57cec5SDimitry Andric { 710b57cec5SDimitry Andric } 720b57cec5SDimitry Andric 73fe6060f1SDimitry Andric future_error::~future_error() noexcept 740b57cec5SDimitry Andric { 750b57cec5SDimitry Andric } 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric void 78fe6060f1SDimitry Andric __assoc_sub_state::__on_zero_shared() noexcept 790b57cec5SDimitry Andric { 800b57cec5SDimitry Andric delete this; 810b57cec5SDimitry Andric } 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric void 840b57cec5SDimitry Andric __assoc_sub_state::set_value() 850b57cec5SDimitry Andric { 860b57cec5SDimitry Andric unique_lock<mutex> __lk(__mut_); 870b57cec5SDimitry Andric if (__has_value()) 880b57cec5SDimitry Andric __throw_future_error(future_errc::promise_already_satisfied); 890b57cec5SDimitry Andric __state_ |= __constructed | ready; 900b57cec5SDimitry Andric __cv_.notify_all(); 910b57cec5SDimitry Andric } 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric void 940b57cec5SDimitry Andric __assoc_sub_state::set_value_at_thread_exit() 950b57cec5SDimitry Andric { 960b57cec5SDimitry Andric unique_lock<mutex> __lk(__mut_); 970b57cec5SDimitry Andric if (__has_value()) 980b57cec5SDimitry Andric __throw_future_error(future_errc::promise_already_satisfied); 990b57cec5SDimitry Andric __state_ |= __constructed; 1000b57cec5SDimitry Andric __thread_local_data()->__make_ready_at_thread_exit(this); 1010b57cec5SDimitry Andric } 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric void 1040b57cec5SDimitry Andric __assoc_sub_state::set_exception(exception_ptr __p) 1050b57cec5SDimitry Andric { 1060b57cec5SDimitry Andric unique_lock<mutex> __lk(__mut_); 1070b57cec5SDimitry Andric if (__has_value()) 1080b57cec5SDimitry Andric __throw_future_error(future_errc::promise_already_satisfied); 1090b57cec5SDimitry Andric __exception_ = __p; 1100b57cec5SDimitry Andric __state_ |= ready; 1110b57cec5SDimitry Andric __cv_.notify_all(); 1120b57cec5SDimitry Andric } 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric void 1150b57cec5SDimitry Andric __assoc_sub_state::set_exception_at_thread_exit(exception_ptr __p) 1160b57cec5SDimitry Andric { 1170b57cec5SDimitry Andric unique_lock<mutex> __lk(__mut_); 1180b57cec5SDimitry Andric if (__has_value()) 1190b57cec5SDimitry Andric __throw_future_error(future_errc::promise_already_satisfied); 1200b57cec5SDimitry Andric __exception_ = __p; 1210b57cec5SDimitry Andric __thread_local_data()->__make_ready_at_thread_exit(this); 1220b57cec5SDimitry Andric } 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric void 1250b57cec5SDimitry Andric __assoc_sub_state::__make_ready() 1260b57cec5SDimitry Andric { 1270b57cec5SDimitry Andric unique_lock<mutex> __lk(__mut_); 1280b57cec5SDimitry Andric __state_ |= ready; 1290b57cec5SDimitry Andric __cv_.notify_all(); 1300b57cec5SDimitry Andric } 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric void 1330b57cec5SDimitry Andric __assoc_sub_state::copy() 1340b57cec5SDimitry Andric { 1350b57cec5SDimitry Andric unique_lock<mutex> __lk(__mut_); 1360b57cec5SDimitry Andric __sub_wait(__lk); 1370b57cec5SDimitry Andric if (__exception_ != nullptr) 1380b57cec5SDimitry Andric rethrow_exception(__exception_); 1390b57cec5SDimitry Andric } 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric void 1420b57cec5SDimitry Andric __assoc_sub_state::wait() 1430b57cec5SDimitry Andric { 1440b57cec5SDimitry Andric unique_lock<mutex> __lk(__mut_); 1450b57cec5SDimitry Andric __sub_wait(__lk); 1460b57cec5SDimitry Andric } 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric void 1490b57cec5SDimitry Andric __assoc_sub_state::__sub_wait(unique_lock<mutex>& __lk) 1500b57cec5SDimitry Andric { 1510b57cec5SDimitry Andric if (!__is_ready()) 1520b57cec5SDimitry Andric { 1530b57cec5SDimitry Andric if (__state_ & static_cast<unsigned>(deferred)) 1540b57cec5SDimitry Andric { 1550b57cec5SDimitry Andric __state_ &= ~static_cast<unsigned>(deferred); 1560b57cec5SDimitry Andric __lk.unlock(); 1570b57cec5SDimitry Andric __execute(); 1580b57cec5SDimitry Andric } 1590b57cec5SDimitry Andric else 1600b57cec5SDimitry Andric while (!__is_ready()) 1610b57cec5SDimitry Andric __cv_.wait(__lk); 1620b57cec5SDimitry Andric } 1630b57cec5SDimitry Andric } 1640b57cec5SDimitry Andric 1650b57cec5SDimitry Andric void 1660b57cec5SDimitry Andric __assoc_sub_state::__execute() 1670b57cec5SDimitry Andric { 1680b57cec5SDimitry Andric __throw_future_error(future_errc::no_state); 1690b57cec5SDimitry Andric } 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric future<void>::future(__assoc_sub_state* __state) 1720b57cec5SDimitry Andric : __state_(__state) 1730b57cec5SDimitry Andric { 1740b57cec5SDimitry Andric __state_->__attach_future(); 1750b57cec5SDimitry Andric } 1760b57cec5SDimitry Andric 1770b57cec5SDimitry Andric future<void>::~future() 1780b57cec5SDimitry Andric { 1790b57cec5SDimitry Andric if (__state_) 1800b57cec5SDimitry Andric __state_->__release_shared(); 1810b57cec5SDimitry Andric } 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric void 1840b57cec5SDimitry Andric future<void>::get() 1850b57cec5SDimitry Andric { 1860b57cec5SDimitry Andric unique_ptr<__shared_count, __release_shared_count> __(__state_); 1870b57cec5SDimitry Andric __assoc_sub_state* __s = __state_; 1880b57cec5SDimitry Andric __state_ = nullptr; 1890b57cec5SDimitry Andric __s->copy(); 1900b57cec5SDimitry Andric } 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric promise<void>::promise() 1930b57cec5SDimitry Andric : __state_(new __assoc_sub_state) 1940b57cec5SDimitry Andric { 1950b57cec5SDimitry Andric } 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric promise<void>::~promise() 1980b57cec5SDimitry Andric { 1990b57cec5SDimitry Andric if (__state_) 2000b57cec5SDimitry Andric { 20106c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS 2020b57cec5SDimitry Andric if (!__state_->__has_value() && __state_->use_count() > 1) 203*5f757f3fSDimitry Andric __state_->set_exception(make_exception_ptr(future_error(future_errc::broken_promise))); 20406c3fb27SDimitry Andric #endif // _LIBCPP_HAS_NO_EXCEPTIONS 2050b57cec5SDimitry Andric __state_->__release_shared(); 2060b57cec5SDimitry Andric } 2070b57cec5SDimitry Andric } 2080b57cec5SDimitry Andric 2090b57cec5SDimitry Andric future<void> 2100b57cec5SDimitry Andric promise<void>::get_future() 2110b57cec5SDimitry Andric { 2120b57cec5SDimitry Andric if (__state_ == nullptr) 2130b57cec5SDimitry Andric __throw_future_error(future_errc::no_state); 2140b57cec5SDimitry Andric return future<void>(__state_); 2150b57cec5SDimitry Andric } 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric void 2180b57cec5SDimitry Andric promise<void>::set_value() 2190b57cec5SDimitry Andric { 2200b57cec5SDimitry Andric if (__state_ == nullptr) 2210b57cec5SDimitry Andric __throw_future_error(future_errc::no_state); 2220b57cec5SDimitry Andric __state_->set_value(); 2230b57cec5SDimitry Andric } 2240b57cec5SDimitry Andric 2250b57cec5SDimitry Andric void 2260b57cec5SDimitry Andric promise<void>::set_exception(exception_ptr __p) 2270b57cec5SDimitry Andric { 2280b57cec5SDimitry Andric if (__state_ == nullptr) 2290b57cec5SDimitry Andric __throw_future_error(future_errc::no_state); 2300b57cec5SDimitry Andric __state_->set_exception(__p); 2310b57cec5SDimitry Andric } 2320b57cec5SDimitry Andric 2330b57cec5SDimitry Andric void 2340b57cec5SDimitry Andric promise<void>::set_value_at_thread_exit() 2350b57cec5SDimitry Andric { 2360b57cec5SDimitry Andric if (__state_ == nullptr) 2370b57cec5SDimitry Andric __throw_future_error(future_errc::no_state); 2380b57cec5SDimitry Andric __state_->set_value_at_thread_exit(); 2390b57cec5SDimitry Andric } 2400b57cec5SDimitry Andric 2410b57cec5SDimitry Andric void 2420b57cec5SDimitry Andric promise<void>::set_exception_at_thread_exit(exception_ptr __p) 2430b57cec5SDimitry Andric { 2440b57cec5SDimitry Andric if (__state_ == nullptr) 2450b57cec5SDimitry Andric __throw_future_error(future_errc::no_state); 2460b57cec5SDimitry Andric __state_->set_exception_at_thread_exit(__p); 2470b57cec5SDimitry Andric } 2480b57cec5SDimitry Andric 2490b57cec5SDimitry Andric shared_future<void>::~shared_future() 2500b57cec5SDimitry Andric { 2510b57cec5SDimitry Andric if (__state_) 2520b57cec5SDimitry Andric __state_->__release_shared(); 2530b57cec5SDimitry Andric } 2540b57cec5SDimitry Andric 2550b57cec5SDimitry Andric shared_future<void>& 2560b57cec5SDimitry Andric shared_future<void>::operator=(const shared_future& __rhs) 2570b57cec5SDimitry Andric { 2580b57cec5SDimitry Andric if (__rhs.__state_) 2590b57cec5SDimitry Andric __rhs.__state_->__add_shared(); 2600b57cec5SDimitry Andric if (__state_) 2610b57cec5SDimitry Andric __state_->__release_shared(); 2620b57cec5SDimitry Andric __state_ = __rhs.__state_; 2630b57cec5SDimitry Andric return *this; 2640b57cec5SDimitry Andric } 2650b57cec5SDimitry Andric 2660b57cec5SDimitry Andric _LIBCPP_END_NAMESPACE_STD 267