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
19class _LIBCPP_HIDDEN __future_error_category
20    : public __do_message
21{
22public:
23    virtual const char* name() const _NOEXCEPT;
24    virtual string message(int ev) const;
25};
26
27const 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
41string
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
68const error_category&
69future_category() _NOEXCEPT
70{
71    static __future_error_category __f;
72    return __f;
73}
74
75future_error::future_error(error_code __ec)
76    : logic_error(__ec.message()),
77      __ec_(__ec)
78{
79}
80
81future_error::~future_error() _NOEXCEPT
82{
83}
84
85void
86__assoc_sub_state::__on_zero_shared() _NOEXCEPT
87{
88    delete this;
89}
90
91void
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
104void
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
117void
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
131void
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
144void
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
153void
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
162void
163__assoc_sub_state::wait()
164{
165    unique_lock<mutex> __lk(__mut_);
166    __sub_wait(__lk);
167}
168
169void
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
186void
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
194future<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
205future<void>::~future()
206{
207    if (__state_)
208        __state_->__release_shared();
209}
210
211void
212future<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
220promise<void>::promise()
221    : __state_(new __assoc_sub_state)
222{
223}
224
225promise<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
237future<void>
238promise<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
247void
248promise<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
257void
258promise<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
267void
268promise<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
277void
278promise<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
287shared_future<void>::~shared_future()
288{
289    if (__state_)
290        __state_->__release_shared();
291}
292
293shared_future<void>&
294shared_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