]>
Commit | Line | Data |
---|---|---|
b32b8144 FG |
1 | |
2 | // Copyright Oliver Kowalke 2014. | |
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_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_IPP | |
8 | #define BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_IPP | |
9 | ||
10 | #include <algorithm> | |
11 | #include <exception> | |
12 | #include <memory> | |
13 | ||
14 | #include <boost/assert.hpp> | |
15 | #include <boost/config.hpp> | |
92f5a8d4 | 16 | #include <boost/context/detail/config.hpp> |
b32b8144 | 17 | |
11fdf7f2 | 18 | #include <boost/context/fiber.hpp> |
b32b8144 FG |
19 | |
20 | #include <boost/coroutine2/detail/config.hpp> | |
21 | #include <boost/coroutine2/detail/forced_unwind.hpp> | |
22 | #include <boost/coroutine2/detail/wrap.hpp> | |
23 | ||
24 | #ifdef BOOST_HAS_ABI_HEADERS | |
25 | # include BOOST_ABI_PREFIX | |
26 | #endif | |
27 | ||
28 | namespace boost { | |
29 | namespace coroutines2 { | |
30 | namespace detail { | |
31 | ||
32 | // push_coroutine< T > | |
33 | ||
34 | template< typename T > | |
35 | void | |
36 | push_coroutine< T >::control_block::destroy( control_block * cb) noexcept { | |
11fdf7f2 | 37 | boost::context::fiber c = std::move( cb->c); |
b32b8144 FG |
38 | // destroy control structure |
39 | cb->~control_block(); | |
40 | // destroy coroutine's stack | |
41 | cb->state |= state_t::destroy; | |
42 | } | |
43 | ||
44 | template< typename T > | |
45 | template< typename StackAllocator, typename Fn > | |
46 | push_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator && salloc, | |
47 | Fn && fn) : | |
b32b8144 | 48 | #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) |
11fdf7f2 TL |
49 | c{ std::allocator_arg, palloc, std::forward< StackAllocator >( salloc), |
50 | wrap( [this](typename std::decay< Fn >::type & fn_,boost::context::fiber && c) mutable { | |
b32b8144 FG |
51 | // create synthesized pull_coroutine< T > |
52 | typename pull_coroutine< T >::control_block synthesized_cb{ this, c }; | |
53 | pull_coroutine< T > synthesized{ & synthesized_cb }; | |
54 | other = & synthesized_cb; | |
11fdf7f2 | 55 | other->c = std::move( other->c).resume(); |
b32b8144 FG |
56 | if ( state_t::none == ( state & state_t::destroy) ) { |
57 | try { | |
58 | auto fn = std::move( fn_); | |
59 | // call coroutine-fn with synthesized pull_coroutine as argument | |
60 | fn( synthesized); | |
61 | } catch ( boost::context::detail::forced_unwind const&) { | |
62 | throw; | |
92f5a8d4 TL |
63 | #if defined( BOOST_CONTEXT_HAS_CXXABI_H ) |
64 | } catch ( abi::__forced_unwind const&) { | |
65 | throw; | |
66 | #endif | |
b32b8144 FG |
67 | } catch (...) { |
68 | // store other exceptions in exception-pointer | |
69 | except = std::current_exception(); | |
70 | } | |
71 | } | |
72 | // set termination flags | |
73 | state |= state_t::complete; | |
74 | // jump back | |
11fdf7f2 TL |
75 | other->c = std::move( other->c).resume(); |
76 | return std::move( other->c); | |
77 | }, | |
78 | std::forward< Fn >( fn) ) }, | |
79 | #else | |
80 | c{ std::allocator_arg, palloc, std::forward< StackAllocator >( salloc), | |
81 | [this,fn_=std::forward< Fn >( fn)](boost::context::fiber && c) mutable { | |
82 | // create synthesized pull_coroutine< T > | |
83 | typename pull_coroutine< T >::control_block synthesized_cb{ this, c }; | |
84 | pull_coroutine< T > synthesized{ & synthesized_cb }; | |
85 | other = & synthesized_cb; | |
86 | other->c = std::move( other->c).resume(); | |
87 | if ( state_t::none == ( state & state_t::destroy) ) { | |
88 | try { | |
89 | auto fn = std::move( fn_); | |
90 | // call coroutine-fn with synthesized pull_coroutine as argument | |
91 | fn( synthesized); | |
92 | } catch ( boost::context::detail::forced_unwind const&) { | |
93 | throw; | |
92f5a8d4 TL |
94 | #if defined( BOOST_CONTEXT_HAS_CXXABI_H ) |
95 | } catch ( abi::__forced_unwind const&) { | |
96 | throw; | |
97 | #endif | |
11fdf7f2 TL |
98 | } catch (...) { |
99 | // store other exceptions in exception-pointer | |
100 | except = std::current_exception(); | |
101 | } | |
102 | } | |
103 | // set termination flags | |
104 | state |= state_t::complete; | |
105 | // jump back | |
106 | return std::move( other->c).resume(); | |
107 | } }, | |
b32b8144 | 108 | #endif |
11fdf7f2 TL |
109 | other{ nullptr }, |
110 | state{ state_t::unwind }, | |
111 | except{} { | |
112 | c = std::move( c).resume(); | |
b32b8144 FG |
113 | } |
114 | ||
115 | template< typename T > | |
116 | push_coroutine< T >::control_block::control_block( typename pull_coroutine< T >::control_block * cb, | |
11fdf7f2 | 117 | boost::context::fiber & c_) noexcept : |
b32b8144 FG |
118 | c{ std::move( c_) }, |
119 | other{ cb }, | |
120 | state{ state_t::none }, | |
121 | except{} { | |
122 | } | |
123 | ||
124 | template< typename T > | |
125 | void | |
126 | push_coroutine< T >::control_block::deallocate() noexcept { | |
127 | if ( state_t::none != ( state & state_t::unwind) ) { | |
128 | destroy( this); | |
129 | } | |
130 | } | |
131 | ||
132 | template< typename T > | |
133 | void | |
134 | push_coroutine< T >::control_block::resume( T const& data) { | |
135 | // pass data to other context | |
136 | other->set( data); | |
137 | // resume other context | |
11fdf7f2 | 138 | c = std::move( c).resume(); |
b32b8144 FG |
139 | if ( except) { |
140 | std::rethrow_exception( except); | |
141 | } | |
142 | } | |
143 | ||
144 | template< typename T > | |
145 | void | |
146 | push_coroutine< T >::control_block::resume( T && data) { | |
147 | // pass data to other context | |
148 | other->set( std::move( data) ); | |
149 | // resume other context | |
11fdf7f2 | 150 | c = std::move( c).resume(); |
b32b8144 FG |
151 | if ( except) { |
152 | std::rethrow_exception( except); | |
153 | } | |
154 | } | |
155 | ||
156 | template< typename T > | |
157 | bool | |
158 | push_coroutine< T >::control_block::valid() const noexcept { | |
159 | return state_t::none == ( state & state_t::complete ); | |
160 | } | |
161 | ||
162 | ||
163 | // push_coroutine< T & > | |
164 | ||
165 | template< typename T > | |
166 | void | |
167 | push_coroutine< T & >::control_block::destroy( control_block * cb) noexcept { | |
11fdf7f2 | 168 | boost::context::fiber c = std::move( cb->c); |
b32b8144 FG |
169 | // destroy control structure |
170 | cb->~control_block(); | |
171 | // destroy coroutine's stack | |
172 | cb->state |= state_t::destroy; | |
173 | } | |
174 | ||
175 | template< typename T > | |
176 | template< typename StackAllocator, typename Fn > | |
177 | push_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator && salloc, | |
178 | Fn && fn) : | |
b32b8144 | 179 | #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) |
11fdf7f2 TL |
180 | c{ std::allocator_arg, palloc, std::forward< StackAllocator >( salloc), |
181 | wrap( [this](typename std::decay< Fn >::type & fn_,boost::context::fiber && c) mutable { | |
b32b8144 FG |
182 | // create synthesized pull_coroutine< T & > |
183 | typename pull_coroutine< T & >::control_block synthesized_cb{ this, c }; | |
184 | pull_coroutine< T & > synthesized{ & synthesized_cb }; | |
185 | other = & synthesized_cb; | |
11fdf7f2 | 186 | other->c = std::move( other->c).resume(); |
b32b8144 FG |
187 | if ( state_t::none == ( state & state_t::destroy) ) { |
188 | try { | |
189 | auto fn = std::move( fn_); | |
190 | // call coroutine-fn with synthesized pull_coroutine as argument | |
191 | fn( synthesized); | |
192 | } catch ( boost::context::detail::forced_unwind const&) { | |
193 | throw; | |
92f5a8d4 TL |
194 | #if defined( BOOST_CONTEXT_HAS_CXXABI_H ) |
195 | } catch ( abi::__forced_unwind const&) { | |
196 | throw; | |
197 | #endif | |
b32b8144 FG |
198 | } catch (...) { |
199 | // store other exceptions in exception-pointer | |
200 | except = std::current_exception(); | |
201 | } | |
202 | } | |
203 | // set termination flags | |
204 | state |= state_t::complete; | |
205 | // jump back | |
11fdf7f2 TL |
206 | other->c = std::move( other->c).resume(); |
207 | return std::move( other->c); | |
208 | }, | |
209 | std::forward< Fn >( fn) ) }, | |
210 | #else | |
211 | c{ std::allocator_arg, palloc, std::forward< StackAllocator >( salloc), | |
212 | [this,fn_=std::forward< Fn >( fn)](boost::context::fiber && c) mutable { | |
213 | // create synthesized pull_coroutine< T & > | |
214 | typename pull_coroutine< T & >::control_block synthesized_cb{ this, c }; | |
215 | pull_coroutine< T & > synthesized{ & synthesized_cb }; | |
216 | other = & synthesized_cb; | |
217 | other->c = std::move( other->c).resume(); | |
218 | if ( state_t::none == ( state & state_t::destroy) ) { | |
219 | try { | |
220 | auto fn = std::move( fn_); | |
221 | // call coroutine-fn with synthesized pull_coroutine as argument | |
222 | fn( synthesized); | |
223 | } catch ( boost::context::detail::forced_unwind const&) { | |
224 | throw; | |
92f5a8d4 TL |
225 | #if defined( BOOST_CONTEXT_HAS_CXXABI_H ) |
226 | } catch ( abi::__forced_unwind const&) { | |
227 | throw; | |
228 | #endif | |
11fdf7f2 TL |
229 | } catch (...) { |
230 | // store other exceptions in exception-pointer | |
231 | except = std::current_exception(); | |
232 | } | |
233 | } | |
234 | // set termination flags | |
235 | state |= state_t::complete; | |
236 | // jump back | |
237 | other->c = std::move( other->c).resume(); | |
238 | return std::move( other->c); | |
239 | } }, | |
b32b8144 | 240 | #endif |
11fdf7f2 TL |
241 | other{ nullptr }, |
242 | state{ state_t::unwind }, | |
243 | except{} { | |
244 | c = std::move( c).resume(); | |
b32b8144 FG |
245 | } |
246 | ||
247 | template< typename T > | |
248 | push_coroutine< T & >::control_block::control_block( typename pull_coroutine< T & >::control_block * cb, | |
11fdf7f2 | 249 | boost::context::fiber & c_) noexcept : |
b32b8144 FG |
250 | c{ std::move( c_) }, |
251 | other{ cb }, | |
252 | state{ state_t::none }, | |
253 | except{} { | |
254 | } | |
255 | ||
256 | template< typename T > | |
257 | void | |
258 | push_coroutine< T & >::control_block::deallocate() noexcept { | |
259 | if ( state_t::none != ( state & state_t::unwind) ) { | |
260 | destroy( this); | |
261 | } | |
262 | } | |
263 | ||
264 | template< typename T > | |
265 | void | |
266 | push_coroutine< T & >::control_block::resume( T & data) { | |
267 | // pass data to other context | |
268 | other->set( data); | |
269 | // resume other context | |
11fdf7f2 | 270 | c = std::move( c).resume(); |
b32b8144 FG |
271 | if ( except) { |
272 | std::rethrow_exception( except); | |
273 | } | |
274 | } | |
275 | ||
276 | template< typename T > | |
277 | bool | |
278 | push_coroutine< T & >::control_block::valid() const noexcept { | |
279 | return state_t::none == ( state & state_t::complete ); | |
280 | } | |
281 | ||
282 | ||
283 | // push_coroutine< void > | |
284 | ||
285 | inline | |
286 | void | |
287 | push_coroutine< void >::control_block::destroy( control_block * cb) noexcept { | |
11fdf7f2 | 288 | boost::context::fiber c = std::move( cb->c); |
b32b8144 FG |
289 | // destroy control structure |
290 | cb->~control_block(); | |
291 | // destroy coroutine's stack | |
292 | cb->state |= state_t::destroy; | |
293 | } | |
294 | ||
295 | template< typename StackAllocator, typename Fn > | |
296 | push_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator && salloc, Fn && fn) : | |
b32b8144 | 297 | #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) |
11fdf7f2 TL |
298 | c{ std::allocator_arg, palloc, std::forward< StackAllocator >( salloc), |
299 | wrap( [this](typename std::decay< Fn >::type & fn_,boost::context::fiber && c) mutable { | |
b32b8144 | 300 | // create synthesized pull_coroutine< void > |
11fdf7f2 | 301 | typename pull_coroutine< void >::control_block synthesized_cb{ this, c }; |
b32b8144 FG |
302 | pull_coroutine< void > synthesized{ & synthesized_cb }; |
303 | other = & synthesized_cb; | |
11fdf7f2 | 304 | other->c = std::move( other->c).resume(); |
b32b8144 FG |
305 | if ( state_t::none == ( state & state_t::destroy) ) { |
306 | try { | |
307 | auto fn = std::move( fn_); | |
308 | // call coroutine-fn with synthesized pull_coroutine as argument | |
309 | fn( synthesized); | |
310 | } catch ( boost::context::detail::forced_unwind const&) { | |
311 | throw; | |
92f5a8d4 TL |
312 | #if defined( BOOST_CONTEXT_HAS_CXXABI_H ) |
313 | } catch ( abi::__forced_unwind const&) { | |
314 | throw; | |
315 | #endif | |
b32b8144 FG |
316 | } catch (...) { |
317 | // store other exceptions in exception-pointer | |
318 | except = std::current_exception(); | |
319 | } | |
320 | } | |
321 | // set termination flags | |
322 | state |= state_t::complete; | |
323 | // jump back | |
11fdf7f2 TL |
324 | other->c = std::move( other->c).resume(); |
325 | return std::move( other->c); | |
326 | }, | |
327 | std::forward< Fn >( fn) ) }, | |
328 | #else | |
329 | c{ std::allocator_arg, palloc, std::forward< StackAllocator >( salloc), | |
330 | [this,fn_=std::forward< Fn >( fn)](boost::context::fiber && c) mutable { | |
331 | // create synthesized pull_coroutine< void > | |
332 | typename pull_coroutine< void >::control_block synthesized_cb{ this, c}; | |
333 | pull_coroutine< void > synthesized{ & synthesized_cb }; | |
334 | other = & synthesized_cb; | |
335 | other->c = std::move( other->c).resume(); | |
336 | if ( state_t::none == ( state & state_t::destroy) ) { | |
337 | try { | |
338 | auto fn = std::move( fn_); | |
339 | // call coroutine-fn with synthesized pull_coroutine as argument | |
340 | fn( synthesized); | |
341 | } catch ( boost::context::detail::forced_unwind const&) { | |
342 | throw; | |
92f5a8d4 TL |
343 | #if defined( BOOST_CONTEXT_HAS_CXXABI_H ) |
344 | } catch ( abi::__forced_unwind const&) { | |
345 | throw; | |
346 | #endif | |
11fdf7f2 TL |
347 | } catch (...) { |
348 | // store other exceptions in exception-pointer | |
349 | except = std::current_exception(); | |
350 | } | |
351 | } | |
352 | // set termination flags | |
353 | state |= state_t::complete; | |
354 | // jump back | |
355 | other->c = std::move( other->c).resume(); | |
356 | return std::move( other->c); | |
357 | } }, | |
b32b8144 | 358 | #endif |
11fdf7f2 TL |
359 | other{ nullptr }, |
360 | state{ state_t::unwind }, | |
361 | except{} { | |
362 | c = std::move( c).resume(); | |
b32b8144 FG |
363 | } |
364 | ||
365 | inline | |
366 | push_coroutine< void >::control_block::control_block( pull_coroutine< void >::control_block * cb, | |
11fdf7f2 | 367 | boost::context::fiber & c_) noexcept : |
b32b8144 FG |
368 | c{ std::move( c_) }, |
369 | other{ cb }, | |
370 | state{ state_t::none }, | |
371 | except{} { | |
372 | } | |
373 | ||
374 | inline | |
375 | void | |
376 | push_coroutine< void >::control_block::deallocate() noexcept { | |
377 | if ( state_t::none != ( state & state_t::unwind) ) { | |
378 | destroy( this); | |
379 | } | |
380 | } | |
381 | ||
382 | inline | |
383 | void | |
384 | push_coroutine< void >::control_block::resume() { | |
11fdf7f2 | 385 | c = std::move( c).resume(); |
b32b8144 FG |
386 | if ( except) { |
387 | std::rethrow_exception( except); | |
388 | } | |
389 | } | |
390 | ||
391 | inline | |
392 | bool | |
393 | push_coroutine< void >::control_block::valid() const noexcept { | |
394 | return state_t::none == ( state & state_t::complete ); | |
395 | } | |
396 | ||
397 | }}} | |
398 | ||
399 | #ifdef BOOST_HAS_ABI_HEADERS | |
400 | # include BOOST_ABI_SUFFIX | |
401 | #endif | |
402 | ||
403 | #endif // BOOST_COROUTINES2_DETAIL_PUSH_CONTROL_BLOCK_IPP |