Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:30:31

0001 
0002 //          Copyright Oliver Kowalke 2009.
0003 // Distributed under the Boost Software License, Version 1.0.
0004 //    (See accompanying file LICENSE_1_0.txt or copy at
0005 //          http://www.boost.org/LICENSE_1_0.txt)
0006 
0007 #ifndef BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_IMPL_H
0008 #define BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_IMPL_H
0009 
0010 #include <boost/assert.hpp>
0011 #include <boost/config.hpp>
0012 #include <boost/exception_ptr.hpp>
0013 #include <boost/throw_exception.hpp>
0014 #include <boost/utility.hpp>
0015 
0016 #include <boost/coroutine/detail/config.hpp>
0017 #include <boost/coroutine/detail/coroutine_context.hpp>
0018 #include <boost/coroutine/detail/flags.hpp>
0019 #include <boost/coroutine/detail/parameters.hpp>
0020 #include <boost/coroutine/detail/trampoline_push.hpp>
0021 #include <boost/coroutine/exceptions.hpp>
0022 
0023 #ifdef BOOST_HAS_ABI_HEADERS
0024 #  include BOOST_ABI_PREFIX
0025 #endif
0026 
0027 namespace boost {
0028 namespace coroutines {
0029 
0030 struct stack_context;
0031 
0032 namespace detail {
0033 
0034 template< typename Arg >
0035 class push_coroutine_impl : private noncopyable
0036 {
0037 protected:
0038     int                     flags_;
0039     exception_ptr           except_;
0040     coroutine_context   *   caller_;
0041     coroutine_context   *   callee_;
0042 
0043 public:
0044     typedef parameters< Arg >                           param_type;
0045 
0046     push_coroutine_impl( coroutine_context * caller,
0047                          coroutine_context * callee,
0048                          bool unwind) :
0049         flags_( 0),
0050         except_(),
0051         caller_( caller),
0052         callee_( callee)
0053     {
0054         if ( unwind) flags_ |= flag_force_unwind;
0055     }
0056 
0057     virtual ~push_coroutine_impl() {}
0058 
0059     bool force_unwind() const BOOST_NOEXCEPT
0060     { return 0 != ( flags_ & flag_force_unwind); }
0061 
0062     bool unwind_requested() const BOOST_NOEXCEPT
0063     { return 0 != ( flags_ & flag_unwind_stack); }
0064 
0065     bool is_started() const BOOST_NOEXCEPT
0066     { return 0 != ( flags_ & flag_started); }
0067 
0068     bool is_running() const BOOST_NOEXCEPT
0069     { return 0 != ( flags_ & flag_running); }
0070 
0071     bool is_complete() const BOOST_NOEXCEPT
0072     { return 0 != ( flags_ & flag_complete); }
0073 
0074     void unwind_stack() BOOST_NOEXCEPT
0075     {
0076         if ( is_started() && ! is_complete() && force_unwind() )
0077         {
0078             flags_ |= flag_unwind_stack;
0079             param_type to( unwind_t::force_unwind);
0080             caller_->jump(
0081                 * callee_,
0082                 & to);
0083             flags_ &= ~flag_unwind_stack;
0084 
0085             BOOST_ASSERT( is_complete() );
0086         }
0087     }
0088 
0089     void push( Arg const& arg)
0090     {
0091         BOOST_ASSERT( ! is_running() );
0092         BOOST_ASSERT( ! is_complete() );
0093 
0094         flags_ |= flag_running;
0095         param_type to( const_cast< Arg * >( & arg), this);
0096         param_type * from(
0097             static_cast< param_type * >(
0098                 caller_->jump(
0099                     * callee_,
0100                     & to) ) );
0101         flags_ &= ~flag_running;
0102         if ( from->do_unwind) throw forced_unwind();
0103         if ( except_) rethrow_exception( except_);
0104     }
0105 
0106     void push( BOOST_RV_REF( Arg) arg)
0107     {
0108         BOOST_ASSERT( ! is_running() );
0109         BOOST_ASSERT( ! is_complete() );
0110 
0111         flags_ |= flag_running;
0112         param_type to( const_cast< Arg * >( & arg), this);
0113         param_type * from(
0114             static_cast< param_type * >(
0115                 caller_->jump(
0116                     * callee_,
0117                     & to) ) );
0118         flags_ &= ~flag_running;
0119         if ( from->do_unwind) throw forced_unwind();
0120         if ( except_) rethrow_exception( except_);
0121     }
0122 
0123     virtual void destroy() = 0;
0124 };
0125 
0126 template< typename Arg >
0127 class push_coroutine_impl< Arg & > : private noncopyable
0128 {
0129 protected:
0130     int                     flags_;
0131     exception_ptr           except_;
0132     coroutine_context   *   caller_;
0133     coroutine_context   *   callee_;
0134 
0135 public:
0136     typedef parameters< Arg & >                         param_type;
0137 
0138     push_coroutine_impl( coroutine_context * caller,
0139                          coroutine_context * callee,
0140                          bool unwind) :
0141         flags_( 0),
0142         except_(),
0143         caller_( caller),
0144         callee_( callee)
0145     {
0146         if ( unwind) flags_ |= flag_force_unwind;
0147     }
0148 
0149     virtual ~push_coroutine_impl() {}
0150 
0151     bool force_unwind() const BOOST_NOEXCEPT
0152     { return 0 != ( flags_ & flag_force_unwind); }
0153 
0154     bool unwind_requested() const BOOST_NOEXCEPT
0155     { return 0 != ( flags_ & flag_unwind_stack); }
0156 
0157     bool is_started() const BOOST_NOEXCEPT
0158     { return 0 != ( flags_ & flag_started); }
0159 
0160     bool is_running() const BOOST_NOEXCEPT
0161     { return 0 != ( flags_ & flag_running); }
0162 
0163     bool is_complete() const BOOST_NOEXCEPT
0164     { return 0 != ( flags_ & flag_complete); }
0165 
0166     void unwind_stack() BOOST_NOEXCEPT
0167     {
0168         if ( is_started() && ! is_complete() && force_unwind() )
0169         {
0170             flags_ |= flag_unwind_stack;
0171             param_type to( unwind_t::force_unwind);
0172             caller_->jump(
0173                 * callee_,
0174                 & to);
0175             flags_ &= ~flag_unwind_stack;
0176 
0177             BOOST_ASSERT( is_complete() );
0178         }
0179     }
0180 
0181     void push( Arg & arg)
0182     {
0183         BOOST_ASSERT( ! is_running() );
0184         BOOST_ASSERT( ! is_complete() );
0185 
0186         flags_ |= flag_running;
0187         param_type to( & arg, this);
0188         param_type * from(
0189             static_cast< param_type * >(
0190                 caller_->jump(
0191                     * callee_,
0192                     & to) ) );
0193         flags_ &= ~flag_running;
0194         if ( from->do_unwind) throw forced_unwind();
0195         if ( except_) rethrow_exception( except_);
0196     }
0197 
0198     virtual void destroy() = 0;
0199 };
0200 
0201 template<>
0202 class push_coroutine_impl< void > : private noncopyable
0203 {
0204 protected:
0205     int                     flags_;
0206     exception_ptr           except_;
0207     coroutine_context   *   caller_;
0208     coroutine_context   *   callee_;
0209 
0210 public:
0211     typedef parameters< void >                          param_type;
0212 
0213     push_coroutine_impl( coroutine_context * caller,
0214                          coroutine_context * callee,
0215                          bool unwind) :
0216         flags_( 0),
0217         except_(),
0218         caller_( caller),
0219         callee_( callee)
0220     {
0221         if ( unwind) flags_ |= flag_force_unwind;
0222     }
0223 
0224     virtual ~push_coroutine_impl() {}
0225 
0226     inline bool force_unwind() const BOOST_NOEXCEPT
0227     { return 0 != ( flags_ & flag_force_unwind); }
0228 
0229     inline bool unwind_requested() const BOOST_NOEXCEPT
0230     { return 0 != ( flags_ & flag_unwind_stack); }
0231 
0232     inline bool is_started() const BOOST_NOEXCEPT
0233     { return 0 != ( flags_ & flag_started); }
0234 
0235     inline bool is_running() const BOOST_NOEXCEPT
0236     { return 0 != ( flags_ & flag_running); }
0237 
0238     inline bool is_complete() const BOOST_NOEXCEPT
0239     { return 0 != ( flags_ & flag_complete); }
0240 
0241     inline void unwind_stack() BOOST_NOEXCEPT
0242     {
0243         if ( is_started() && ! is_complete() && force_unwind() )
0244         {
0245             flags_ |= flag_unwind_stack;
0246             param_type to( unwind_t::force_unwind);
0247             caller_->jump(
0248                 * callee_,
0249                 & to);
0250             flags_ &= ~flag_unwind_stack;
0251 
0252             BOOST_ASSERT( is_complete() );
0253         }
0254     }
0255 
0256     inline void push()
0257     {
0258         BOOST_ASSERT( ! is_running() );
0259         BOOST_ASSERT( ! is_complete() );
0260 
0261         flags_ |= flag_running;
0262         param_type to( this);
0263         param_type * from(
0264             static_cast< param_type * >(
0265                 caller_->jump(
0266                     * callee_,
0267                     & to) ) );
0268         flags_ &= ~flag_running;
0269         if ( from->do_unwind) throw forced_unwind();
0270         if ( except_) rethrow_exception( except_);
0271     }
0272 
0273     virtual void destroy() = 0;
0274 };
0275 
0276 }}}
0277 
0278 #ifdef BOOST_HAS_ABI_HEADERS
0279 #  include BOOST_ABI_SUFFIX
0280 #endif
0281 
0282 #endif // BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_IMPL_H