xref: /freebsd-12.1/contrib/libc++/src/future.cpp (revision b5893f02)
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 Andric future_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 Chisnall future_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 Chisnall future_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 Chisnall future<void>::future(__assoc_sub_state* __state)
1807a984708SDavid Chisnall     : __state_(__state)
1817a984708SDavid Chisnall {
182*b5893f02SDimitry Andric     __state_->__attach_future();
1837a984708SDavid Chisnall }
1847a984708SDavid Chisnall 
~future()1857a984708SDavid Chisnall future<void>::~future()
1867a984708SDavid Chisnall {
1877a984708SDavid Chisnall     if (__state_)
1887a984708SDavid Chisnall         __state_->__release_shared();
1897a984708SDavid Chisnall }
1907a984708SDavid Chisnall 
1917a984708SDavid Chisnall void
get()1927a984708SDavid Chisnall future<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 Chisnall promise<void>::promise()
2017a984708SDavid Chisnall     : __state_(new __assoc_sub_state)
2027a984708SDavid Chisnall {
2037a984708SDavid Chisnall }
2047a984708SDavid Chisnall 
~promise()2057a984708SDavid Chisnall promise<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 Chisnall promise<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 Chisnall promise<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 Chisnall promise<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 Chisnall promise<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 Chisnall promise<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 Chisnall shared_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 Chisnall shared_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