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_IMPL_H 8 #define BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_IMPL_H 9 10 #include <boost/assert.hpp> 11 #include <boost/config.hpp> 12 #include <boost/cstdint.hpp> 13 #include <boost/utility.hpp> 14 15 #include <boost/coroutine/detail/config.hpp> 16 #include <boost/coroutine/detail/coroutine_context.hpp> 17 #include <boost/coroutine/detail/flags.hpp> 18 #include <boost/coroutine/detail/parameters.hpp> 19 #include <boost/coroutine/detail/preallocated.hpp> 20 #include <boost/coroutine/detail/trampoline.hpp> 21 #include <boost/coroutine/exceptions.hpp> 22 #include <boost/coroutine/stack_context.hpp> 23 24 #ifdef BOOST_HAS_ABI_HEADERS 25 # include BOOST_ABI_PREFIX 26 #endif 27 28 namespace boost { 29 namespace coroutines { 30 namespace detail { 31 32 template< typename R > 33 class symmetric_coroutine_impl : private noncopyable 34 { 35 public: 36 typedef parameters< R > param_type; 37 symmetric_coroutine_impl(preallocated const & palloc,bool unwind)38 symmetric_coroutine_impl( preallocated const& palloc, 39 bool unwind) BOOST_NOEXCEPT : 40 flags_( 0), 41 caller_(), 42 callee_( trampoline< symmetric_coroutine_impl< R > >, palloc) 43 { 44 if ( unwind) flags_ |= flag_force_unwind; 45 } 46 ~symmetric_coroutine_impl()47 virtual ~symmetric_coroutine_impl() {} 48 force_unwind() const49 bool force_unwind() const BOOST_NOEXCEPT 50 { return 0 != ( flags_ & flag_force_unwind); } 51 unwind_requested() const52 bool unwind_requested() const BOOST_NOEXCEPT 53 { return 0 != ( flags_ & flag_unwind_stack); } 54 is_started() const55 bool is_started() const BOOST_NOEXCEPT 56 { return 0 != ( flags_ & flag_started); } 57 is_running() const58 bool is_running() const BOOST_NOEXCEPT 59 { return 0 != ( flags_ & flag_running); } 60 is_complete() const61 bool is_complete() const BOOST_NOEXCEPT 62 { return 0 != ( flags_ & flag_complete); } 63 unwind_stack()64 void unwind_stack() BOOST_NOEXCEPT 65 { 66 if ( is_started() && ! is_complete() && force_unwind() ) 67 { 68 flags_ |= flag_unwind_stack; 69 flags_ |= flag_running; 70 param_type to( unwind_t::force_unwind); 71 caller_.jump( 72 callee_, 73 & to); 74 flags_ &= ~flag_running; 75 flags_ &= ~flag_unwind_stack; 76 77 BOOST_ASSERT( is_complete() ); 78 } 79 } 80 resume(R r)81 void resume( R r) BOOST_NOEXCEPT 82 { 83 param_type to( const_cast< R * >( & r), this); 84 resume_( & to); 85 } 86 yield()87 R * yield() 88 { 89 BOOST_ASSERT( is_running() ); 90 BOOST_ASSERT( ! is_complete() ); 91 92 flags_ &= ~flag_running; 93 param_type to; 94 param_type * from( 95 static_cast< param_type * >( 96 callee_.jump( 97 caller_, 98 & to) ) ); 99 flags_ |= flag_running; 100 if ( from->do_unwind) throw forced_unwind(); 101 BOOST_ASSERT( from->data); 102 return from->data; 103 } 104 105 template< typename X > yield_to(symmetric_coroutine_impl<X> * other,X x)106 R * yield_to( symmetric_coroutine_impl< X > * other, X x) 107 { 108 typename symmetric_coroutine_impl< X >::param_type to( & x, other); 109 return yield_to_( other, & to); 110 } 111 112 template< typename X > yield_to(symmetric_coroutine_impl<X &> * other,X & x)113 R * yield_to( symmetric_coroutine_impl< X & > * other, X & x) 114 { 115 typename symmetric_coroutine_impl< X & >::param_type to( & x, other); 116 return yield_to_( other, & to); 117 } 118 119 template< typename X > yield_to(symmetric_coroutine_impl<X> * other)120 R * yield_to( symmetric_coroutine_impl< X > * other) 121 { 122 typename symmetric_coroutine_impl< X >::param_type to( other); 123 return yield_to_( other, & to); 124 } 125 126 virtual void run( R *) BOOST_NOEXCEPT = 0; 127 128 virtual void destroy() = 0; 129 130 protected: 131 template< typename X > 132 friend class symmetric_coroutine_impl; 133 134 int flags_; 135 coroutine_context caller_; 136 coroutine_context callee_; 137 resume_(param_type * to)138 void resume_( param_type * to) BOOST_NOEXCEPT 139 { 140 BOOST_ASSERT( ! is_running() ); 141 BOOST_ASSERT( ! is_complete() ); 142 143 flags_ |= flag_running; 144 caller_.jump( 145 callee_, 146 to); 147 flags_ &= ~flag_running; 148 } 149 150 template< typename Other > yield_to_(Other * other,typename Other::param_type * to)151 R * yield_to_( Other * other, typename Other::param_type * to) 152 { 153 BOOST_ASSERT( is_running() ); 154 BOOST_ASSERT( ! is_complete() ); 155 BOOST_ASSERT( ! other->is_running() ); 156 BOOST_ASSERT( ! other->is_complete() ); 157 158 other->caller_ = caller_; 159 flags_ &= ~flag_running; 160 param_type * from( 161 static_cast< param_type * >( 162 callee_.jump( 163 other->callee_, 164 to) ) ); 165 flags_ |= flag_running; 166 if ( from->do_unwind) throw forced_unwind(); 167 BOOST_ASSERT( from->data); 168 return from->data; 169 } 170 }; 171 172 template< typename R > 173 class symmetric_coroutine_impl< R & > : private noncopyable 174 { 175 public: 176 typedef parameters< R & > param_type; 177 symmetric_coroutine_impl(preallocated const & palloc,bool unwind)178 symmetric_coroutine_impl( preallocated const& palloc, 179 bool unwind) BOOST_NOEXCEPT : 180 flags_( 0), 181 caller_(), 182 callee_( trampoline< symmetric_coroutine_impl< R > >, palloc) 183 { 184 if ( unwind) flags_ |= flag_force_unwind; 185 } 186 ~symmetric_coroutine_impl()187 virtual ~symmetric_coroutine_impl() {} 188 force_unwind() const189 bool force_unwind() const BOOST_NOEXCEPT 190 { return 0 != ( flags_ & flag_force_unwind); } 191 unwind_requested() const192 bool unwind_requested() const BOOST_NOEXCEPT 193 { return 0 != ( flags_ & flag_unwind_stack); } 194 is_started() const195 bool is_started() const BOOST_NOEXCEPT 196 { return 0 != ( flags_ & flag_started); } 197 is_running() const198 bool is_running() const BOOST_NOEXCEPT 199 { return 0 != ( flags_ & flag_running); } 200 is_complete() const201 bool is_complete() const BOOST_NOEXCEPT 202 { return 0 != ( flags_ & flag_complete); } 203 unwind_stack()204 void unwind_stack() BOOST_NOEXCEPT 205 { 206 if ( is_started() && ! is_complete() && force_unwind() ) 207 { 208 flags_ |= flag_unwind_stack; 209 flags_ |= flag_running; 210 param_type to( unwind_t::force_unwind); 211 caller_.jump( 212 callee_, 213 & to); 214 flags_ &= ~flag_running; 215 flags_ &= ~flag_unwind_stack; 216 217 BOOST_ASSERT( is_complete() ); 218 } 219 } 220 resume(R & arg)221 void resume( R & arg) BOOST_NOEXCEPT 222 { 223 param_type to( & arg, this); 224 resume_( & to); 225 } 226 yield()227 R * yield() 228 { 229 BOOST_ASSERT( is_running() ); 230 BOOST_ASSERT( ! is_complete() ); 231 232 flags_ &= ~flag_running; 233 param_type to; 234 param_type * from( 235 static_cast< param_type * >( 236 callee_.jump( 237 caller_, 238 & to) ) ); 239 flags_ |= flag_running; 240 if ( from->do_unwind) throw forced_unwind(); 241 BOOST_ASSERT( from->data); 242 return from->data; 243 } 244 245 template< typename X > yield_to(symmetric_coroutine_impl<X> * other,X x)246 R * yield_to( symmetric_coroutine_impl< X > * other, X x) 247 { 248 typename symmetric_coroutine_impl< X >::param_type to( & x, other); 249 return yield_to_( other, & to); 250 } 251 252 template< typename X > yield_to(symmetric_coroutine_impl<X &> * other,X & x)253 R * yield_to( symmetric_coroutine_impl< X & > * other, X & x) 254 { 255 typename symmetric_coroutine_impl< X & >::param_type to( & x, other); 256 return yield_to_( other, & to); 257 } 258 259 template< typename X > yield_to(symmetric_coroutine_impl<X> * other)260 R * yield_to( symmetric_coroutine_impl< X > * other) 261 { 262 typename symmetric_coroutine_impl< X >::param_type to( other); 263 return yield_to_( other, & to); 264 } 265 266 virtual void run( R *) BOOST_NOEXCEPT = 0; 267 268 virtual void destroy() = 0; 269 270 protected: 271 template< typename X > 272 friend class symmetric_coroutine_impl; 273 274 int flags_; 275 coroutine_context caller_; 276 coroutine_context callee_; 277 resume_(param_type * to)278 void resume_( param_type * to) BOOST_NOEXCEPT 279 { 280 BOOST_ASSERT( ! is_running() ); 281 BOOST_ASSERT( ! is_complete() ); 282 283 flags_ |= flag_running; 284 caller_.jump( 285 callee_, 286 to); 287 flags_ &= ~flag_running; 288 } 289 290 template< typename Other > yield_to_(Other * other,typename Other::param_type * to)291 R * yield_to_( Other * other, typename Other::param_type * to) 292 { 293 BOOST_ASSERT( is_running() ); 294 BOOST_ASSERT( ! is_complete() ); 295 BOOST_ASSERT( ! other->is_running() ); 296 BOOST_ASSERT( ! other->is_complete() ); 297 298 other->caller_ = caller_; 299 flags_ &= ~flag_running; 300 param_type * from( 301 static_cast< param_type * >( 302 callee_.jump( 303 other->callee_, 304 to) ) ); 305 flags_ |= flag_running; 306 if ( from->do_unwind) throw forced_unwind(); 307 BOOST_ASSERT( from->data); 308 return from->data; 309 } 310 }; 311 312 template<> 313 class symmetric_coroutine_impl< void > : private noncopyable 314 { 315 public: 316 typedef parameters< void > param_type; 317 symmetric_coroutine_impl(preallocated const & palloc,bool unwind)318 symmetric_coroutine_impl( preallocated const& palloc, 319 bool unwind) BOOST_NOEXCEPT : 320 flags_( 0), 321 caller_(), 322 callee_( trampoline_void< symmetric_coroutine_impl< void > >, palloc) 323 { 324 if ( unwind) flags_ |= flag_force_unwind; 325 } 326 ~symmetric_coroutine_impl()327 virtual ~symmetric_coroutine_impl() {} 328 force_unwind() const329 inline bool force_unwind() const BOOST_NOEXCEPT 330 { return 0 != ( flags_ & flag_force_unwind); } 331 unwind_requested() const332 inline bool unwind_requested() const BOOST_NOEXCEPT 333 { return 0 != ( flags_ & flag_unwind_stack); } 334 is_started() const335 inline bool is_started() const BOOST_NOEXCEPT 336 { return 0 != ( flags_ & flag_started); } 337 is_running() const338 inline bool is_running() const BOOST_NOEXCEPT 339 { return 0 != ( flags_ & flag_running); } 340 is_complete() const341 inline bool is_complete() const BOOST_NOEXCEPT 342 { return 0 != ( flags_ & flag_complete); } 343 unwind_stack()344 inline void unwind_stack() BOOST_NOEXCEPT 345 { 346 if ( is_started() && ! is_complete() && force_unwind() ) 347 { 348 flags_ |= flag_unwind_stack; 349 flags_ |= flag_running; 350 param_type to( unwind_t::force_unwind); 351 caller_.jump( 352 callee_, 353 & to); 354 flags_ &= ~flag_running; 355 flags_ &= ~flag_unwind_stack; 356 357 BOOST_ASSERT( is_complete() ); 358 } 359 } 360 resume()361 inline void resume() BOOST_NOEXCEPT 362 { 363 BOOST_ASSERT( ! is_running() ); 364 BOOST_ASSERT( ! is_complete() ); 365 366 param_type to( this); 367 flags_ |= flag_running; 368 caller_.jump( 369 callee_, 370 & to); 371 flags_ &= ~flag_running; 372 } 373 yield()374 inline void yield() 375 { 376 BOOST_ASSERT( is_running() ); 377 BOOST_ASSERT( ! is_complete() ); 378 379 flags_ &= ~flag_running; 380 param_type to; 381 param_type * from( 382 static_cast< param_type * >( 383 callee_.jump( 384 caller_, 385 & to) ) ); 386 flags_ |= flag_running; 387 if ( from->do_unwind) throw forced_unwind(); 388 } 389 390 template< typename X > yield_to(symmetric_coroutine_impl<X> * other,X x)391 void yield_to( symmetric_coroutine_impl< X > * other, X x) 392 { 393 typename symmetric_coroutine_impl< X >::param_type to( & x, other); 394 yield_to_( other, & to); 395 } 396 397 template< typename X > yield_to(symmetric_coroutine_impl<X &> * other,X & x)398 void yield_to( symmetric_coroutine_impl< X & > * other, X & x) 399 { 400 typename symmetric_coroutine_impl< X & >::param_type to( & x, other); 401 yield_to_( other, & to); 402 } 403 404 template< typename X > yield_to(symmetric_coroutine_impl<X> * other)405 void yield_to( symmetric_coroutine_impl< X > * other) 406 { 407 typename symmetric_coroutine_impl< X >::param_type to( other); 408 yield_to_( other, & to); 409 } 410 411 virtual void run() BOOST_NOEXCEPT = 0; 412 413 virtual void destroy() = 0; 414 415 protected: 416 template< typename X > 417 friend class symmetric_coroutine_impl; 418 419 int flags_; 420 coroutine_context caller_; 421 coroutine_context callee_; 422 423 template< typename Other > yield_to_(Other * other,typename Other::param_type * to)424 void yield_to_( Other * other, typename Other::param_type * to) 425 { 426 BOOST_ASSERT( is_running() ); 427 BOOST_ASSERT( ! is_complete() ); 428 BOOST_ASSERT( ! other->is_running() ); 429 BOOST_ASSERT( ! other->is_complete() ); 430 431 other->caller_ = caller_; 432 flags_ &= ~flag_running; 433 param_type * from( 434 static_cast< param_type * >( 435 callee_.jump( 436 other->callee_, 437 to) ) ); 438 flags_ |= flag_running; 439 if ( from->do_unwind) throw forced_unwind(); 440 } 441 }; 442 443 }}} 444 445 #ifdef BOOST_HAS_ABI_HEADERS 446 # include BOOST_ABI_SUFFIX 447 #endif 448 449 #endif // BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_IMPL_H 450