// Copyright Oliver Kowalke 2009. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_IMPL_H #define BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_IMPL_H #include #include #include #include #include #include #include #include #include #include #include #include #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_PREFIX #endif namespace boost { namespace coroutines { namespace detail { template< typename R > class symmetric_coroutine_impl : private noncopyable { public: typedef parameters< R > param_type; symmetric_coroutine_impl( preallocated const& palloc, bool unwind) BOOST_NOEXCEPT : flags_( 0), caller_(), callee_( trampoline< symmetric_coroutine_impl< R > >, palloc) { if ( unwind) flags_ |= flag_force_unwind; } virtual ~symmetric_coroutine_impl() {} bool force_unwind() const BOOST_NOEXCEPT { return 0 != ( flags_ & flag_force_unwind); } bool unwind_requested() const BOOST_NOEXCEPT { return 0 != ( flags_ & flag_unwind_stack); } bool is_started() const BOOST_NOEXCEPT { return 0 != ( flags_ & flag_started); } bool is_running() const BOOST_NOEXCEPT { return 0 != ( flags_ & flag_running); } bool is_complete() const BOOST_NOEXCEPT { return 0 != ( flags_ & flag_complete); } void unwind_stack() BOOST_NOEXCEPT { if ( is_started() && ! is_complete() && force_unwind() ) { flags_ |= flag_unwind_stack; flags_ |= flag_running; param_type to( unwind_t::force_unwind); caller_.jump( callee_, & to); flags_ &= ~flag_running; flags_ &= ~flag_unwind_stack; BOOST_ASSERT( is_complete() ); } } void resume( R r) BOOST_NOEXCEPT { param_type to( const_cast< R * >( & r), this); resume_( & to); } R * yield() { BOOST_ASSERT( is_running() ); BOOST_ASSERT( ! is_complete() ); flags_ &= ~flag_running; param_type to; param_type * from( static_cast< param_type * >( callee_.jump( caller_, & to) ) ); flags_ |= flag_running; if ( from->do_unwind) throw forced_unwind(); BOOST_ASSERT( from->data); return from->data; } template< typename X > R * yield_to( symmetric_coroutine_impl< X > * other, X x) { typename symmetric_coroutine_impl< X >::param_type to( & x, other); return yield_to_( other, & to); } template< typename X > R * yield_to( symmetric_coroutine_impl< X & > * other, X & x) { typename symmetric_coroutine_impl< X & >::param_type to( & x, other); return yield_to_( other, & to); } template< typename X > R * yield_to( symmetric_coroutine_impl< X > * other) { typename symmetric_coroutine_impl< X >::param_type to( other); return yield_to_( other, & to); } virtual void run( R *) BOOST_NOEXCEPT = 0; virtual void destroy() = 0; protected: template< typename X > friend class symmetric_coroutine_impl; int flags_; coroutine_context caller_; coroutine_context callee_; void resume_( param_type * to) BOOST_NOEXCEPT { BOOST_ASSERT( ! is_running() ); BOOST_ASSERT( ! is_complete() ); flags_ |= flag_running; caller_.jump( callee_, to); flags_ &= ~flag_running; } template< typename Other > R * yield_to_( Other * other, typename Other::param_type * to) { BOOST_ASSERT( is_running() ); BOOST_ASSERT( ! is_complete() ); BOOST_ASSERT( ! other->is_running() ); BOOST_ASSERT( ! other->is_complete() ); other->caller_ = caller_; flags_ &= ~flag_running; param_type * from( static_cast< param_type * >( callee_.jump( other->callee_, to) ) ); flags_ |= flag_running; if ( from->do_unwind) throw forced_unwind(); BOOST_ASSERT( from->data); return from->data; } }; template< typename R > class symmetric_coroutine_impl< R & > : private noncopyable { public: typedef parameters< R & > param_type; symmetric_coroutine_impl( preallocated const& palloc, bool unwind) BOOST_NOEXCEPT : flags_( 0), caller_(), callee_( trampoline< symmetric_coroutine_impl< R > >, palloc) { if ( unwind) flags_ |= flag_force_unwind; } virtual ~symmetric_coroutine_impl() {} bool force_unwind() const BOOST_NOEXCEPT { return 0 != ( flags_ & flag_force_unwind); } bool unwind_requested() const BOOST_NOEXCEPT { return 0 != ( flags_ & flag_unwind_stack); } bool is_started() const BOOST_NOEXCEPT { return 0 != ( flags_ & flag_started); } bool is_running() const BOOST_NOEXCEPT { return 0 != ( flags_ & flag_running); } bool is_complete() const BOOST_NOEXCEPT { return 0 != ( flags_ & flag_complete); } void unwind_stack() BOOST_NOEXCEPT { if ( is_started() && ! is_complete() && force_unwind() ) { flags_ |= flag_unwind_stack; flags_ |= flag_running; param_type to( unwind_t::force_unwind); caller_.jump( callee_, & to); flags_ &= ~flag_running; flags_ &= ~flag_unwind_stack; BOOST_ASSERT( is_complete() ); } } void resume( R & arg) BOOST_NOEXCEPT { param_type to( & arg, this); resume_( & to); } R * yield() { BOOST_ASSERT( is_running() ); BOOST_ASSERT( ! is_complete() ); flags_ &= ~flag_running; param_type to; param_type * from( static_cast< param_type * >( callee_.jump( caller_, & to) ) ); flags_ |= flag_running; if ( from->do_unwind) throw forced_unwind(); BOOST_ASSERT( from->data); return from->data; } template< typename X > R * yield_to( symmetric_coroutine_impl< X > * other, X x) { typename symmetric_coroutine_impl< X >::param_type to( & x, other); return yield_to_( other, & to); } template< typename X > R * yield_to( symmetric_coroutine_impl< X & > * other, X & x) { typename symmetric_coroutine_impl< X & >::param_type to( & x, other); return yield_to_( other, & to); } template< typename X > R * yield_to( symmetric_coroutine_impl< X > * other) { typename symmetric_coroutine_impl< X >::param_type to( other); return yield_to_( other, & to); } virtual void run( R *) BOOST_NOEXCEPT = 0; virtual void destroy() = 0; protected: template< typename X > friend class symmetric_coroutine_impl; int flags_; coroutine_context caller_; coroutine_context callee_; void resume_( param_type * to) BOOST_NOEXCEPT { BOOST_ASSERT( ! is_running() ); BOOST_ASSERT( ! is_complete() ); flags_ |= flag_running; caller_.jump( callee_, to); flags_ &= ~flag_running; } template< typename Other > R * yield_to_( Other * other, typename Other::param_type * to) { BOOST_ASSERT( is_running() ); BOOST_ASSERT( ! is_complete() ); BOOST_ASSERT( ! other->is_running() ); BOOST_ASSERT( ! other->is_complete() ); other->caller_ = caller_; flags_ &= ~flag_running; param_type * from( static_cast< param_type * >( callee_.jump( other->callee_, to) ) ); flags_ |= flag_running; if ( from->do_unwind) throw forced_unwind(); BOOST_ASSERT( from->data); return from->data; } }; template<> class symmetric_coroutine_impl< void > : private noncopyable { public: typedef parameters< void > param_type; symmetric_coroutine_impl( preallocated const& palloc, bool unwind) BOOST_NOEXCEPT : flags_( 0), caller_(), callee_( trampoline_void< symmetric_coroutine_impl< void > >, palloc) { if ( unwind) flags_ |= flag_force_unwind; } virtual ~symmetric_coroutine_impl() {} inline bool force_unwind() const BOOST_NOEXCEPT { return 0 != ( flags_ & flag_force_unwind); } inline bool unwind_requested() const BOOST_NOEXCEPT { return 0 != ( flags_ & flag_unwind_stack); } inline bool is_started() const BOOST_NOEXCEPT { return 0 != ( flags_ & flag_started); } inline bool is_running() const BOOST_NOEXCEPT { return 0 != ( flags_ & flag_running); } inline bool is_complete() const BOOST_NOEXCEPT { return 0 != ( flags_ & flag_complete); } inline void unwind_stack() BOOST_NOEXCEPT { if ( is_started() && ! is_complete() && force_unwind() ) { flags_ |= flag_unwind_stack; flags_ |= flag_running; param_type to( unwind_t::force_unwind); caller_.jump( callee_, & to); flags_ &= ~flag_running; flags_ &= ~flag_unwind_stack; BOOST_ASSERT( is_complete() ); } } inline void resume() BOOST_NOEXCEPT { BOOST_ASSERT( ! is_running() ); BOOST_ASSERT( ! is_complete() ); param_type to( this); flags_ |= flag_running; caller_.jump( callee_, & to); flags_ &= ~flag_running; } inline void yield() { BOOST_ASSERT( is_running() ); BOOST_ASSERT( ! is_complete() ); flags_ &= ~flag_running; param_type to; param_type * from( static_cast< param_type * >( callee_.jump( caller_, & to) ) ); flags_ |= flag_running; if ( from->do_unwind) throw forced_unwind(); } template< typename X > void yield_to( symmetric_coroutine_impl< X > * other, X x) { typename symmetric_coroutine_impl< X >::param_type to( & x, other); yield_to_( other, & to); } template< typename X > void yield_to( symmetric_coroutine_impl< X & > * other, X & x) { typename symmetric_coroutine_impl< X & >::param_type to( & x, other); yield_to_( other, & to); } template< typename X > void yield_to( symmetric_coroutine_impl< X > * other) { typename symmetric_coroutine_impl< X >::param_type to( other); yield_to_( other, & to); } virtual void run() BOOST_NOEXCEPT = 0; virtual void destroy() = 0; protected: template< typename X > friend class symmetric_coroutine_impl; int flags_; coroutine_context caller_; coroutine_context callee_; template< typename Other > void yield_to_( Other * other, typename Other::param_type * to) { BOOST_ASSERT( is_running() ); BOOST_ASSERT( ! is_complete() ); BOOST_ASSERT( ! other->is_running() ); BOOST_ASSERT( ! other->is_complete() ); other->caller_ = caller_; flags_ &= ~flag_running; param_type * from( static_cast< param_type * >( callee_.jump( other->callee_, to) ) ); flags_ |= flag_running; if ( from->do_unwind) throw forced_unwind(); } }; }}} #ifdef BOOST_HAS_ABI_HEADERS # include BOOST_ABI_SUFFIX #endif #endif // BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_IMPL_H