Home | History | Annotate | Download | only in src
      1 //===------------------------- future.cpp ---------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is dual licensed under the MIT and the University of Illinois Open
      6 // Source Licenses. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "__config"
     11 
     12 #ifndef _LIBCPP_HAS_NO_THREADS
     13 
     14 #include "future"
     15 #include "string"
     16 
     17 _LIBCPP_BEGIN_NAMESPACE_STD
     18 
     19 class _LIBCPP_HIDDEN __future_error_category
     20     : public __do_message
     21 {
     22 public:
     23     virtual const char* name() const _NOEXCEPT;
     24     virtual string message(int ev) const;
     25 };
     26 
     27 const char*
     28 __future_error_category::name() const _NOEXCEPT
     29 {
     30     return "future";
     31 }
     32 
     33 #if defined(__clang__)
     34 #pragma clang diagnostic push
     35 #pragma clang diagnostic ignored "-Wswitch"
     36 #elif defined(__GNUC__) || defined(__GNUG__)
     37 #pragma GCC diagnostic push
     38 #pragma GCC diagnostic ignored "-Wswitch"
     39 #endif
     40 
     41 string
     42 __future_error_category::message(int ev) const
     43 {
     44     switch (static_cast<future_errc>(ev))
     45     {
     46     case future_errc(0):  // For backwards compatibility with C++11 (LWG 2056)
     47     case future_errc::broken_promise:
     48         return string("The associated promise has been destructed prior "
     49                       "to the associated state becoming ready.");
     50     case future_errc::future_already_retrieved:
     51         return string("The future has already been retrieved from "
     52                       "the promise or packaged_task.");
     53     case future_errc::promise_already_satisfied:
     54         return string("The state of the promise has already been set.");
     55     case future_errc::no_state:
     56         return string("Operation not permitted on an object without "
     57                       "an associated state.");
     58     }
     59     return string("unspecified future_errc value\n");
     60 }
     61 
     62 #if defined(__clang__)
     63 #pragma clang diagnostic pop
     64 #elif defined(__GNUC__) || defined(__GNUG__)
     65 #pragma GCC diagnostic pop
     66 #endif
     67 
     68 const error_category&
     69 future_category() _NOEXCEPT
     70 {
     71     static __future_error_category __f;
     72     return __f;
     73 }
     74 
     75 future_error::future_error(error_code __ec)
     76     : logic_error(__ec.message()),
     77       __ec_(__ec)
     78 {
     79 }
     80 
     81 future_error::~future_error() _NOEXCEPT
     82 {
     83 }
     84 
     85 void
     86 __assoc_sub_state::__on_zero_shared() _NOEXCEPT
     87 {
     88     delete this;
     89 }
     90 
     91 void
     92 __assoc_sub_state::set_value()
     93 {
     94     unique_lock<mutex> __lk(__mut_);
     95 #ifndef _LIBCPP_NO_EXCEPTIONS
     96     if (__has_value())
     97         throw future_error(make_error_code(future_errc::promise_already_satisfied));
     98 #endif
     99     __state_ |= __constructed | ready;
    100     __cv_.notify_all();
    101 }
    102 
    103 void
    104 __assoc_sub_state::set_value_at_thread_exit()
    105 {
    106     unique_lock<mutex> __lk(__mut_);
    107 #ifndef _LIBCPP_NO_EXCEPTIONS
    108     if (__has_value())
    109         throw future_error(make_error_code(future_errc::promise_already_satisfied));
    110 #endif
    111     __state_ |= __constructed;
    112     __thread_local_data()->__make_ready_at_thread_exit(this);
    113 }
    114 
    115 void
    116 __assoc_sub_state::set_exception(exception_ptr __p)
    117 {
    118     unique_lock<mutex> __lk(__mut_);
    119 #ifndef _LIBCPP_NO_EXCEPTIONS
    120     if (__has_value())
    121         throw future_error(make_error_code(future_errc::promise_already_satisfied));
    122 #endif
    123     __exception_ = __p;
    124     __state_ |= ready;
    125     __cv_.notify_all();
    126 }
    127 
    128 void
    129 __assoc_sub_state::set_exception_at_thread_exit(exception_ptr __p)
    130 {
    131     unique_lock<mutex> __lk(__mut_);
    132 #ifndef _LIBCPP_NO_EXCEPTIONS
    133     if (__has_value())
    134         throw future_error(make_error_code(future_errc::promise_already_satisfied));
    135 #endif
    136     __exception_ = __p;
    137     __thread_local_data()->__make_ready_at_thread_exit(this);
    138 }
    139 
    140 void
    141 __assoc_sub_state::__make_ready()
    142 {
    143     unique_lock<mutex> __lk(__mut_);
    144     __state_ |= ready;
    145     __cv_.notify_all();
    146 }
    147 
    148 void
    149 __assoc_sub_state::copy()
    150 {
    151     unique_lock<mutex> __lk(__mut_);
    152     __sub_wait(__lk);
    153     if (__exception_ != nullptr)
    154         rethrow_exception(__exception_);
    155 }
    156 
    157 void
    158 __assoc_sub_state::wait()
    159 {
    160     unique_lock<mutex> __lk(__mut_);
    161     __sub_wait(__lk);
    162 }
    163 
    164 void
    165 __assoc_sub_state::__sub_wait(unique_lock<mutex>& __lk)
    166 {
    167     if (!__is_ready())
    168     {
    169         if (__state_ & static_cast<unsigned>(deferred))
    170         {
    171             __state_ &= ~static_cast<unsigned>(deferred);
    172             __lk.unlock();
    173             __execute();
    174         }
    175         else
    176             while (!__is_ready())
    177                 __cv_.wait(__lk);
    178     }
    179 }
    180 
    181 void
    182 __assoc_sub_state::__execute()
    183 {
    184 #ifndef _LIBCPP_NO_EXCEPTIONS
    185     throw future_error(make_error_code(future_errc::no_state));
    186 #endif
    187 }
    188 
    189 future<void>::future(__assoc_sub_state* __state)
    190     : __state_(__state)
    191 {
    192 #ifndef _LIBCPP_NO_EXCEPTIONS
    193     if (__state_->__has_future_attached())
    194         throw future_error(make_error_code(future_errc::future_already_retrieved));
    195 #endif
    196     __state_->__add_shared();
    197     __state_->__set_future_attached();
    198 }
    199 
    200 future<void>::~future()
    201 {
    202     if (__state_)
    203         __state_->__release_shared();
    204 }
    205 
    206 void
    207 future<void>::get()
    208 {
    209     unique_ptr<__shared_count, __release_shared_count> __(__state_);
    210     __assoc_sub_state* __s = __state_;
    211     __state_ = nullptr;
    212     __s->copy();
    213 }
    214 
    215 promise<void>::promise()
    216     : __state_(new __assoc_sub_state)
    217 {
    218 }
    219 
    220 promise<void>::~promise()
    221 {
    222     if (__state_)
    223     {
    224         if (!__state_->__has_value() && __state_->use_count() > 1)
    225             __state_->set_exception(make_exception_ptr(
    226                       future_error(make_error_code(future_errc::broken_promise))
    227                                                       ));
    228         __state_->__release_shared();
    229     }
    230 }
    231 
    232 future<void>
    233 promise<void>::get_future()
    234 {
    235 #ifndef _LIBCPP_NO_EXCEPTIONS
    236     if (__state_ == nullptr)
    237         throw future_error(make_error_code(future_errc::no_state));
    238 #endif
    239     return future<void>(__state_);
    240 }
    241 
    242 void
    243 promise<void>::set_value()
    244 {
    245 #ifndef _LIBCPP_NO_EXCEPTIONS
    246     if (__state_ == nullptr)
    247         throw future_error(make_error_code(future_errc::no_state));
    248 #endif
    249     __state_->set_value();
    250 }
    251 
    252 void
    253 promise<void>::set_exception(exception_ptr __p)
    254 {
    255 #ifndef _LIBCPP_NO_EXCEPTIONS
    256     if (__state_ == nullptr)
    257         throw future_error(make_error_code(future_errc::no_state));
    258 #endif
    259     __state_->set_exception(__p);
    260 }
    261 
    262 void
    263 promise<void>::set_value_at_thread_exit()
    264 {
    265 #ifndef _LIBCPP_NO_EXCEPTIONS
    266     if (__state_ == nullptr)
    267         throw future_error(make_error_code(future_errc::no_state));
    268 #endif
    269     __state_->set_value_at_thread_exit();
    270 }
    271 
    272 void
    273 promise<void>::set_exception_at_thread_exit(exception_ptr __p)
    274 {
    275 #ifndef _LIBCPP_NO_EXCEPTIONS
    276     if (__state_ == nullptr)
    277         throw future_error(make_error_code(future_errc::no_state));
    278 #endif
    279     __state_->set_exception_at_thread_exit(__p);
    280 }
    281 
    282 shared_future<void>::~shared_future()
    283 {
    284     if (__state_)
    285         __state_->__release_shared();
    286 }
    287 
    288 shared_future<void>&
    289 shared_future<void>::operator=(const shared_future& __rhs)
    290 {
    291     if (__rhs.__state_)
    292         __rhs.__state_->__add_shared();
    293     if (__state_)
    294         __state_->__release_shared();
    295     __state_ = __rhs.__state_;
    296     return *this;
    297 }
    298 
    299 _LIBCPP_END_NAMESPACE_STD
    300 
    301 #endif // !_LIBCPP_HAS_NO_THREADS
    302