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_IMPL_H 8 #define BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_IMPL_H 9 10 #include <boost/assert.hpp> 11 #include <boost/config.hpp> 12 #include <boost/exception_ptr.hpp> 13 #include <boost/throw_exception.hpp> 14 #include <boost/utility.hpp> 15 16 #include <boost/coroutine/detail/config.hpp> 17 #include <boost/coroutine/detail/coroutine_context.hpp> 18 #include <boost/coroutine/detail/flags.hpp> 19 #include <boost/coroutine/detail/parameters.hpp> 20 #include <boost/coroutine/detail/trampoline_push.hpp> 21 #include <boost/coroutine/exceptions.hpp> 22 23 #ifdef BOOST_HAS_ABI_HEADERS 24 # include BOOST_ABI_PREFIX 25 #endif 26 27 namespace boost { 28 namespace coroutines { 29 30 struct stack_context; 31 32 namespace detail { 33 34 template< typename Arg > 35 class push_coroutine_impl : private noncopyable 36 { 37 protected: 38 int flags_; 39 exception_ptr except_; 40 coroutine_context * caller_; 41 coroutine_context * callee_; 42 43 public: 44 typedef parameters< Arg > param_type; 45 push_coroutine_impl(coroutine_context * caller,coroutine_context * callee,bool unwind)46 push_coroutine_impl( coroutine_context * caller, 47 coroutine_context * callee, 48 bool unwind) : 49 flags_( 0), 50 except_(), 51 caller_( caller), 52 callee_( callee) 53 { 54 if ( unwind) flags_ |= flag_force_unwind; 55 } 56 ~push_coroutine_impl()57 virtual ~push_coroutine_impl() {} 58 force_unwind() const59 bool force_unwind() const BOOST_NOEXCEPT 60 { return 0 != ( flags_ & flag_force_unwind); } 61 unwind_requested() const62 bool unwind_requested() const BOOST_NOEXCEPT 63 { return 0 != ( flags_ & flag_unwind_stack); } 64 is_started() const65 bool is_started() const BOOST_NOEXCEPT 66 { return 0 != ( flags_ & flag_started); } 67 is_running() const68 bool is_running() const BOOST_NOEXCEPT 69 { return 0 != ( flags_ & flag_running); } 70 is_complete() const71 bool is_complete() const BOOST_NOEXCEPT 72 { return 0 != ( flags_ & flag_complete); } 73 unwind_stack()74 void unwind_stack() BOOST_NOEXCEPT 75 { 76 if ( is_started() && ! is_complete() && force_unwind() ) 77 { 78 flags_ |= flag_unwind_stack; 79 param_type to( unwind_t::force_unwind); 80 caller_->jump( 81 * callee_, 82 & to); 83 flags_ &= ~flag_unwind_stack; 84 85 BOOST_ASSERT( is_complete() ); 86 } 87 } 88 push(Arg const & arg)89 void push( Arg const& arg) 90 { 91 BOOST_ASSERT( ! is_running() ); 92 BOOST_ASSERT( ! is_complete() ); 93 94 flags_ |= flag_running; 95 param_type to( const_cast< Arg * >( & arg), this); 96 param_type * from( 97 static_cast< param_type * >( 98 caller_->jump( 99 * callee_, 100 & to) ) ); 101 flags_ &= ~flag_running; 102 if ( from->do_unwind) throw forced_unwind(); 103 if ( except_) rethrow_exception( except_); 104 } 105 push(BOOST_RV_REF (Arg)arg)106 void push( BOOST_RV_REF( Arg) arg) 107 { 108 BOOST_ASSERT( ! is_running() ); 109 BOOST_ASSERT( ! is_complete() ); 110 111 flags_ |= flag_running; 112 param_type to( const_cast< Arg * >( & arg), this); 113 param_type * from( 114 static_cast< param_type * >( 115 caller_->jump( 116 * callee_, 117 & to) ) ); 118 flags_ &= ~flag_running; 119 if ( from->do_unwind) throw forced_unwind(); 120 if ( except_) rethrow_exception( except_); 121 } 122 123 virtual void destroy() = 0; 124 }; 125 126 template< typename Arg > 127 class push_coroutine_impl< Arg & > : private noncopyable 128 { 129 protected: 130 int flags_; 131 exception_ptr except_; 132 coroutine_context * caller_; 133 coroutine_context * callee_; 134 135 public: 136 typedef parameters< Arg & > param_type; 137 push_coroutine_impl(coroutine_context * caller,coroutine_context * callee,bool unwind)138 push_coroutine_impl( coroutine_context * caller, 139 coroutine_context * callee, 140 bool unwind) : 141 flags_( 0), 142 except_(), 143 caller_( caller), 144 callee_( callee) 145 { 146 if ( unwind) flags_ |= flag_force_unwind; 147 } 148 ~push_coroutine_impl()149 virtual ~push_coroutine_impl() {} 150 force_unwind() const151 bool force_unwind() const BOOST_NOEXCEPT 152 { return 0 != ( flags_ & flag_force_unwind); } 153 unwind_requested() const154 bool unwind_requested() const BOOST_NOEXCEPT 155 { return 0 != ( flags_ & flag_unwind_stack); } 156 is_started() const157 bool is_started() const BOOST_NOEXCEPT 158 { return 0 != ( flags_ & flag_started); } 159 is_running() const160 bool is_running() const BOOST_NOEXCEPT 161 { return 0 != ( flags_ & flag_running); } 162 is_complete() const163 bool is_complete() const BOOST_NOEXCEPT 164 { return 0 != ( flags_ & flag_complete); } 165 unwind_stack()166 void unwind_stack() BOOST_NOEXCEPT 167 { 168 if ( is_started() && ! is_complete() && force_unwind() ) 169 { 170 flags_ |= flag_unwind_stack; 171 param_type to( unwind_t::force_unwind); 172 caller_->jump( 173 * callee_, 174 & to); 175 flags_ &= ~flag_unwind_stack; 176 177 BOOST_ASSERT( is_complete() ); 178 } 179 } 180 push(Arg & arg)181 void push( Arg & arg) 182 { 183 BOOST_ASSERT( ! is_running() ); 184 BOOST_ASSERT( ! is_complete() ); 185 186 flags_ |= flag_running; 187 param_type to( & arg, this); 188 param_type * from( 189 static_cast< param_type * >( 190 caller_->jump( 191 * callee_, 192 & to) ) ); 193 flags_ &= ~flag_running; 194 if ( from->do_unwind) throw forced_unwind(); 195 if ( except_) rethrow_exception( except_); 196 } 197 198 virtual void destroy() = 0; 199 }; 200 201 template<> 202 class push_coroutine_impl< void > : private noncopyable 203 { 204 protected: 205 int flags_; 206 exception_ptr except_; 207 coroutine_context * caller_; 208 coroutine_context * callee_; 209 210 public: 211 typedef parameters< void > param_type; 212 push_coroutine_impl(coroutine_context * caller,coroutine_context * callee,bool unwind)213 push_coroutine_impl( coroutine_context * caller, 214 coroutine_context * callee, 215 bool unwind) : 216 flags_( 0), 217 except_(), 218 caller_( caller), 219 callee_( callee) 220 { 221 if ( unwind) flags_ |= flag_force_unwind; 222 } 223 ~push_coroutine_impl()224 virtual ~push_coroutine_impl() {} 225 force_unwind() const226 inline bool force_unwind() const BOOST_NOEXCEPT 227 { return 0 != ( flags_ & flag_force_unwind); } 228 unwind_requested() const229 inline bool unwind_requested() const BOOST_NOEXCEPT 230 { return 0 != ( flags_ & flag_unwind_stack); } 231 is_started() const232 inline bool is_started() const BOOST_NOEXCEPT 233 { return 0 != ( flags_ & flag_started); } 234 is_running() const235 inline bool is_running() const BOOST_NOEXCEPT 236 { return 0 != ( flags_ & flag_running); } 237 is_complete() const238 inline bool is_complete() const BOOST_NOEXCEPT 239 { return 0 != ( flags_ & flag_complete); } 240 unwind_stack()241 inline void unwind_stack() BOOST_NOEXCEPT 242 { 243 if ( is_started() && ! is_complete() && force_unwind() ) 244 { 245 flags_ |= flag_unwind_stack; 246 param_type to( unwind_t::force_unwind); 247 caller_->jump( 248 * callee_, 249 & to); 250 flags_ &= ~flag_unwind_stack; 251 252 BOOST_ASSERT( is_complete() ); 253 } 254 } 255 push()256 inline void push() 257 { 258 BOOST_ASSERT( ! is_running() ); 259 BOOST_ASSERT( ! is_complete() ); 260 261 flags_ |= flag_running; 262 param_type to( this); 263 param_type * from( 264 static_cast< param_type * >( 265 caller_->jump( 266 * callee_, 267 & to) ) ); 268 flags_ &= ~flag_running; 269 if ( from->do_unwind) throw forced_unwind(); 270 if ( except_) rethrow_exception( except_); 271 } 272 273 virtual void destroy() = 0; 274 }; 275 276 }}} 277 278 #ifdef BOOST_HAS_ABI_HEADERS 279 # include BOOST_ABI_SUFFIX 280 #endif 281 282 #endif // BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_IMPL_H 283