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