xref: /freebsd/contrib/llvm-project/libcxx/src/future.cpp (revision cb14a3fe5122c879eae1fb480ed7ce82a699ddb6)
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 
14*cb14a3feSDimitry Andric class _LIBCPP_HIDDEN __future_error_category : public __do_message {
150b57cec5SDimitry Andric public:
16fe6060f1SDimitry Andric   virtual const char* name() const noexcept;
170b57cec5SDimitry Andric   virtual string message(int ev) const;
180b57cec5SDimitry Andric };
190b57cec5SDimitry Andric 
20*cb14a3feSDimitry Andric const char* __future_error_category::name() const noexcept { return "future"; }
210b57cec5SDimitry Andric 
2281ad6265SDimitry Andric _LIBCPP_DIAGNOSTIC_PUSH
2381ad6265SDimitry Andric _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wswitch")
2481ad6265SDimitry Andric _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wswitch")
250b57cec5SDimitry Andric 
26*cb14a3feSDimitry Andric string __future_error_category::message(int ev) const {
27*cb14a3feSDimitry Andric   switch (static_cast<future_errc>(ev)) {
280b57cec5SDimitry Andric   case future_errc(0): // For backwards compatibility with C++11 (LWG 2056)
290b57cec5SDimitry Andric   case future_errc::broken_promise:
300b57cec5SDimitry Andric     return string("The associated promise has been destructed prior "
310b57cec5SDimitry Andric                   "to the associated state becoming ready.");
320b57cec5SDimitry Andric   case future_errc::future_already_retrieved:
330b57cec5SDimitry Andric     return string("The future has already been retrieved from "
340b57cec5SDimitry Andric                   "the promise or packaged_task.");
350b57cec5SDimitry Andric   case future_errc::promise_already_satisfied:
360b57cec5SDimitry Andric     return string("The state of the promise has already been set.");
370b57cec5SDimitry Andric   case future_errc::no_state:
380b57cec5SDimitry Andric     return string("Operation not permitted on an object without "
390b57cec5SDimitry Andric                   "an associated state.");
400b57cec5SDimitry Andric   }
410b57cec5SDimitry Andric   return string("unspecified future_errc value\n");
420b57cec5SDimitry Andric }
430b57cec5SDimitry Andric 
4481ad6265SDimitry Andric _LIBCPP_DIAGNOSTIC_POP
450b57cec5SDimitry Andric 
46*cb14a3feSDimitry Andric const error_category& future_category() noexcept {
475f757f3fSDimitry Andric   union AvoidDestroyingFutureCategory {
485f757f3fSDimitry Andric     __future_error_category future_error_category;
495f757f3fSDimitry Andric     constexpr explicit AvoidDestroyingFutureCategory() : future_error_category() {}
505f757f3fSDimitry Andric     ~AvoidDestroyingFutureCategory() {}
515f757f3fSDimitry Andric   };
525f757f3fSDimitry Andric   constinit static AvoidDestroyingFutureCategory helper;
535f757f3fSDimitry Andric   return helper.future_error_category;
540b57cec5SDimitry Andric }
550b57cec5SDimitry Andric 
56*cb14a3feSDimitry Andric future_error::future_error(error_code __ec) : logic_error(__ec.message()), __ec_(__ec) {}
570b57cec5SDimitry Andric 
58*cb14a3feSDimitry Andric future_error::~future_error() noexcept {}
590b57cec5SDimitry Andric 
60*cb14a3feSDimitry Andric void __assoc_sub_state::__on_zero_shared() noexcept { delete this; }
610b57cec5SDimitry Andric 
62*cb14a3feSDimitry Andric void __assoc_sub_state::set_value() {
630b57cec5SDimitry Andric   unique_lock<mutex> __lk(__mut_);
640b57cec5SDimitry Andric   if (__has_value())
650b57cec5SDimitry Andric     __throw_future_error(future_errc::promise_already_satisfied);
660b57cec5SDimitry Andric   __state_ |= __constructed | ready;
670b57cec5SDimitry Andric   __cv_.notify_all();
680b57cec5SDimitry Andric }
690b57cec5SDimitry Andric 
70*cb14a3feSDimitry Andric void __assoc_sub_state::set_value_at_thread_exit() {
710b57cec5SDimitry Andric   unique_lock<mutex> __lk(__mut_);
720b57cec5SDimitry Andric   if (__has_value())
730b57cec5SDimitry Andric     __throw_future_error(future_errc::promise_already_satisfied);
740b57cec5SDimitry Andric   __state_ |= __constructed;
750b57cec5SDimitry Andric   __thread_local_data()->__make_ready_at_thread_exit(this);
760b57cec5SDimitry Andric }
770b57cec5SDimitry Andric 
78*cb14a3feSDimitry Andric void __assoc_sub_state::set_exception(exception_ptr __p) {
790b57cec5SDimitry Andric   unique_lock<mutex> __lk(__mut_);
800b57cec5SDimitry Andric   if (__has_value())
810b57cec5SDimitry Andric     __throw_future_error(future_errc::promise_already_satisfied);
820b57cec5SDimitry Andric   __exception_ = __p;
830b57cec5SDimitry Andric   __state_ |= ready;
840b57cec5SDimitry Andric   __cv_.notify_all();
850b57cec5SDimitry Andric }
860b57cec5SDimitry Andric 
87*cb14a3feSDimitry Andric void __assoc_sub_state::set_exception_at_thread_exit(exception_ptr __p) {
880b57cec5SDimitry Andric   unique_lock<mutex> __lk(__mut_);
890b57cec5SDimitry Andric   if (__has_value())
900b57cec5SDimitry Andric     __throw_future_error(future_errc::promise_already_satisfied);
910b57cec5SDimitry Andric   __exception_ = __p;
920b57cec5SDimitry Andric   __thread_local_data()->__make_ready_at_thread_exit(this);
930b57cec5SDimitry Andric }
940b57cec5SDimitry Andric 
95*cb14a3feSDimitry Andric void __assoc_sub_state::__make_ready() {
960b57cec5SDimitry Andric   unique_lock<mutex> __lk(__mut_);
970b57cec5SDimitry Andric   __state_ |= ready;
980b57cec5SDimitry Andric   __cv_.notify_all();
990b57cec5SDimitry Andric }
1000b57cec5SDimitry Andric 
101*cb14a3feSDimitry Andric void __assoc_sub_state::copy() {
1020b57cec5SDimitry Andric   unique_lock<mutex> __lk(__mut_);
1030b57cec5SDimitry Andric   __sub_wait(__lk);
1040b57cec5SDimitry Andric   if (__exception_ != nullptr)
1050b57cec5SDimitry Andric     rethrow_exception(__exception_);
1060b57cec5SDimitry Andric }
1070b57cec5SDimitry Andric 
108*cb14a3feSDimitry Andric void __assoc_sub_state::wait() {
1090b57cec5SDimitry Andric   unique_lock<mutex> __lk(__mut_);
1100b57cec5SDimitry Andric   __sub_wait(__lk);
1110b57cec5SDimitry Andric }
1120b57cec5SDimitry Andric 
113*cb14a3feSDimitry Andric void __assoc_sub_state::__sub_wait(unique_lock<mutex>& __lk) {
114*cb14a3feSDimitry Andric   if (!__is_ready()) {
115*cb14a3feSDimitry Andric     if (__state_ & static_cast<unsigned>(deferred)) {
1160b57cec5SDimitry Andric       __state_ &= ~static_cast<unsigned>(deferred);
1170b57cec5SDimitry Andric       __lk.unlock();
1180b57cec5SDimitry Andric       __execute();
119*cb14a3feSDimitry Andric     } else
1200b57cec5SDimitry Andric       while (!__is_ready())
1210b57cec5SDimitry Andric         __cv_.wait(__lk);
1220b57cec5SDimitry Andric   }
1230b57cec5SDimitry Andric }
1240b57cec5SDimitry Andric 
125*cb14a3feSDimitry Andric void __assoc_sub_state::__execute() { __throw_future_error(future_errc::no_state); }
1260b57cec5SDimitry Andric 
127*cb14a3feSDimitry Andric future<void>::future(__assoc_sub_state* __state) : __state_(__state) { __state_->__attach_future(); }
1280b57cec5SDimitry Andric 
129*cb14a3feSDimitry Andric future<void>::~future() {
1300b57cec5SDimitry Andric   if (__state_)
1310b57cec5SDimitry Andric     __state_->__release_shared();
1320b57cec5SDimitry Andric }
1330b57cec5SDimitry Andric 
134*cb14a3feSDimitry Andric void future<void>::get() {
1350b57cec5SDimitry Andric   unique_ptr<__shared_count, __release_shared_count> __(__state_);
1360b57cec5SDimitry Andric   __assoc_sub_state* __s = __state_;
1370b57cec5SDimitry Andric   __state_               = nullptr;
1380b57cec5SDimitry Andric   __s->copy();
1390b57cec5SDimitry Andric }
1400b57cec5SDimitry Andric 
141*cb14a3feSDimitry Andric promise<void>::promise() : __state_(new __assoc_sub_state) {}
1420b57cec5SDimitry Andric 
143*cb14a3feSDimitry Andric promise<void>::~promise() {
144*cb14a3feSDimitry Andric   if (__state_) {
14506c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
1460b57cec5SDimitry Andric     if (!__state_->__has_value() && __state_->use_count() > 1)
1475f757f3fSDimitry Andric       __state_->set_exception(make_exception_ptr(future_error(future_errc::broken_promise)));
14806c3fb27SDimitry Andric #endif // _LIBCPP_HAS_NO_EXCEPTIONS
1490b57cec5SDimitry Andric     __state_->__release_shared();
1500b57cec5SDimitry Andric   }
1510b57cec5SDimitry Andric }
1520b57cec5SDimitry Andric 
153*cb14a3feSDimitry Andric future<void> promise<void>::get_future() {
1540b57cec5SDimitry Andric   if (__state_ == nullptr)
1550b57cec5SDimitry Andric     __throw_future_error(future_errc::no_state);
1560b57cec5SDimitry Andric   return future<void>(__state_);
1570b57cec5SDimitry Andric }
1580b57cec5SDimitry Andric 
159*cb14a3feSDimitry Andric void promise<void>::set_value() {
1600b57cec5SDimitry Andric   if (__state_ == nullptr)
1610b57cec5SDimitry Andric     __throw_future_error(future_errc::no_state);
1620b57cec5SDimitry Andric   __state_->set_value();
1630b57cec5SDimitry Andric }
1640b57cec5SDimitry Andric 
165*cb14a3feSDimitry Andric void promise<void>::set_exception(exception_ptr __p) {
1660b57cec5SDimitry Andric   if (__state_ == nullptr)
1670b57cec5SDimitry Andric     __throw_future_error(future_errc::no_state);
1680b57cec5SDimitry Andric   __state_->set_exception(__p);
1690b57cec5SDimitry Andric }
1700b57cec5SDimitry Andric 
171*cb14a3feSDimitry Andric void promise<void>::set_value_at_thread_exit() {
1720b57cec5SDimitry Andric   if (__state_ == nullptr)
1730b57cec5SDimitry Andric     __throw_future_error(future_errc::no_state);
1740b57cec5SDimitry Andric   __state_->set_value_at_thread_exit();
1750b57cec5SDimitry Andric }
1760b57cec5SDimitry Andric 
177*cb14a3feSDimitry Andric void promise<void>::set_exception_at_thread_exit(exception_ptr __p) {
1780b57cec5SDimitry Andric   if (__state_ == nullptr)
1790b57cec5SDimitry Andric     __throw_future_error(future_errc::no_state);
1800b57cec5SDimitry Andric   __state_->set_exception_at_thread_exit(__p);
1810b57cec5SDimitry Andric }
1820b57cec5SDimitry Andric 
183*cb14a3feSDimitry Andric shared_future<void>::~shared_future() {
1840b57cec5SDimitry Andric   if (__state_)
1850b57cec5SDimitry Andric     __state_->__release_shared();
1860b57cec5SDimitry Andric }
1870b57cec5SDimitry Andric 
188*cb14a3feSDimitry Andric shared_future<void>& shared_future<void>::operator=(const shared_future& __rhs) {
1890b57cec5SDimitry Andric   if (__rhs.__state_)
1900b57cec5SDimitry Andric     __rhs.__state_->__add_shared();
1910b57cec5SDimitry Andric   if (__state_)
1920b57cec5SDimitry Andric     __state_->__release_shared();
1930b57cec5SDimitry Andric   __state_ = __rhs.__state_;
1940b57cec5SDimitry Andric   return *this;
1950b57cec5SDimitry Andric }
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric _LIBCPP_END_NAMESPACE_STD
198