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