17a984708SDavid Chisnall //===------------------------- future.cpp ---------------------------------===// 27a984708SDavid Chisnall // 37a984708SDavid Chisnall // The LLVM Compiler Infrastructure 47a984708SDavid Chisnall // 57a984708SDavid Chisnall // This file is dual licensed under the MIT and the University of Illinois Open 67a984708SDavid Chisnall // Source Licenses. See LICENSE.TXT for details. 77a984708SDavid Chisnall // 87a984708SDavid Chisnall //===----------------------------------------------------------------------===// 97a984708SDavid Chisnall 10d72607e9SDimitry Andric #include "__config" 11d72607e9SDimitry Andric 12d72607e9SDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS 13d72607e9SDimitry Andric 147a984708SDavid Chisnall #include "future" 157a984708SDavid Chisnall #include "string" 167a984708SDavid Chisnall 177a984708SDavid Chisnall _LIBCPP_BEGIN_NAMESPACE_STD 187a984708SDavid Chisnall 197a984708SDavid Chisnall class _LIBCPP_HIDDEN __future_error_category 207a984708SDavid Chisnall : public __do_message 217a984708SDavid Chisnall { 227a984708SDavid Chisnall public: 237a984708SDavid Chisnall virtual const char* name() const _NOEXCEPT; 247a984708SDavid Chisnall virtual string message(int ev) const; 257a984708SDavid Chisnall }; 267a984708SDavid Chisnall 277a984708SDavid Chisnall const char* name() const287a984708SDavid Chisnall__future_error_category::name() const _NOEXCEPT 297a984708SDavid Chisnall { 307a984708SDavid Chisnall return "future"; 317a984708SDavid Chisnall } 327a984708SDavid Chisnall 33d72607e9SDimitry Andric #if defined(__clang__) 344f7ab58eSDimitry Andric #pragma clang diagnostic push 354f7ab58eSDimitry Andric #pragma clang diagnostic ignored "-Wswitch" 36d72607e9SDimitry Andric #elif defined(__GNUC__) || defined(__GNUG__) 37d72607e9SDimitry Andric #pragma GCC diagnostic push 38d72607e9SDimitry Andric #pragma GCC diagnostic ignored "-Wswitch" 39d72607e9SDimitry Andric #endif 404f7ab58eSDimitry Andric 417a984708SDavid Chisnall string message(int ev) const427a984708SDavid Chisnall__future_error_category::message(int ev) const 437a984708SDavid Chisnall { 4494e3ee44SDavid Chisnall switch (static_cast<future_errc>(ev)) 457a984708SDavid Chisnall { 464f7ab58eSDimitry Andric case future_errc(0): // For backwards compatibility with C++11 (LWG 2056) 477a984708SDavid Chisnall case future_errc::broken_promise: 487a984708SDavid Chisnall return string("The associated promise has been destructed prior " 497a984708SDavid Chisnall "to the associated state becoming ready."); 507a984708SDavid Chisnall case future_errc::future_already_retrieved: 517a984708SDavid Chisnall return string("The future has already been retrieved from " 527a984708SDavid Chisnall "the promise or packaged_task."); 537a984708SDavid Chisnall case future_errc::promise_already_satisfied: 547a984708SDavid Chisnall return string("The state of the promise has already been set."); 557a984708SDavid Chisnall case future_errc::no_state: 567a984708SDavid Chisnall return string("Operation not permitted on an object without " 577a984708SDavid Chisnall "an associated state."); 587a984708SDavid Chisnall } 597a984708SDavid Chisnall return string("unspecified future_errc value\n"); 607a984708SDavid Chisnall } 617a984708SDavid Chisnall 62d72607e9SDimitry Andric #if defined(__clang__) 634f7ab58eSDimitry Andric #pragma clang diagnostic pop 64d72607e9SDimitry Andric #elif defined(__GNUC__) || defined(__GNUG__) 65d72607e9SDimitry Andric #pragma GCC diagnostic pop 66d72607e9SDimitry Andric #endif 674f7ab58eSDimitry Andric 687a984708SDavid Chisnall const error_category& future_category()69936e9439SDimitry Andricfuture_category() _NOEXCEPT 707a984708SDavid Chisnall { 717a984708SDavid Chisnall static __future_error_category __f; 727a984708SDavid Chisnall return __f; 737a984708SDavid Chisnall } 747a984708SDavid Chisnall future_error(error_code __ec)757a984708SDavid Chisnallfuture_error::future_error(error_code __ec) 767a984708SDavid Chisnall : logic_error(__ec.message()), 777a984708SDavid Chisnall __ec_(__ec) 787a984708SDavid Chisnall { 797a984708SDavid Chisnall } 807a984708SDavid Chisnall ~future_error()817a984708SDavid Chisnallfuture_error::~future_error() _NOEXCEPT 827a984708SDavid Chisnall { 837a984708SDavid Chisnall } 847a984708SDavid Chisnall 857a984708SDavid Chisnall void __on_zero_shared()867a984708SDavid Chisnall__assoc_sub_state::__on_zero_shared() _NOEXCEPT 877a984708SDavid Chisnall { 887a984708SDavid Chisnall delete this; 897a984708SDavid Chisnall } 907a984708SDavid Chisnall 917a984708SDavid Chisnall void set_value()927a984708SDavid Chisnall__assoc_sub_state::set_value() 937a984708SDavid Chisnall { 947a984708SDavid Chisnall unique_lock<mutex> __lk(__mut_); 957a984708SDavid Chisnall if (__has_value()) 964ba319b5SDimitry Andric __throw_future_error(future_errc::promise_already_satisfied); 977a984708SDavid Chisnall __state_ |= __constructed | ready; 987a984708SDavid Chisnall __cv_.notify_all(); 997a984708SDavid Chisnall } 1007a984708SDavid Chisnall 1017a984708SDavid Chisnall void set_value_at_thread_exit()1027a984708SDavid Chisnall__assoc_sub_state::set_value_at_thread_exit() 1037a984708SDavid Chisnall { 1047a984708SDavid Chisnall unique_lock<mutex> __lk(__mut_); 1057a984708SDavid Chisnall if (__has_value()) 1064ba319b5SDimitry Andric __throw_future_error(future_errc::promise_already_satisfied); 1077a984708SDavid Chisnall __state_ |= __constructed; 1087a984708SDavid Chisnall __thread_local_data()->__make_ready_at_thread_exit(this); 1097a984708SDavid Chisnall } 1107a984708SDavid Chisnall 1117a984708SDavid Chisnall void set_exception(exception_ptr __p)1127a984708SDavid Chisnall__assoc_sub_state::set_exception(exception_ptr __p) 1137a984708SDavid Chisnall { 1147a984708SDavid Chisnall unique_lock<mutex> __lk(__mut_); 1157a984708SDavid Chisnall if (__has_value()) 1164ba319b5SDimitry Andric __throw_future_error(future_errc::promise_already_satisfied); 1177a984708SDavid Chisnall __exception_ = __p; 1187a984708SDavid Chisnall __state_ |= ready; 1197a984708SDavid Chisnall __cv_.notify_all(); 1207a984708SDavid Chisnall } 1217a984708SDavid Chisnall 1227a984708SDavid Chisnall void set_exception_at_thread_exit(exception_ptr __p)1237a984708SDavid Chisnall__assoc_sub_state::set_exception_at_thread_exit(exception_ptr __p) 1247a984708SDavid Chisnall { 1257a984708SDavid Chisnall unique_lock<mutex> __lk(__mut_); 1267a984708SDavid Chisnall if (__has_value()) 1274ba319b5SDimitry Andric __throw_future_error(future_errc::promise_already_satisfied); 1287a984708SDavid Chisnall __exception_ = __p; 1297a984708SDavid Chisnall __thread_local_data()->__make_ready_at_thread_exit(this); 1307a984708SDavid Chisnall } 1317a984708SDavid Chisnall 1327a984708SDavid Chisnall void __make_ready()1337a984708SDavid Chisnall__assoc_sub_state::__make_ready() 1347a984708SDavid Chisnall { 1357a984708SDavid Chisnall unique_lock<mutex> __lk(__mut_); 1367a984708SDavid Chisnall __state_ |= ready; 1377a984708SDavid Chisnall __cv_.notify_all(); 1387a984708SDavid Chisnall } 1397a984708SDavid Chisnall 1407a984708SDavid Chisnall void copy()1417a984708SDavid Chisnall__assoc_sub_state::copy() 1427a984708SDavid Chisnall { 1437a984708SDavid Chisnall unique_lock<mutex> __lk(__mut_); 1447a984708SDavid Chisnall __sub_wait(__lk); 1457a984708SDavid Chisnall if (__exception_ != nullptr) 1467a984708SDavid Chisnall rethrow_exception(__exception_); 1477a984708SDavid Chisnall } 1487a984708SDavid Chisnall 1497a984708SDavid Chisnall void wait()1507a984708SDavid Chisnall__assoc_sub_state::wait() 1517a984708SDavid Chisnall { 1527a984708SDavid Chisnall unique_lock<mutex> __lk(__mut_); 1537a984708SDavid Chisnall __sub_wait(__lk); 1547a984708SDavid Chisnall } 1557a984708SDavid Chisnall 1567a984708SDavid Chisnall void __sub_wait(unique_lock<mutex> & __lk)1577a984708SDavid Chisnall__assoc_sub_state::__sub_wait(unique_lock<mutex>& __lk) 1587a984708SDavid Chisnall { 1597a984708SDavid Chisnall if (!__is_ready()) 1607a984708SDavid Chisnall { 16194e3ee44SDavid Chisnall if (__state_ & static_cast<unsigned>(deferred)) 1627a984708SDavid Chisnall { 16394e3ee44SDavid Chisnall __state_ &= ~static_cast<unsigned>(deferred); 1647a984708SDavid Chisnall __lk.unlock(); 1657a984708SDavid Chisnall __execute(); 1667a984708SDavid Chisnall } 1677a984708SDavid Chisnall else 1687a984708SDavid Chisnall while (!__is_ready()) 1697a984708SDavid Chisnall __cv_.wait(__lk); 1707a984708SDavid Chisnall } 1717a984708SDavid Chisnall } 1727a984708SDavid Chisnall 1737a984708SDavid Chisnall void __execute()1747a984708SDavid Chisnall__assoc_sub_state::__execute() 1757a984708SDavid Chisnall { 1764ba319b5SDimitry Andric __throw_future_error(future_errc::no_state); 1777a984708SDavid Chisnall } 1787a984708SDavid Chisnall future(__assoc_sub_state * __state)1797a984708SDavid Chisnallfuture<void>::future(__assoc_sub_state* __state) 1807a984708SDavid Chisnall : __state_(__state) 1817a984708SDavid Chisnall { 182*b5893f02SDimitry Andric __state_->__attach_future(); 1837a984708SDavid Chisnall } 1847a984708SDavid Chisnall ~future()1857a984708SDavid Chisnallfuture<void>::~future() 1867a984708SDavid Chisnall { 1877a984708SDavid Chisnall if (__state_) 1887a984708SDavid Chisnall __state_->__release_shared(); 1897a984708SDavid Chisnall } 1907a984708SDavid Chisnall 1917a984708SDavid Chisnall void get()1927a984708SDavid Chisnallfuture<void>::get() 1937a984708SDavid Chisnall { 1947a984708SDavid Chisnall unique_ptr<__shared_count, __release_shared_count> __(__state_); 1957a984708SDavid Chisnall __assoc_sub_state* __s = __state_; 1967a984708SDavid Chisnall __state_ = nullptr; 1977a984708SDavid Chisnall __s->copy(); 1987a984708SDavid Chisnall } 1997a984708SDavid Chisnall promise()2007a984708SDavid Chisnallpromise<void>::promise() 2017a984708SDavid Chisnall : __state_(new __assoc_sub_state) 2027a984708SDavid Chisnall { 2037a984708SDavid Chisnall } 2047a984708SDavid Chisnall ~promise()2057a984708SDavid Chisnallpromise<void>::~promise() 2067a984708SDavid Chisnall { 2077a984708SDavid Chisnall if (__state_) 2087a984708SDavid Chisnall { 2099729cf09SDimitry Andric #ifndef _LIBCPP_NO_EXCEPTIONS 2107a984708SDavid Chisnall if (!__state_->__has_value() && __state_->use_count() > 1) 2117a984708SDavid Chisnall __state_->set_exception(make_exception_ptr( 2127a984708SDavid Chisnall future_error(make_error_code(future_errc::broken_promise)) 2137a984708SDavid Chisnall )); 2149729cf09SDimitry Andric #endif // _LIBCPP_NO_EXCEPTIONS 2157a984708SDavid Chisnall __state_->__release_shared(); 2167a984708SDavid Chisnall } 2177a984708SDavid Chisnall } 2187a984708SDavid Chisnall 2197a984708SDavid Chisnall future<void> get_future()2207a984708SDavid Chisnallpromise<void>::get_future() 2217a984708SDavid Chisnall { 2227a984708SDavid Chisnall if (__state_ == nullptr) 2234ba319b5SDimitry Andric __throw_future_error(future_errc::no_state); 2247a984708SDavid Chisnall return future<void>(__state_); 2257a984708SDavid Chisnall } 2267a984708SDavid Chisnall 2277a984708SDavid Chisnall void set_value()2287a984708SDavid Chisnallpromise<void>::set_value() 2297a984708SDavid Chisnall { 2307a984708SDavid Chisnall if (__state_ == nullptr) 2314ba319b5SDimitry Andric __throw_future_error(future_errc::no_state); 2327a984708SDavid Chisnall __state_->set_value(); 2337a984708SDavid Chisnall } 2347a984708SDavid Chisnall 2357a984708SDavid Chisnall void set_exception(exception_ptr __p)2367a984708SDavid Chisnallpromise<void>::set_exception(exception_ptr __p) 2377a984708SDavid Chisnall { 2387a984708SDavid Chisnall if (__state_ == nullptr) 2394ba319b5SDimitry Andric __throw_future_error(future_errc::no_state); 2407a984708SDavid Chisnall __state_->set_exception(__p); 2417a984708SDavid Chisnall } 2427a984708SDavid Chisnall 2437a984708SDavid Chisnall void set_value_at_thread_exit()2447a984708SDavid Chisnallpromise<void>::set_value_at_thread_exit() 2457a984708SDavid Chisnall { 2467a984708SDavid Chisnall if (__state_ == nullptr) 2474ba319b5SDimitry Andric __throw_future_error(future_errc::no_state); 2487a984708SDavid Chisnall __state_->set_value_at_thread_exit(); 2497a984708SDavid Chisnall } 2507a984708SDavid Chisnall 2517a984708SDavid Chisnall void set_exception_at_thread_exit(exception_ptr __p)2527a984708SDavid Chisnallpromise<void>::set_exception_at_thread_exit(exception_ptr __p) 2537a984708SDavid Chisnall { 2547a984708SDavid Chisnall if (__state_ == nullptr) 2554ba319b5SDimitry Andric __throw_future_error(future_errc::no_state); 2567a984708SDavid Chisnall __state_->set_exception_at_thread_exit(__p); 2577a984708SDavid Chisnall } 2587a984708SDavid Chisnall ~shared_future()2597a984708SDavid Chisnallshared_future<void>::~shared_future() 2607a984708SDavid Chisnall { 2617a984708SDavid Chisnall if (__state_) 2627a984708SDavid Chisnall __state_->__release_shared(); 2637a984708SDavid Chisnall } 2647a984708SDavid Chisnall 2657a984708SDavid Chisnall shared_future<void>& operator =(const shared_future & __rhs)2667a984708SDavid Chisnallshared_future<void>::operator=(const shared_future& __rhs) 2677a984708SDavid Chisnall { 2687a984708SDavid Chisnall if (__rhs.__state_) 2697a984708SDavid Chisnall __rhs.__state_->__add_shared(); 2707a984708SDavid Chisnall if (__state_) 2717a984708SDavid Chisnall __state_->__release_shared(); 2727a984708SDavid Chisnall __state_ = __rhs.__state_; 2737a984708SDavid Chisnall return *this; 2747a984708SDavid Chisnall } 2757a984708SDavid Chisnall 2767a984708SDavid Chisnall _LIBCPP_END_NAMESPACE_STD 277d72607e9SDimitry Andric 278d72607e9SDimitry Andric #endif // !_LIBCPP_HAS_NO_THREADS 279