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_SYMMETRIC_COROUTINE_OBJECT_H 8 #define BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_OBJECT_H 9 10 #include <boost/assert.hpp> 11 #include <boost/config.hpp> 12 #include <boost/move/move.hpp> 13 14 #include <boost/coroutine/detail/config.hpp> 15 #include <boost/coroutine/detail/flags.hpp> 16 #include <boost/coroutine/detail/preallocated.hpp> 17 #include <boost/coroutine/detail/symmetric_coroutine_impl.hpp> 18 #include <boost/coroutine/detail/symmetric_coroutine_yield.hpp> 19 #include <boost/coroutine/exceptions.hpp> 20 #include <boost/coroutine/stack_context.hpp> 21 22 #ifdef BOOST_HAS_ABI_HEADERS 23 # include BOOST_ABI_PREFIX 24 #endif 25 26 namespace boost { 27 namespace coroutines { 28 29 struct stack_context; 30 31 namespace detail { 32 33 template< typename R, typename Fn, typename StackAllocator > 34 class symmetric_coroutine_object : public symmetric_coroutine_impl< R > 35 { 36 private: 37 typedef symmetric_coroutine_impl< R > impl_t; 38 typedef symmetric_coroutine_object< R, Fn, StackAllocator > obj_t; 39 40 Fn fn_; 41 stack_context stack_ctx_; 42 StackAllocator stack_alloc_; 43 deallocate_(obj_t * obj)44 static void deallocate_( obj_t * obj) 45 { 46 stack_context stack_ctx( obj->stack_ctx_); 47 StackAllocator stack_alloc( obj->stack_alloc_); 48 obj->unwind_stack(); 49 obj->~obj_t(); 50 stack_alloc.deallocate( stack_ctx); 51 } 52 53 public: 54 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES symmetric_coroutine_object(Fn fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)55 symmetric_coroutine_object( Fn fn, attributes const& attrs, 56 preallocated const& palloc, 57 StackAllocator const& stack_alloc) BOOST_NOEXCEPT : 58 impl_t( palloc, 59 stack_unwind == attrs.do_unwind, 60 fpu_preserved == attrs.preserve_fpu), 61 fn_( fn), 62 stack_ctx_( palloc.sctx), 63 stack_alloc_( stack_alloc) 64 {} 65 #endif 66 symmetric_coroutine_object(BOOST_RV_REF (Fn)fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)67 symmetric_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs, 68 preallocated const& palloc, 69 StackAllocator const& stack_alloc) BOOST_NOEXCEPT : 70 impl_t( palloc, 71 stack_unwind == attrs.do_unwind, 72 fpu_preserved == attrs.preserve_fpu), 73 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES 74 fn_( fn), 75 #else 76 fn_( boost::forward< Fn >( fn) ), 77 #endif 78 stack_ctx_( palloc.sctx), 79 stack_alloc_( stack_alloc) 80 {} 81 run(R * r)82 void run( R * r) BOOST_NOEXCEPT 83 { 84 BOOST_ASSERT( ! impl_t::unwind_requested() ); 85 86 impl_t::flags_ |= flag_started; 87 impl_t::flags_ |= flag_running; 88 try 89 { 90 symmetric_coroutine_yield< R > yc( this, r); 91 fn_( yc); 92 } 93 catch ( forced_unwind const&) 94 {} 95 catch (...) 96 { std::terminate(); } 97 98 impl_t::flags_ |= flag_complete; 99 impl_t::flags_ &= ~flag_running; 100 typename impl_t::param_type to; 101 impl_t::callee_.jump( 102 impl_t::caller_, 103 reinterpret_cast< intptr_t >( & to), 104 impl_t::preserve_fpu() ); 105 BOOST_ASSERT_MSG( false, "coroutine is complete"); 106 } 107 destroy()108 void destroy() 109 { deallocate_( this); } 110 }; 111 112 template< typename R, typename Fn, typename StackAllocator > 113 class symmetric_coroutine_object< R &, Fn, StackAllocator > : public symmetric_coroutine_impl< R & > 114 { 115 private: 116 typedef symmetric_coroutine_impl< R & > impl_t; 117 typedef symmetric_coroutine_object< R &, Fn, StackAllocator > obj_t; 118 119 Fn fn_; 120 stack_context stack_ctx_; 121 StackAllocator stack_alloc_; 122 deallocate_(obj_t * obj)123 static void deallocate_( obj_t * obj) 124 { 125 stack_context stack_ctx( obj->stack_ctx_); 126 StackAllocator stack_alloc( obj->stack_alloc_); 127 obj->unwind_stack(); 128 obj->~obj_t(); 129 stack_alloc.deallocate( stack_ctx); 130 } 131 132 public: 133 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES symmetric_coroutine_object(Fn fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)134 symmetric_coroutine_object( Fn fn, attributes const& attrs, 135 preallocated const& palloc, 136 StackAllocator const& stack_alloc) BOOST_NOEXCEPT : 137 impl_t( palloc, 138 stack_unwind == attrs.do_unwind, 139 fpu_preserved == attrs.preserve_fpu), 140 fn_( fn), 141 stack_ctx_( palloc.sctx), 142 stack_alloc_( stack_alloc) 143 {} 144 #endif 145 symmetric_coroutine_object(BOOST_RV_REF (Fn)fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)146 symmetric_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs, 147 preallocated const& palloc, 148 StackAllocator const& stack_alloc) BOOST_NOEXCEPT : 149 impl_t( palloc, 150 stack_unwind == attrs.do_unwind, 151 fpu_preserved == attrs.preserve_fpu), 152 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES 153 fn_( fn), 154 #else 155 fn_( boost::forward< Fn >( fn) ), 156 #endif 157 stack_ctx_( palloc.sctx), 158 stack_alloc_( stack_alloc) 159 {} 160 run(R * r)161 void run( R * r) BOOST_NOEXCEPT 162 { 163 BOOST_ASSERT( ! impl_t::unwind_requested() ); 164 165 impl_t::flags_ |= flag_started; 166 impl_t::flags_ |= flag_running; 167 try 168 { 169 symmetric_coroutine_yield< R & > yc( this, r); 170 fn_( yc); 171 } 172 catch ( forced_unwind const&) 173 {} 174 catch (...) 175 { std::terminate(); } 176 177 impl_t::flags_ |= flag_complete; 178 impl_t::flags_ &= ~flag_running; 179 typename impl_t::param_type to; 180 impl_t::callee_.jump( 181 impl_t::caller_, 182 reinterpret_cast< intptr_t >( & to), 183 impl_t::preserve_fpu() ); 184 BOOST_ASSERT_MSG( false, "coroutine is complete"); 185 } 186 destroy()187 void destroy() 188 { deallocate_( this); } 189 }; 190 191 template< typename Fn, typename StackAllocator > 192 class symmetric_coroutine_object< void, Fn, StackAllocator > : public symmetric_coroutine_impl< void > 193 { 194 private: 195 typedef symmetric_coroutine_impl< void > impl_t; 196 typedef symmetric_coroutine_object< void, Fn, StackAllocator > obj_t; 197 198 Fn fn_; 199 stack_context stack_ctx_; 200 StackAllocator stack_alloc_; 201 deallocate_(obj_t * obj)202 static void deallocate_( obj_t * obj) 203 { 204 stack_context stack_ctx( obj->stack_ctx_); 205 StackAllocator stack_alloc( obj->stack_alloc_); 206 obj->unwind_stack(); 207 obj->~obj_t(); 208 stack_alloc.deallocate( stack_ctx); 209 } 210 211 public: 212 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES symmetric_coroutine_object(Fn fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)213 symmetric_coroutine_object( Fn fn, attributes const& attrs, 214 preallocated const& palloc, 215 StackAllocator const& stack_alloc) BOOST_NOEXCEPT : 216 impl_t( palloc, 217 stack_unwind == attrs.do_unwind, 218 fpu_preserved == attrs.preserve_fpu), 219 fn_( fn), 220 stack_ctx_( palloc.sctx), 221 stack_alloc_( stack_alloc) 222 {} 223 #endif 224 symmetric_coroutine_object(BOOST_RV_REF (Fn)fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)225 symmetric_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs, 226 preallocated const& palloc, 227 StackAllocator const& stack_alloc) BOOST_NOEXCEPT : 228 impl_t( palloc, 229 stack_unwind == attrs.do_unwind, 230 fpu_preserved == attrs.preserve_fpu), 231 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES 232 fn_( fn), 233 #else 234 fn_( boost::forward< Fn >( fn) ), 235 #endif 236 stack_ctx_( palloc.sctx), 237 stack_alloc_( stack_alloc) 238 {} 239 run()240 void run() BOOST_NOEXCEPT 241 { 242 BOOST_ASSERT( ! impl_t::unwind_requested() ); 243 244 impl_t::flags_ |= flag_started; 245 impl_t::flags_ |= flag_running; 246 try 247 { 248 symmetric_coroutine_yield< void > yc( this); 249 fn_( yc); 250 } 251 catch ( forced_unwind const&) 252 {} 253 catch (...) 254 { std::terminate(); } 255 256 impl_t::flags_ |= flag_complete; 257 impl_t::flags_ &= ~flag_running; 258 typename impl_t::param_type to; 259 impl_t::callee_.jump( 260 impl_t::caller_, 261 reinterpret_cast< intptr_t >( & to), 262 impl_t::preserve_fpu() ); 263 BOOST_ASSERT_MSG( false, "coroutine is complete"); 264 } 265 destroy()266 void destroy() 267 { deallocate_( this); } 268 }; 269 270 }}} 271 272 #ifdef BOOST_HAS_ABI_HEADERS 273 # include BOOST_ABI_SUFFIX 274 #endif 275 276 #endif // BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_OBJECT_H 277