1
2// Copyright Oliver Kowalke 2013.
3// Distributed under the Boost Software License, Version 1.0.
4// (See accompanying file LICENSE_1_0.txt or copy at
5// http://www.boost.org/LICENSE_1_0.txt)
6
7#ifndef BOOST_FIBERS_DETAIL_SHARED_STATE_H
8#define BOOST_FIBERS_DETAIL_SHARED_STATE_H
9
10#include <algorithm>
11#include <atomic>
12#include <chrono>
13#include <cstddef>
14#include <exception>
15#include <memory>
16#include <mutex>
17#include <type_traits>
18
19#include <boost/assert.hpp>
20#include <boost/config.hpp>
21#include <boost/intrusive_ptr.hpp>
22
23#include <boost/fiber/detail/config.hpp>
24#include <boost/fiber/future/future_status.hpp>
25#include <boost/fiber/condition_variable.hpp>
26#include <boost/fiber/exceptions.hpp>
27#include <boost/fiber/mutex.hpp>
28
29#ifdef BOOST_HAS_ABI_HEADERS
30# include BOOST_ABI_PREFIX
31#endif
32
33namespace boost {
34namespace fibers {
35namespace detail {
36
37class shared_state_base {
38private:
39 std::atomic< std::size_t > use_count_{ 0 };
40 mutable condition_variable waiters_{};
41
42protected:
43 mutable mutex mtx_{};
44 bool ready_{ false };
45 std::exception_ptr except_{};
46
47 void mark_ready_and_notify_( std::unique_lock< mutex > & lk) noexcept {
48 BOOST_ASSERT( lk.owns_lock() );
49 ready_ = true;
50 lk.unlock();
51 waiters_.notify_all();
52 }
53
54 void owner_destroyed_( std::unique_lock< mutex > & lk) {
55 BOOST_ASSERT( lk.owns_lock() );
56 if ( ! ready_) {
57 set_exception_(
58 except: std::make_exception_ptr( ex: broken_promise() ),
59 lk);
60 }
61 }
62
63 void set_exception_( std::exception_ptr except, std::unique_lock< mutex > & lk) {
64 BOOST_ASSERT( lk.owns_lock() );
65 if ( BOOST_UNLIKELY( ready_) ) {
66 throw promise_already_satisfied();
67 }
68 except_ = except;
69 mark_ready_and_notify_( lk);
70 }
71
72 std::exception_ptr get_exception_ptr_( std::unique_lock< mutex > & lk) {
73 BOOST_ASSERT( lk.owns_lock() );
74 wait_( lk);
75 return except_;
76 }
77
78 void wait_( std::unique_lock< mutex > & lk) const {
79 BOOST_ASSERT( lk.owns_lock() );
80 waiters_.wait( lt&: lk, pred: [this](){ return ready_; });
81 }
82
83 template< typename Rep, typename Period >
84 future_status wait_for_( std::unique_lock< mutex > & lk,
85 std::chrono::duration< Rep, Period > const& timeout_duration) const {
86 BOOST_ASSERT( lk.owns_lock() );
87 return waiters_.wait_for( lk, timeout_duration, [this](){ return ready_; })
88 ? future_status::ready
89 : future_status::timeout;
90 }
91
92 template< typename Clock, typename Duration >
93 future_status wait_until_( std::unique_lock< mutex > & lk,
94 std::chrono::time_point< Clock, Duration > const& timeout_time) const {
95 BOOST_ASSERT( lk.owns_lock() );
96 return waiters_.wait_until( lk, timeout_time, [this](){ return ready_; })
97 ? future_status::ready
98 : future_status::timeout;
99 }
100
101 virtual void deallocate_future() noexcept = 0;
102
103public:
104 shared_state_base() = default;
105
106 virtual ~shared_state_base() = default;
107
108 shared_state_base( shared_state_base const&) = delete;
109 shared_state_base & operator=( shared_state_base const&) = delete;
110
111 void owner_destroyed() {
112 std::unique_lock< mutex > lk{ mtx_ };
113 owner_destroyed_( lk);
114 }
115
116 void set_exception( std::exception_ptr except) {
117 std::unique_lock< mutex > lk{ mtx_ };
118 set_exception_( except, lk);
119 }
120
121 std::exception_ptr get_exception_ptr() {
122 std::unique_lock< mutex > lk{ mtx_ };
123 return get_exception_ptr_( lk);
124 }
125
126 void wait() const {
127 std::unique_lock< mutex > lk{ mtx_ };
128 wait_( lk);
129 }
130
131 template< typename Rep, typename Period >
132 future_status wait_for( std::chrono::duration< Rep, Period > const& timeout_duration) const {
133 std::unique_lock< mutex > lk{ mtx_ };
134 return wait_for_( lk, timeout_duration);
135 }
136
137 template< typename Clock, typename Duration >
138 future_status wait_until( std::chrono::time_point< Clock, Duration > const& timeout_time) const {
139 std::unique_lock< mutex > lk{ mtx_ };
140 return wait_until_( lk, timeout_time);
141 }
142
143 friend inline
144 void intrusive_ptr_add_ref( shared_state_base * p) noexcept {
145 p->use_count_.fetch_add( i: 1, m: std::memory_order_relaxed);
146 }
147
148 friend inline
149 void intrusive_ptr_release( shared_state_base * p) noexcept {
150 if ( 1 == p->use_count_.fetch_sub( i: 1, m: std::memory_order_release) ) {
151 std::atomic_thread_fence( m: std::memory_order_acquire);
152 p->deallocate_future();
153 }
154 }
155};
156
157template< typename R >
158class shared_state : public shared_state_base {
159private:
160 typename std::aligned_storage< sizeof( R), alignof( R) >::type storage_{};
161
162 void set_value_( R const& value, std::unique_lock< mutex > & lk) {
163 BOOST_ASSERT( lk.owns_lock() );
164 if ( BOOST_UNLIKELY( ready_) ) {
165 throw promise_already_satisfied{};
166 }
167 ::new ( static_cast< void * >( std::addressof( storage_) ) ) R( value );
168 mark_ready_and_notify_( lk);
169 }
170
171 void set_value_( R && value, std::unique_lock< mutex > & lk) {
172 BOOST_ASSERT( lk.owns_lock() );
173 if ( BOOST_UNLIKELY( ready_) ) {
174 throw promise_already_satisfied{};
175 }
176 ::new ( static_cast< void * >( std::addressof( storage_) ) ) R( std::move( value) );
177 mark_ready_and_notify_( lk);
178 }
179
180 R & get_( std::unique_lock< mutex > & lk) {
181 BOOST_ASSERT( lk.owns_lock() );
182 wait_( lk);
183 if ( except_) {
184 std::rethrow_exception( except_);
185 }
186 return * reinterpret_cast< R * >( std::addressof( storage_) );
187 }
188
189public:
190 typedef intrusive_ptr< shared_state > ptr_type;
191
192 shared_state() = default;
193
194 virtual ~shared_state() {
195 if ( ready_ && ! except_) {
196 reinterpret_cast< R * >( std::addressof( storage_) )->~R();
197 }
198 }
199
200 shared_state( shared_state const&) = delete;
201 shared_state & operator=( shared_state const&) = delete;
202
203 void set_value( R const& value) {
204 std::unique_lock< mutex > lk{ mtx_ };
205 set_value_( value, lk);
206 }
207
208 void set_value( R && value) {
209 std::unique_lock< mutex > lk{ mtx_ };
210 set_value_( std::move( value), lk);
211 }
212
213 R & get() {
214 std::unique_lock< mutex > lk{ mtx_ };
215 return get_( lk);
216 }
217};
218
219template< typename R >
220class shared_state< R & > : public shared_state_base {
221private:
222 R * value_{ nullptr };
223
224 void set_value_( R & value, std::unique_lock< mutex > & lk) {
225 BOOST_ASSERT( lk.owns_lock() );
226 if ( BOOST_UNLIKELY( ready_) ) {
227 throw promise_already_satisfied();
228 }
229 value_ = std::addressof( value);
230 mark_ready_and_notify_( lk);
231 }
232
233 R & get_( std::unique_lock< mutex > & lk) {
234 BOOST_ASSERT( lk.owns_lock() );
235 wait_( lk);
236 if ( except_) {
237 std::rethrow_exception( except_);
238 }
239 return * value_;
240 }
241
242public:
243 typedef intrusive_ptr< shared_state > ptr_type;
244
245 shared_state() = default;
246
247 virtual ~shared_state() = default;
248
249 shared_state( shared_state const&) = delete;
250 shared_state & operator=( shared_state const&) = delete;
251
252 void set_value( R & value) {
253 std::unique_lock< mutex > lk{ mtx_ };
254 set_value_( value, lk);
255 }
256
257 R & get() {
258 std::unique_lock< mutex > lk{ mtx_ };
259 return get_( lk);
260 }
261};
262
263template<>
264class shared_state< void > : public shared_state_base {
265private:
266 inline
267 void set_value_( std::unique_lock< mutex > & lk) {
268 BOOST_ASSERT( lk.owns_lock() );
269 if ( BOOST_UNLIKELY( ready_) ) {
270 throw promise_already_satisfied();
271 }
272 mark_ready_and_notify_( lk);
273 }
274
275 inline
276 void get_( std::unique_lock< mutex > & lk) {
277 BOOST_ASSERT( lk.owns_lock() );
278 wait_( lk);
279 if ( except_) {
280 std::rethrow_exception( except_);
281 }
282 }
283
284public:
285 typedef intrusive_ptr< shared_state > ptr_type;
286
287 shared_state() = default;
288
289 virtual ~shared_state() = default;
290
291 shared_state( shared_state const&) = delete;
292 shared_state & operator=( shared_state const&) = delete;
293
294 inline
295 void set_value() {
296 std::unique_lock< mutex > lk{ mtx_ };
297 set_value_( lk);
298 }
299
300 inline
301 void get() {
302 std::unique_lock< mutex > lk{ mtx_ };
303 get_( lk);
304 }
305};
306
307}}}
308
309#ifdef BOOST_HAS_ABI_HEADERS
310# include BOOST_ABI_SUFFIX
311#endif
312
313#endif // BOOST_FIBERS_DETAIL_SHARED_STATE_H
314

source code of boost/libs/fiber/include/boost/fiber/future/detail/shared_state.hpp