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}
102
103void
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
115void
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
128void
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
140void
141__assoc_sub_state::__make_ready()
142{
143    unique_lock<mutex> __lk(__mut_);
144    __state_ |= ready;
145    __cv_.notify_all();
146}
147
148void
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
157void
158__assoc_sub_state::wait()
159{
160    unique_lock<mutex> __lk(__mut_);
161    __sub_wait(__lk);
162}
163
164void
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
181void
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
189future<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
200future<void>::~future()
201{
202    if (__state_)
203        __state_->__release_shared();
204}
205
206void
207future<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
215promise<void>::promise()
216    : __state_(new __assoc_sub_state)
217{
218}
219
220promise<void>::~promise()
221{
222    if (__state_)
223    {
224#ifndef _LIBCPP_NO_EXCEPTIONS
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#endif // _LIBCPP_NO_EXCEPTIONS
230        __state_->__release_shared();
231    }
232}
233
234future<void>
235promise<void>::get_future()
236{
237#ifndef _LIBCPP_NO_EXCEPTIONS
238    if (__state_ == nullptr)
239        throw future_error(make_error_code(future_errc::no_state));
240#endif
241    return future<void>(__state_);
242}
243
244void
245promise<void>::set_value()
246{
247#ifndef _LIBCPP_NO_EXCEPTIONS
248    if (__state_ == nullptr)
249        throw future_error(make_error_code(future_errc::no_state));
250#endif
251    __state_->set_value();
252}
253
254void
255promise<void>::set_exception(exception_ptr __p)
256{
257#ifndef _LIBCPP_NO_EXCEPTIONS
258    if (__state_ == nullptr)
259        throw future_error(make_error_code(future_errc::no_state));
260#endif
261    __state_->set_exception(__p);
262}
263
264void
265promise<void>::set_value_at_thread_exit()
266{
267#ifndef _LIBCPP_NO_EXCEPTIONS
268    if (__state_ == nullptr)
269        throw future_error(make_error_code(future_errc::no_state));
270#endif
271    __state_->set_value_at_thread_exit();
272}
273
274void
275promise<void>::set_exception_at_thread_exit(exception_ptr __p)
276{
277#ifndef _LIBCPP_NO_EXCEPTIONS
278    if (__state_ == nullptr)
279        throw future_error(make_error_code(future_errc::no_state));
280#endif
281    __state_->set_exception_at_thread_exit(__p);
282}
283
284shared_future<void>::~shared_future()
285{
286    if (__state_)
287        __state_->__release_shared();
288}
289
290shared_future<void>&
291shared_future<void>::operator=(const shared_future& __rhs)
292{
293    if (__rhs.__state_)
294        __rhs.__state_->__add_shared();
295    if (__state_)
296        __state_->__release_shared();
297    __state_ = __rhs.__state_;
298    return *this;
299}
300
301_LIBCPP_END_NAMESPACE_STD
302
303#endif // !_LIBCPP_HAS_NO_THREADS
304