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