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_PULL_CONTROL_BLOCK_IPP 8#define BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP 9 10#include <exception> 11 12#include <boost/assert.hpp> 13#include <boost/config.hpp> 14 15#include <boost/context/execution_context.hpp> 16 17#include <boost/coroutine2/detail/config.hpp> 18#include <boost/coroutine2/detail/forced_unwind.hpp> 19#include <boost/coroutine2/detail/state.hpp> 20 21#ifdef BOOST_HAS_ABI_HEADERS 22# include BOOST_ABI_PREFIX 23#endif 24 25namespace boost { 26namespace coroutines2 { 27namespace detail { 28 29// pull_coroutine< T > 30 31template< typename T > 32template< typename StackAllocator, typename Fn > 33pull_coroutine< T >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, 34 Fn && fn_, bool preserve_fpu_) : 35 other( nullptr), 36 caller( boost::context::execution_context::current() ), 37 callee( palloc, salloc, 38 [=,fn=std::forward< Fn >( fn_)] () mutable -> decltype( auto) { 39 // create synthesized push_coroutine< T > 40 typename push_coroutine< T >::control_block synthesized_cb( this); 41 push_coroutine< T > synthesized( & synthesized_cb); 42 other = & synthesized_cb; 43 try { 44 // call coroutine-fn with synthesized push_coroutine as argument 45 fn( synthesized); 46 } catch ( forced_unwind const&) { 47 // do nothing for unwinding exception 48 } catch (...) { 49 // store other exceptions in exception-pointer 50 except = std::current_exception(); 51 } 52 // set termination flags 53 state |= static_cast< int >( state_t::complete); 54 // jump back to caller 55 caller( preserve_fpu); 56 BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); 57 }), 58 preserve_fpu( preserve_fpu_), 59 state( static_cast< int >( state_t::unwind) ), 60 except() { 61 callee( preserve_fpu); 62} 63 64template< typename T > 65pull_coroutine< T >::control_block::control_block( typename push_coroutine< T >::control_block * cb) : 66 other( cb), 67 caller( other->callee), 68 callee( other->caller), 69 preserve_fpu( other->preserve_fpu), 70 state( 0), 71 except() { 72} 73 74template< typename T > 75pull_coroutine< T >::control_block::~control_block() { 76 if ( 0 == ( state & static_cast< int >( state_t::complete ) ) && 77 0 != ( state & static_cast< int >( state_t::unwind) ) ) { 78 // set early-exit flag 79 state |= static_cast< int >( state_t::early_exit); 80 callee( preserve_fpu); 81 } 82} 83 84template< typename T > 85void 86pull_coroutine< T >::control_block::resume() { 87 callee( preserve_fpu); 88 if ( except) { 89 std::rethrow_exception( except); 90 } 91 // test early-exit-flag 92 if ( 0 != ( ( other->state) & static_cast< int >( state_t::early_exit) ) ) { 93 throw forced_unwind(); 94 } 95} 96 97template< typename T > 98bool 99pull_coroutine< T >::control_block::valid() const noexcept { 100 return nullptr != other && nullptr != other->t && 0 == ( state & static_cast< int >( state_t::complete) ); 101} 102 103 104// pull_coroutine< T & > 105 106template< typename T > 107template< typename StackAllocator, typename Fn > 108pull_coroutine< T & >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, 109 Fn && fn_, bool preserve_fpu_) : 110 other( nullptr), 111 caller( boost::context::execution_context::current() ), 112 callee( palloc, salloc, 113 [=,fn=std::forward< Fn >( fn_)] () mutable -> decltype( auto) { 114 // create synthesized push_coroutine< T > 115 typename push_coroutine< T & >::control_block synthesized_cb( this); 116 push_coroutine< T & > synthesized( & synthesized_cb); 117 other = & synthesized_cb; 118 try { 119 // call coroutine-fn with synthesized push_coroutine as argument 120 fn( synthesized); 121 } catch ( forced_unwind const&) { 122 // do nothing for unwinding exception 123 } catch (...) { 124 // store other exceptions in exception-pointer 125 except = std::current_exception(); 126 } 127 // set termination flags 128 state |= static_cast< int >( state_t::complete); 129 // jump back to caller 130 caller( preserve_fpu); 131 BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); 132 }), 133 preserve_fpu( preserve_fpu_), 134 state( static_cast< int >( state_t::unwind) ), 135 except() { 136 callee( preserve_fpu); 137} 138 139template< typename T > 140pull_coroutine< T & >::control_block::control_block( typename push_coroutine< T & >::control_block * cb) : 141 other( cb), 142 caller( other->callee), 143 callee( other->caller), 144 preserve_fpu( other->preserve_fpu), 145 state( 0), 146 except() { 147} 148 149template< typename T > 150pull_coroutine< T & >::control_block::~control_block() { 151 if ( 0 == ( state & static_cast< int >( state_t::complete ) ) && 152 0 != ( state & static_cast< int >( state_t::unwind) ) ) { 153 // set early-exit flag 154 state |= static_cast< int >( state_t::early_exit); 155 callee( preserve_fpu); 156 } 157} 158 159template< typename T > 160void 161pull_coroutine< T & >::control_block::resume() { 162 callee( preserve_fpu); 163 if ( except) { 164 std::rethrow_exception( except); 165 } 166 // test early-exit-flag 167 if ( 0 != ( ( other->state) & static_cast< int >( state_t::early_exit) ) ) { 168 throw forced_unwind(); 169 } 170} 171 172template< typename T > 173bool 174pull_coroutine< T & >::control_block::valid() const noexcept { 175 return nullptr != other && nullptr != other->t && 0 == ( state & static_cast< int >( state_t::complete) ); 176} 177 178 179// pull_coroutine< void > 180 181template< typename StackAllocator, typename Fn > 182pull_coroutine< void >::control_block::control_block( context::preallocated palloc, StackAllocator salloc, 183 Fn && fn_, bool preserve_fpu_) : 184 other( nullptr), 185 caller( boost::context::execution_context::current() ), 186 callee( palloc, salloc, 187 [=,fn=std::forward< Fn >( fn_)] () mutable -> decltype( auto) { 188 // create synthesized push_coroutine< T > 189 typename push_coroutine< void >::control_block synthesized_cb( this); 190 push_coroutine< void > synthesized( & synthesized_cb); 191 other = & synthesized_cb; 192 try { 193 // call coroutine-fn with synthesized push_coroutine as argument 194 fn( synthesized); 195 } catch ( forced_unwind const&) { 196 // do nothing for unwinding exception 197 } catch (...) { 198 // store other exceptions in exception-pointer 199 except = std::current_exception(); 200 } 201 // set termination flags 202 state |= static_cast< int >( state_t::complete); 203 // jump back to caller 204 caller( preserve_fpu); 205 BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); 206 }), 207 preserve_fpu( preserve_fpu_), 208 state( static_cast< int >( state_t::unwind) ), 209 except() { 210 callee( preserve_fpu); 211} 212 213inline 214pull_coroutine< void >::control_block::control_block( push_coroutine< void >::control_block * cb) : 215 other( cb), 216 caller( other->callee), 217 callee( other->caller), 218 preserve_fpu( other->preserve_fpu), 219 state( 0), 220 except() { 221} 222 223inline 224pull_coroutine< void >::control_block::~control_block() { 225 if ( 0 == ( state & static_cast< int >( state_t::complete ) ) && 226 0 != ( state & static_cast< int >( state_t::unwind) ) ) { 227 // set early-exit flag 228 state |= static_cast< int >( state_t::early_exit); 229 callee( preserve_fpu); 230 } 231} 232 233inline 234void 235pull_coroutine< void >::control_block::resume() { 236 callee( preserve_fpu); 237 if ( except) { 238 std::rethrow_exception( except); 239 } 240 // test early-exit-flag 241 if ( 0 != ( ( other->state) & static_cast< int >( state_t::early_exit) ) ) { 242 throw forced_unwind(); 243 } 244} 245 246inline 247bool 248pull_coroutine< void >::control_block::valid() const noexcept { 249 return nullptr != other && 0 == ( state & static_cast< int >( state_t::complete) ); 250} 251 252}}} 253 254#ifdef BOOST_HAS_ABI_HEADERS 255# include BOOST_ABI_SUFFIX 256#endif 257 258#endif // BOOST_COROUTINES2_DETAIL_PULL_CONTROL_BLOCK_IPP 259