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 fn_( fn), 61 stack_ctx_( palloc.sctx), 62 stack_alloc_( stack_alloc) 63 {} 64 #endif 65 symmetric_coroutine_object(BOOST_RV_REF (Fn)fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)66 symmetric_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs, 67 preallocated const& palloc, 68 StackAllocator const& stack_alloc) BOOST_NOEXCEPT : 69 impl_t( palloc, 70 stack_unwind == attrs.do_unwind), 71 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES 72 fn_( fn), 73 #else 74 fn_( boost::forward< Fn >( fn) ), 75 #endif 76 stack_ctx_( palloc.sctx), 77 stack_alloc_( stack_alloc) 78 {} 79 run(R * r)80 void run( R * r) BOOST_NOEXCEPT 81 { 82 BOOST_ASSERT( ! impl_t::unwind_requested() ); 83 84 impl_t::flags_ |= flag_started; 85 impl_t::flags_ |= flag_running; 86 try 87 { 88 symmetric_coroutine_yield< R > yc( this, r); 89 fn_( yc); 90 } 91 catch ( forced_unwind const&) 92 {} 93 catch (...) 94 { std::terminate(); } 95 96 impl_t::flags_ |= flag_complete; 97 impl_t::flags_ &= ~flag_running; 98 typename impl_t::param_type to; 99 impl_t::callee_.jump( 100 impl_t::caller_, 101 & to); 102 BOOST_ASSERT_MSG( false, "coroutine is complete"); 103 } 104 destroy()105 void destroy() 106 { deallocate_( this); } 107 }; 108 109 template< typename R, typename Fn, typename StackAllocator > 110 class symmetric_coroutine_object< R &, Fn, StackAllocator > : public symmetric_coroutine_impl< R & > 111 { 112 private: 113 typedef symmetric_coroutine_impl< R & > impl_t; 114 typedef symmetric_coroutine_object< R &, Fn, StackAllocator > obj_t; 115 116 Fn fn_; 117 stack_context stack_ctx_; 118 StackAllocator stack_alloc_; 119 deallocate_(obj_t * obj)120 static void deallocate_( obj_t * obj) 121 { 122 stack_context stack_ctx( obj->stack_ctx_); 123 StackAllocator stack_alloc( obj->stack_alloc_); 124 obj->unwind_stack(); 125 obj->~obj_t(); 126 stack_alloc.deallocate( stack_ctx); 127 } 128 129 public: 130 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES symmetric_coroutine_object(Fn fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)131 symmetric_coroutine_object( Fn fn, attributes const& attrs, 132 preallocated const& palloc, 133 StackAllocator const& stack_alloc) BOOST_NOEXCEPT : 134 impl_t( palloc, 135 stack_unwind == attrs.do_unwind), 136 fn_( fn), 137 stack_ctx_( palloc.sctx), 138 stack_alloc_( stack_alloc) 139 {} 140 #endif 141 symmetric_coroutine_object(BOOST_RV_REF (Fn)fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)142 symmetric_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs, 143 preallocated const& palloc, 144 StackAllocator const& stack_alloc) BOOST_NOEXCEPT : 145 impl_t( palloc, 146 stack_unwind == attrs.do_unwind), 147 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES 148 fn_( fn), 149 #else 150 fn_( boost::forward< Fn >( fn) ), 151 #endif 152 stack_ctx_( palloc.sctx), 153 stack_alloc_( stack_alloc) 154 {} 155 run(R * r)156 void run( R * r) BOOST_NOEXCEPT 157 { 158 BOOST_ASSERT( ! impl_t::unwind_requested() ); 159 160 impl_t::flags_ |= flag_started; 161 impl_t::flags_ |= flag_running; 162 try 163 { 164 symmetric_coroutine_yield< R & > yc( this, r); 165 fn_( yc); 166 } 167 catch ( forced_unwind const&) 168 {} 169 catch (...) 170 { std::terminate(); } 171 172 impl_t::flags_ |= flag_complete; 173 impl_t::flags_ &= ~flag_running; 174 typename impl_t::param_type to; 175 impl_t::callee_.jump( 176 impl_t::caller_, 177 & to); 178 BOOST_ASSERT_MSG( false, "coroutine is complete"); 179 } 180 destroy()181 void destroy() 182 { deallocate_( this); } 183 }; 184 185 template< typename Fn, typename StackAllocator > 186 class symmetric_coroutine_object< void, Fn, StackAllocator > : public symmetric_coroutine_impl< void > 187 { 188 private: 189 typedef symmetric_coroutine_impl< void > impl_t; 190 typedef symmetric_coroutine_object< void, Fn, StackAllocator > obj_t; 191 192 Fn fn_; 193 stack_context stack_ctx_; 194 StackAllocator stack_alloc_; 195 deallocate_(obj_t * obj)196 static void deallocate_( obj_t * obj) 197 { 198 stack_context stack_ctx( obj->stack_ctx_); 199 StackAllocator stack_alloc( obj->stack_alloc_); 200 obj->unwind_stack(); 201 obj->~obj_t(); 202 stack_alloc.deallocate( stack_ctx); 203 } 204 205 public: 206 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES symmetric_coroutine_object(Fn fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)207 symmetric_coroutine_object( Fn fn, attributes const& attrs, 208 preallocated const& palloc, 209 StackAllocator const& stack_alloc) BOOST_NOEXCEPT : 210 impl_t( palloc, 211 stack_unwind == attrs.do_unwind), 212 fn_( fn), 213 stack_ctx_( palloc.sctx), 214 stack_alloc_( stack_alloc) 215 {} 216 #endif 217 symmetric_coroutine_object(BOOST_RV_REF (Fn)fn,attributes const & attrs,preallocated const & palloc,StackAllocator const & stack_alloc)218 symmetric_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs, 219 preallocated const& palloc, 220 StackAllocator const& stack_alloc) BOOST_NOEXCEPT : 221 impl_t( palloc, 222 stack_unwind == attrs.do_unwind), 223 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES 224 fn_( fn), 225 #else 226 fn_( boost::forward< Fn >( fn) ), 227 #endif 228 stack_ctx_( palloc.sctx), 229 stack_alloc_( stack_alloc) 230 {} 231 run()232 void run() BOOST_NOEXCEPT 233 { 234 BOOST_ASSERT( ! impl_t::unwind_requested() ); 235 236 impl_t::flags_ |= flag_started; 237 impl_t::flags_ |= flag_running; 238 try 239 { 240 symmetric_coroutine_yield< void > yc( this); 241 fn_( yc); 242 } 243 catch ( forced_unwind const&) 244 {} 245 catch (...) 246 { std::terminate(); } 247 248 impl_t::flags_ |= flag_complete; 249 impl_t::flags_ &= ~flag_running; 250 typename impl_t::param_type to; 251 impl_t::callee_.jump( 252 impl_t::caller_, 253 & to); 254 BOOST_ASSERT_MSG( false, "coroutine is complete"); 255 } 256 destroy()257 void destroy() 258 { deallocate_( this); } 259 }; 260 261 }}} 262 263 #ifdef BOOST_HAS_ABI_HEADERS 264 # include BOOST_ABI_SUFFIX 265 #endif 266 267 #endif // BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_OBJECT_H 268