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     __lk.unlock();
    102 }
    103 
    104 void
    105 __assoc_sub_state::set_value_at_thread_exit()
    106 {
    107     unique_lock<mutex> __lk(__mut_);
    108 #ifndef _LIBCPP_NO_EXCEPTIONS
    109     if (__has_value())
    110         throw future_error(make_error_code(future_errc::promise_already_satisfied));
    111 #endif
    112     __state_ |= __constructed;
    113     __thread_local_data()->__make_ready_at_thread_exit(this);
    114     __lk.unlock();
    115 }
    116 
    117 void
    118 __assoc_sub_state::set_exception(exception_ptr __p)
    119 {
    120     unique_lock<mutex> __lk(__mut_);
    121 #ifndef _LIBCPP_NO_EXCEPTIONS
    122     if (__has_value())
    123         throw future_error(make_error_code(future_errc::promise_already_satisfied));
    124 #endif
    125     __exception_ = __p;
    126     __state_ |= ready;
    127     __lk.unlock();
    128     __cv_.notify_all();
    129 }
    130 
    131 void
    132 __assoc_sub_state::set_exception_at_thread_exit(exception_ptr __p)
    133 {
    134     unique_lock<mutex> __lk(__mut_);
    135 #ifndef _LIBCPP_NO_EXCEPTIONS
    136     if (__has_value())
    137         throw future_error(make_error_code(future_errc::promise_already_satisfied));
    138 #endif
    139     __exception_ = __p;
    140     __thread_local_data()->__make_ready_at_thread_exit(this);
    141     __lk.unlock();
    142 }
    143 
    144 void
    145 __assoc_sub_state::__make_ready()
    146 {
    147     unique_lock<mutex> __lk(__mut_);
    148     __state_ |= ready;
    149     __lk.unlock();
    150     __cv_.notify_all();
    151 }
    152 
    153 void
    154 __assoc_sub_state::copy()
    155 {
    156     unique_lock<mutex> __lk(__mut_);
    157     __sub_wait(__lk);
    158     if (__exception_ != nullptr)
    159         rethrow_exception(__exception_);
    160 }
    161 
    162 void
    163 __assoc_sub_state::wait()
    164 {
    165     unique_lock<mutex> __lk(__mut_);
    166     __sub_wait(__lk);
    167 }
    168 
    169 void
    170 __assoc_sub_state::__sub_wait(unique_lock<mutex>& __lk)
    171 {
    172     if (!__is_ready())
    173     {
    174         if (__state_ & static_cast<unsigned>(deferred))
    175         {
    176             __state_ &= ~static_cast<unsigned>(deferred);
    177             __lk.unlock();
    178             __execute();
    179         }
    180         else
    181             while (!__is_ready())
    182                 __cv_.wait(__lk);
    183     }
    184 }
    185 
    186 void
    187 __assoc_sub_state::__execute()
    188 {
    189 #ifndef _LIBCPP_NO_EXCEPTIONS
    190     throw future_error(make_error_code(future_errc::no_state));
    191 #endif
    192 }
    193 
    194 future<void>::future(__assoc_sub_state* __state)
    195     : __state_(__state)
    196 {
    197 #ifndef _LIBCPP_NO_EXCEPTIONS
    198     if (__state_->__has_future_attached())
    199         throw future_error(make_error_code(future_errc::future_already_retrieved));
    200 #endif
    201     __state_->__add_shared();
    202     __state_->__set_future_attached();
    203 }
    204 
    205 future<void>::~future()
    206 {
    207     if (__state_)
    208         __state_->__release_shared();
    209 }
    210 
    211 void
    212 future<void>::get()
    213 {
    214     unique_ptr<__shared_count, __release_shared_count> __(__state_);
    215     __assoc_sub_state* __s = __state_;
    216     __state_ = nullptr;
    217     __s->copy();
    218 }
    219 
    220 promise<void>::promise()
    221     : __state_(new __assoc_sub_state)
    222 {
    223 }
    224 
    225 promise<void>::~promise()
    226 {
    227     if (__state_)
    228     {
    229         if (!__state_->__has_value() && __state_->use_count() > 1)
    230             __state_->set_exception(make_exception_ptr(
    231                       future_error(make_error_code(future_errc::broken_promise))
    232                                                       ));
    233         __state_->__release_shared();
    234     }
    235 }
    236 
    237 future<void>
    238 promise<void>::get_future()
    239 {
    240 #ifndef _LIBCPP_NO_EXCEPTIONS
    241     if (__state_ == nullptr)
    242         throw future_error(make_error_code(future_errc::no_state));
    243 #endif
    244     return future<void>(__state_);
    245 }
    246 
    247 void
    248 promise<void>::set_value()
    249 {
    250 #ifndef _LIBCPP_NO_EXCEPTIONS
    251     if (__state_ == nullptr)
    252         throw future_error(make_error_code(future_errc::no_state));
    253 #endif
    254     __state_->set_value();
    255 }
    256 
    257 void
    258 promise<void>::set_exception(exception_ptr __p)
    259 {
    260 #ifndef _LIBCPP_NO_EXCEPTIONS
    261     if (__state_ == nullptr)
    262         throw future_error(make_error_code(future_errc::no_state));
    263 #endif
    264     __state_->set_exception(__p);
    265 }
    266 
    267 void
    268 promise<void>::set_value_at_thread_exit()
    269 {
    270 #ifndef _LIBCPP_NO_EXCEPTIONS
    271     if (__state_ == nullptr)
    272         throw future_error(make_error_code(future_errc::no_state));
    273 #endif
    274     __state_->set_value_at_thread_exit();
    275 }
    276 
    277 void
    278 promise<void>::set_exception_at_thread_exit(exception_ptr __p)
    279 {
    280 #ifndef _LIBCPP_NO_EXCEPTIONS
    281     if (__state_ == nullptr)
    282         throw future_error(make_error_code(future_errc::no_state));
    283 #endif
    284     __state_->set_exception_at_thread_exit(__p);
    285 }
    286 
    287 shared_future<void>::~shared_future()
    288 {
    289     if (__state_)
    290         __state_->__release_shared();
    291 }
    292 
    293 shared_future<void>&
    294 shared_future<void>::operator=(const shared_future& __rhs)
    295 {
    296     if (__rhs.__state_)
    297         __rhs.__state_->__add_shared();
    298     if (__state_)
    299         __state_->__release_shared();
    300     __state_ = __rhs.__state_;
    301     return *this;
    302 }
    303 
    304 _LIBCPP_END_NAMESPACE_STD
    305 
    306 #endif // !_LIBCPP_HAS_NO_THREADS
    307