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)
7 #ifndef BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP
8 #define BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP
14 #include <boost/assert.hpp>
15 #include <boost/config.hpp>
17 #include <boost/context/execution_context.hpp>
19 #include <boost/coroutine2/detail/config.hpp>
20 #include <boost/coroutine2/detail/decay_copy.hpp>
21 #include <boost/coroutine2/detail/forced_unwind.hpp>
22 #include <boost/coroutine2/detail/state.hpp>
24 #ifdef BOOST_HAS_ABI_HEADERS
25 # include BOOST_ABI_PREFIX
29 namespace coroutines2 {
32 // pull_coroutine< T >
34 template< typename T >
36 pull_coroutine< T >::control_block::destroy( control_block * cb) noexcept {
37 boost::context::execution_context ctx = cb->ctx;
38 // destroy control structure
39 cb->state |= state_t::destroy;
43 template< typename T >
44 template< typename StackAllocator, typename Fn >
45 pull_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
47 #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
48 ctx{ std::allocator_arg, palloc, salloc,
51 [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context & ctx, void *) mutable noexcept {
52 // create synthesized push_coroutine< T >
53 typename push_coroutine< T >::control_block synthesized_cb{ this, ctx };
54 push_coroutine< T > synthesized{ & synthesized_cb };
55 other = & synthesized_cb;
56 if ( state_t::none == ( state & state_t::destroy) ) {
58 auto fn = std::move( fn_);
59 // call coroutine-fn with synthesized push_coroutine as argument
61 } catch ( forced_unwind const&) {
62 // do nothing for unwinding exception
64 // store other exceptions in exception-pointer
65 except = std::current_exception();
68 // set termination flags
69 state |= state_t::complete;
72 BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
74 std::forward< Fn >( fn),
75 boost::context::execution_context::current(),
76 std::placeholders::_1))},
78 ctx{ std::allocator_arg, palloc, salloc,
79 [this,fn_=decay_copy( std::forward< Fn >( fn) ),ctx=boost::context::execution_context::current()] (void *) mutable noexcept {
80 // create synthesized push_coroutine< T >
81 typename push_coroutine< T >::control_block synthesized_cb{ this, ctx };
82 push_coroutine< T > synthesized{ & synthesized_cb };
83 other = & synthesized_cb;
84 if ( state_t::none == ( state & state_t::destroy) ) {
86 auto fn = std::move( fn_);
87 // call coroutine-fn with synthesized push_coroutine as argument
89 } catch ( forced_unwind const&) {
90 // do nothing for unwinding exception
92 // store other exceptions in exception-pointer
93 except = std::current_exception();
96 // set termination flags
97 state |= state_t::complete;
100 BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
104 state{ state_t::unwind },
108 // enter coroutine-fn in order to have first value available after ctor (of `*this`) returns
109 set( static_cast< T * >( ctx() ) );
112 template< typename T >
113 pull_coroutine< T >::control_block::control_block( typename push_coroutine< T >::control_block * cb,
114 boost::context::execution_context const& ctx_) noexcept :
117 state{ state_t::none },
123 template< typename T >
124 pull_coroutine< T >::control_block::~control_block() {
125 if ( state_t::none == ( state & state_t::complete) &&
126 state_t::none != ( state & state_t::unwind) ) {
127 // unwind coroutine stack
128 other->ctx = boost::context::execution_context::current();
129 ctx( context::exec_ontop_arg, unwind_coroutine);
131 // destroy data if it set
133 reinterpret_cast< T * >( std::addressof( storage) )->~T();
137 template< typename T >
139 pull_coroutine< T >::control_block::deallocate() noexcept {
140 if ( state_t::none != ( state & state_t::unwind) ) {
145 template< typename T >
147 pull_coroutine< T >::control_block::resume() {
148 other->ctx = boost::context::execution_context::current();
149 set( static_cast< T * >( ctx() ) );
151 std::rethrow_exception( except);
155 template< typename T >
157 pull_coroutine< T >::control_block::set( T * t) {
158 // destroy data if it set
160 reinterpret_cast< T * >( std::addressof( storage) )->~T();
163 ::new ( static_cast< void * >( std::addressof( storage) ) ) T( std::move( * t) );
170 template< typename T >
172 pull_coroutine< T >::control_block::get() noexcept {
173 return * reinterpret_cast< T * >( std::addressof( storage) );
176 template< typename T >
178 pull_coroutine< T >::control_block::valid() const noexcept {
179 return nullptr != other && state_t::none == ( state & state_t::complete) && bvalid;
183 // pull_coroutine< T & >
185 template< typename T >
187 pull_coroutine< T & >::control_block::destroy( control_block * cb) noexcept {
188 boost::context::execution_context ctx = cb->ctx;
189 // destroy control structure
190 cb->state |= state_t::destroy;
191 cb->~control_block();
194 template< typename T >
195 template< typename StackAllocator, typename Fn >
196 pull_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
198 #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
199 ctx{ std::allocator_arg, palloc, salloc,
202 [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context & ctx, void *) mutable noexcept {
203 // create synthesized push_coroutine< T >
204 typename push_coroutine< T & >::control_block synthesized_cb{ this, ctx };
205 push_coroutine< T & > synthesized{ & synthesized_cb };
206 other = & synthesized_cb;
207 if ( state_t::none == ( state & state_t::destroy) ) {
209 auto fn = std::move( fn_);
210 // call coroutine-fn with synthesized push_coroutine as argument
212 } catch ( forced_unwind const&) {
213 // do nothing for unwinding exception
215 // store other exceptions in exception-pointer
216 except = std::current_exception();
219 // set termination flags
220 state |= state_t::complete;
223 BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
225 std::forward< Fn >( fn),
226 boost::context::execution_context::current(),
227 std::placeholders::_1))},
229 ctx{ std::allocator_arg, palloc, salloc,
230 [this,fn_=decay_copy( std::forward< Fn >( fn) ),ctx=boost::context::execution_context::current()] (void *) mutable noexcept {
231 // create synthesized push_coroutine< T >
232 typename push_coroutine< T & >::control_block synthesized_cb{ this, ctx };
233 push_coroutine< T & > synthesized{ & synthesized_cb };
234 other = & synthesized_cb;
235 if ( state_t::none == ( state & state_t::destroy) ) {
237 auto fn = std::move( fn_);
238 // call coroutine-fn with synthesized push_coroutine as argument
240 } catch ( forced_unwind const&) {
241 // do nothing for unwinding exception
243 // store other exceptions in exception-pointer
244 except = std::current_exception();
247 // set termination flags
248 state |= state_t::complete;
251 BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
255 state{ state_t::unwind },
258 // enter coroutine-fn in order to have first value available after ctor (of `*this`) returns
259 t = static_cast< T * >( ctx() );
262 template< typename T >
263 pull_coroutine< T & >::control_block::control_block( typename push_coroutine< T & >::control_block * cb,
264 boost::context::execution_context const& ctx_) noexcept :
267 state{ state_t::none },
272 template< typename T >
273 pull_coroutine< T & >::control_block::~control_block() {
274 if ( state_t::none == ( state & state_t::complete) &&
275 state_t::none != ( state & state_t::unwind) ) {
276 // unwind coroutine stack
277 other->ctx = boost::context::execution_context::current();
278 ctx( context::exec_ontop_arg, unwind_coroutine);
282 template< typename T >
284 pull_coroutine< T & >::control_block::deallocate() noexcept {
285 if ( state_t::none != ( state & state_t::unwind) ) {
290 template< typename T >
292 pull_coroutine< T & >::control_block::resume() {
293 other->ctx = boost::context::execution_context::current();
294 t = static_cast< T * >( ctx() );
296 std::rethrow_exception( except);
300 template< typename T >
302 pull_coroutine< T & >::control_block::get() noexcept {
303 return * static_cast< T * >( t);
306 template< typename T >
308 pull_coroutine< T & >::control_block::valid() const noexcept {
309 return nullptr != other && state_t::none == ( state & state_t::complete) && nullptr != t;
313 // pull_coroutine< void >
317 pull_coroutine< void >::control_block::destroy( control_block * cb) noexcept {
318 boost::context::execution_context ctx = cb->ctx;
319 // destroy control structure
320 cb->state |= state_t::destroy;
321 cb->~control_block();
324 template< typename StackAllocator, typename Fn >
325 pull_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc,
327 #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS)
328 ctx{ std::allocator_arg, palloc, salloc,
331 [this]( typename std::decay< Fn >::type & fn_, boost::context::execution_context & ctx, void *) mutable noexcept {
332 // create synthesized push_coroutine< T >
333 typename push_coroutine< void >::control_block synthesized_cb{ this, ctx };
334 push_coroutine< void > synthesized{ & synthesized_cb };
335 other = & synthesized_cb;
336 if ( state_t::none == ( state & state_t::destroy) ) {
338 auto fn = std::move( fn_);
339 // call coroutine-fn with synthesized push_coroutine as argument
341 } catch ( forced_unwind const&) {
342 // do nothing for unwinding exception
344 // store other exceptions in exception-pointer
345 except = std::current_exception();
348 // set termination flags
349 state |= state_t::complete;
352 BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
354 std::forward< Fn >( fn),
355 boost::context::execution_context::current(),
356 std::placeholders::_1))},
358 ctx{ std::allocator_arg, palloc, salloc,
359 [this,fn_=decay_copy( std::forward< Fn >( fn) ),ctx=boost::context::execution_context::current()] (void *) mutable noexcept {
360 // create synthesized push_coroutine< T >
361 typename push_coroutine< void >::control_block synthesized_cb{ this, ctx };
362 push_coroutine< void > synthesized{ & synthesized_cb };
363 other = & synthesized_cb;
364 if ( state_t::none == ( state & state_t::destroy) ) {
366 auto fn = std::move( fn_);
367 // call coroutine-fn with synthesized push_coroutine as argument
369 } catch ( forced_unwind const&) {
370 // do nothing for unwinding exception
372 // store other exceptions in exception-pointer
373 except = std::current_exception();
376 // set termination flags
377 state |= state_t::complete;
380 BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
384 state{ state_t::unwind },
386 // enter coroutine-fn in order to have first value available after ctor returns
391 pull_coroutine< void >::control_block::control_block( push_coroutine< void >::control_block * cb,
392 boost::context::execution_context const& ctx_) noexcept :
395 state{ state_t::none },
400 pull_coroutine< void >::control_block::~control_block() {
401 if ( state_t::none == ( state & state_t::complete) &&
402 state_t::none != ( state & state_t::unwind) ) {
403 // unwind coroutine stack
404 other->ctx = boost::context::execution_context::current();
405 ctx( context::exec_ontop_arg, unwind_coroutine);
411 pull_coroutine< void >::control_block::deallocate() noexcept {
412 if ( state_t::none != ( state & state_t::unwind) ) {
419 pull_coroutine< void >::control_block::resume() {
420 other->ctx = boost::context::execution_context::current();
423 std::rethrow_exception( except);
429 pull_coroutine< void >::control_block::valid() const noexcept {
430 return nullptr != other && state_t::none == ( state & state_t::complete);
435 #ifdef BOOST_HAS_ABI_HEADERS
436 # include BOOST_ABI_SUFFIX
439 #endif // BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP