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