1 2 // Copyright Oliver Kowalke 2009. 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_COROUTINES_DETAIL_PUSH_COROUTINE_OBJECT_H 8 #define BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_OBJECT_H 9 10 #include <boost/assert.hpp> 11 #include <boost/config.hpp> 12 #include <boost/context/detail/config.hpp> 13 #include <boost/cstdint.hpp> 14 #include <boost/exception_ptr.hpp> 15 #include <boost/move/move.hpp> 16 17 #include <boost/coroutine/detail/config.hpp> 18 #include <boost/coroutine/detail/coroutine_context.hpp> 19 #include <boost/coroutine/detail/flags.hpp> 20 #include <boost/coroutine/detail/preallocated.hpp> 21 #include <boost/coroutine/detail/push_coroutine_impl.hpp> 22 #include <boost/coroutine/detail/trampoline_push.hpp> 23 #include <boost/coroutine/exceptions.hpp> 24 #include <boost/coroutine/flags.hpp> 25 #include <boost/coroutine/stack_context.hpp> 26 27 #ifdef BOOST_HAS_ABI_HEADERS 28 # include BOOST_ABI_PREFIX 29 #endif 30 31 #if defined(BOOST_MSVC) 32 # pragma warning(push) 33 # pragma warning(disable:4355) 34 #endif 35 36 namespace boost { 37 namespace coroutines { 38 namespace detail { 39 40 struct push_coroutine_context 41 { 42 coroutine_context caller; 43 coroutine_context callee; 44 45 template< typename Coro > push_coroutine_contextboost::coroutines::detail::push_coroutine_context46 push_coroutine_context( preallocated const& palloc, Coro *) : 47 caller(), 48 callee( trampoline_push< Coro >, palloc) 49 {} 50 }; 51 52 struct push_coroutine_context_void 53 { 54 coroutine_context caller; 55 coroutine_context callee; 56 57 template< typename Coro > push_coroutine_context_voidboost::coroutines::detail::push_coroutine_context_void58 push_coroutine_context_void( preallocated const& palloc, Coro *) : 59 caller(), 60 callee( trampoline_push_void< Coro >, palloc) 61 {} 62 }; 63 64 template< typename PullCoro, typename R, typename Fn, typename StackAllocator > 65 class push_coroutine_object : private push_coroutine_context, 66 public push_coroutine_impl< R > 67 { 68 private: 69 typedef push_coroutine_context ctx_t; 70 typedef push_coroutine_impl< R > base_t; 71 typedef push_coroutine_object< PullCoro, R, Fn, StackAllocator > obj_t; 72 73 Fn fn_; 74 stack_context stack_ctx_; 75 StackAllocator stack_alloc_; 76 deallocate_(obj_t * obj)77 static void deallocate_( obj_t * obj) 78 { 79 stack_context stack_ctx( obj->stack_ctx_); 80 StackAllocator stack_alloc( obj->stack_alloc_); 81 obj->unwind_stack(); 82 obj->~obj_t(); 83 stack_alloc.deallocate( stack_ctx); 84 } 85 86 public: 87 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES push_coroutine_object(Fn fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)88 push_coroutine_object( Fn fn, attributes const& attrs, 89 preallocated const& palloc, 90 StackAllocator const& stack_alloc) BOOST_NOEXCEPT : 91 ctx_t( palloc, this), 92 base_t( & this->caller, 93 & this->callee, 94 stack_unwind == attrs.do_unwind), 95 fn_( fn), 96 stack_ctx_( palloc.sctx), 97 stack_alloc_( stack_alloc) 98 {} 99 #endif 100 push_coroutine_object(BOOST_RV_REF (Fn)fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)101 push_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs, 102 preallocated const& palloc, 103 StackAllocator const& stack_alloc) BOOST_NOEXCEPT : 104 ctx_t( palloc, this), 105 base_t( & this->caller, 106 & this->callee, 107 stack_unwind == attrs.do_unwind), 108 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES 109 fn_( fn), 110 #else 111 fn_( boost::forward< Fn >( fn) ), 112 #endif 113 stack_ctx_( palloc.sctx), 114 stack_alloc_( stack_alloc) 115 {} 116 run(R * result)117 void run( R * result) 118 { 119 BOOST_ASSERT( ! base_t::unwind_requested() ); 120 121 base_t::flags_ |= flag_started; 122 base_t::flags_ |= flag_running; 123 124 // create push_coroutine 125 typename PullCoro::synth_type b( & this->callee, & this->caller, false, result); 126 PullCoro pull_coro( synthesized_t::syntesized, b); 127 try 128 { fn_( pull_coro); } 129 catch ( forced_unwind const&) 130 {} 131 #if defined( BOOST_CONTEXT_HAS_CXXABI_H ) 132 catch ( abi::__forced_unwind const&) 133 { throw; } 134 #endif 135 catch (...) 136 { base_t::except_ = current_exception(); } 137 138 base_t::flags_ |= flag_complete; 139 base_t::flags_ &= ~flag_running; 140 typename base_t::param_type to; 141 this->callee.jump( 142 this->caller, 143 & to); 144 BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); 145 } 146 destroy()147 void destroy() 148 { deallocate_( this); } 149 }; 150 151 template< typename PullCoro, typename R, typename Fn, typename StackAllocator > 152 class push_coroutine_object< PullCoro, R &, Fn, StackAllocator > : private push_coroutine_context, 153 public push_coroutine_impl< R & > 154 { 155 private: 156 typedef push_coroutine_context ctx_t; 157 typedef push_coroutine_impl< R & > base_t; 158 typedef push_coroutine_object< PullCoro, R &, Fn, StackAllocator > obj_t; 159 160 Fn fn_; 161 stack_context stack_ctx_; 162 StackAllocator stack_alloc_; 163 deallocate_(obj_t * obj)164 static void deallocate_( obj_t * obj) 165 { 166 stack_context stack_ctx( obj->stack_ctx_); 167 StackAllocator stack_alloc( obj->stack_alloc_); 168 obj->unwind_stack(); 169 obj->~obj_t(); 170 stack_alloc.deallocate( stack_ctx); 171 } 172 173 public: 174 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES push_coroutine_object(Fn fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)175 push_coroutine_object( Fn fn, attributes const& attrs, 176 preallocated const& palloc, 177 StackAllocator const& stack_alloc) BOOST_NOEXCEPT : 178 ctx_t( palloc, this), 179 base_t( & this->caller, 180 & this->callee, 181 stack_unwind == attrs.do_unwind), 182 fn_( fn), 183 stack_ctx_( palloc.sctx), 184 stack_alloc_( stack_alloc) 185 {} 186 #endif 187 push_coroutine_object(BOOST_RV_REF (Fn)fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)188 push_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs, 189 preallocated const& palloc, 190 StackAllocator const& stack_alloc) BOOST_NOEXCEPT : 191 ctx_t( palloc, this), 192 base_t( & this->caller, 193 & this->callee, 194 stack_unwind == attrs.do_unwind), 195 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES 196 fn_( fn), 197 #else 198 fn_( boost::forward< Fn >( fn) ), 199 #endif 200 stack_ctx_( palloc.sctx), 201 stack_alloc_( stack_alloc) 202 {} 203 run(R * result)204 void run( R * result) 205 { 206 BOOST_ASSERT( ! base_t::unwind_requested() ); 207 208 base_t::flags_ |= flag_started; 209 base_t::flags_ |= flag_running; 210 211 // create push_coroutine 212 typename PullCoro::synth_type b( & this->callee, & this->caller, false, result); 213 PullCoro push_coro( synthesized_t::syntesized, b); 214 try 215 { fn_( push_coro); } 216 catch ( forced_unwind const&) 217 {} 218 #if defined( BOOST_CONTEXT_HAS_CXXABI_H ) 219 catch ( abi::__forced_unwind const&) 220 { throw; } 221 #endif 222 catch (...) 223 { base_t::except_ = current_exception(); } 224 225 base_t::flags_ |= flag_complete; 226 base_t::flags_ &= ~flag_running; 227 typename base_t::param_type to; 228 this->callee.jump( 229 this->caller, 230 & to); 231 BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); 232 } 233 destroy()234 void destroy() 235 { deallocate_( this); } 236 }; 237 238 template< typename PullCoro, typename Fn, typename StackAllocator > 239 class push_coroutine_object< PullCoro, void, Fn, StackAllocator > : private push_coroutine_context_void, 240 public push_coroutine_impl< void > 241 { 242 private: 243 typedef push_coroutine_context_void ctx_t; 244 typedef push_coroutine_impl< void > base_t; 245 typedef push_coroutine_object< PullCoro, void, Fn, StackAllocator > obj_t; 246 247 Fn fn_; 248 stack_context stack_ctx_; 249 StackAllocator stack_alloc_; 250 deallocate_(obj_t * obj)251 static void deallocate_( obj_t * obj) 252 { 253 stack_context stack_ctx( obj->stack_ctx_); 254 StackAllocator stack_alloc( obj->stack_alloc_); 255 obj->unwind_stack(); 256 obj->~obj_t(); 257 stack_alloc.deallocate( stack_ctx); 258 } 259 260 public: 261 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES push_coroutine_object(Fn fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)262 push_coroutine_object( Fn fn, attributes const& attrs, 263 preallocated const& palloc, 264 StackAllocator const& stack_alloc) BOOST_NOEXCEPT : 265 ctx_t( palloc, this), 266 base_t( & this->caller, 267 & this->callee, 268 stack_unwind == attrs.do_unwind), 269 fn_( fn), 270 stack_ctx_( palloc.sctx), 271 stack_alloc_( stack_alloc) 272 {} 273 #endif 274 push_coroutine_object(BOOST_RV_REF (Fn)fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)275 push_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs, 276 preallocated const& palloc, 277 StackAllocator const& stack_alloc) BOOST_NOEXCEPT : 278 ctx_t( palloc, this), 279 base_t( & this->caller, 280 & this->callee, 281 stack_unwind == attrs.do_unwind), 282 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES 283 fn_( fn), 284 #else 285 fn_( boost::forward< Fn >( fn) ), 286 #endif 287 stack_ctx_( palloc.sctx), 288 stack_alloc_( stack_alloc) 289 {} 290 run()291 void run() 292 { 293 BOOST_ASSERT( ! base_t::unwind_requested() ); 294 295 base_t::flags_ |= flag_started; 296 base_t::flags_ |= flag_running; 297 298 // create push_coroutine 299 typename PullCoro::synth_type b( & this->callee, & this->caller, false); 300 PullCoro push_coro( synthesized_t::syntesized, b); 301 try 302 { fn_( push_coro); } 303 catch ( forced_unwind const&) 304 {} 305 #if defined( BOOST_CONTEXT_HAS_CXXABI_H ) 306 catch ( abi::__forced_unwind const&) 307 { throw; } 308 #endif 309 catch (...) 310 { base_t::except_ = current_exception(); } 311 312 base_t::flags_ |= flag_complete; 313 base_t::flags_ &= ~flag_running; 314 typename base_t::param_type to; 315 this->callee.jump( 316 this->caller, 317 & to); 318 BOOST_ASSERT_MSG( false, "pull_coroutine is complete"); 319 } 320 destroy()321 void destroy() 322 { deallocate_( this); } 323 }; 324 325 }}} 326 327 #if defined(BOOST_MSVC) 328 # pragma warning(pop) 329 #endif 330 331 #ifdef BOOST_HAS_ABI_HEADERS 332 # include BOOST_ABI_SUFFIX 333 #endif 334 335 #endif // BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_OBJECT_H 336