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