Back to home page

EIC code displayed by LXR

 
 

    


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

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_SYMMETRIC_COROUTINE_IMPL_H
0008 #define BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_IMPL_H
0009 
0010 #include <boost/assert.hpp>
0011 #include <boost/config.hpp>
0012 #include <boost/cstdint.hpp>
0013 #include <boost/utility.hpp>
0014 
0015 #include <boost/coroutine/detail/config.hpp>
0016 #include <boost/coroutine/detail/coroutine_context.hpp>
0017 #include <boost/coroutine/detail/flags.hpp>
0018 #include <boost/coroutine/detail/parameters.hpp>
0019 #include <boost/coroutine/detail/preallocated.hpp>
0020 #include <boost/coroutine/detail/trampoline.hpp>
0021 #include <boost/coroutine/exceptions.hpp>
0022 #include <boost/coroutine/stack_context.hpp>
0023 
0024 #ifdef BOOST_HAS_ABI_HEADERS
0025 #  include BOOST_ABI_PREFIX
0026 #endif
0027 
0028 namespace boost {
0029 namespace coroutines {
0030 namespace detail {
0031 
0032 template< typename R >
0033 class symmetric_coroutine_impl : private noncopyable
0034 {
0035 public:
0036     typedef parameters< R >                           param_type;
0037 
0038     symmetric_coroutine_impl( preallocated const& palloc,
0039                               bool unwind) BOOST_NOEXCEPT :
0040         flags_( 0),
0041         caller_(),
0042         callee_( trampoline< symmetric_coroutine_impl< R > >, palloc)
0043     {
0044         if ( unwind) flags_ |= flag_force_unwind;
0045     }
0046 
0047     virtual ~symmetric_coroutine_impl() {}
0048 
0049     bool force_unwind() const BOOST_NOEXCEPT
0050     { return 0 != ( flags_ & flag_force_unwind); }
0051 
0052     bool unwind_requested() const BOOST_NOEXCEPT
0053     { return 0 != ( flags_ & flag_unwind_stack); }
0054 
0055     bool is_started() const BOOST_NOEXCEPT
0056     { return 0 != ( flags_ & flag_started); }
0057 
0058     bool is_running() const BOOST_NOEXCEPT
0059     { return 0 != ( flags_ & flag_running); }
0060 
0061     bool is_complete() const BOOST_NOEXCEPT
0062     { return 0 != ( flags_ & flag_complete); }
0063 
0064     void unwind_stack() BOOST_NOEXCEPT
0065     {
0066         if ( is_started() && ! is_complete() && force_unwind() )
0067         {
0068             flags_ |= flag_unwind_stack;
0069             flags_ |= flag_running;
0070             param_type to( unwind_t::force_unwind);
0071             caller_.jump(
0072                 callee_,
0073                 & to);
0074             flags_ &= ~flag_running;
0075             flags_ &= ~flag_unwind_stack;
0076 
0077             BOOST_ASSERT( is_complete() );
0078         }
0079     }
0080 
0081     void resume( R r) BOOST_NOEXCEPT
0082     {
0083         param_type to( const_cast< R * >( & r), this);
0084         resume_( & to);
0085     }
0086 
0087     R * yield()
0088     {
0089         BOOST_ASSERT( is_running() );
0090         BOOST_ASSERT( ! is_complete() );
0091 
0092         flags_ &= ~flag_running;
0093         param_type to;
0094         param_type * from(
0095             static_cast< param_type * >(
0096                 callee_.jump(
0097                     caller_,
0098                     & to) ) );
0099         flags_ |= flag_running;
0100         if ( from->do_unwind) throw forced_unwind();
0101         BOOST_ASSERT( from->data);
0102         return from->data;
0103     }
0104 
0105     template< typename X >
0106     R * yield_to( symmetric_coroutine_impl< X > * other, X x)
0107     {
0108         typename symmetric_coroutine_impl< X >::param_type to( & x, other);
0109         return yield_to_( other, & to);
0110     }
0111 
0112     template< typename X >
0113     R * yield_to( symmetric_coroutine_impl< X & > * other, X & x)
0114     {
0115         typename symmetric_coroutine_impl< X & >::param_type to( & x, other);
0116         return yield_to_( other, & to);
0117     }
0118 
0119     template< typename X >
0120     R * yield_to( symmetric_coroutine_impl< X > * other)
0121     {
0122         typename symmetric_coroutine_impl< X >::param_type to( other);
0123         return yield_to_( other, & to);
0124     }
0125 
0126     virtual void run( R *) BOOST_NOEXCEPT = 0;
0127 
0128     virtual void destroy() = 0;
0129 
0130 protected:
0131     template< typename X >
0132     friend class symmetric_coroutine_impl;
0133 
0134     int                 flags_;
0135     coroutine_context   caller_;
0136     coroutine_context   callee_;
0137 
0138     void resume_( param_type * to) BOOST_NOEXCEPT
0139     {
0140         BOOST_ASSERT( ! is_running() );
0141         BOOST_ASSERT( ! is_complete() );
0142 
0143         flags_ |= flag_running;
0144         caller_.jump(
0145             callee_,
0146             to);
0147         flags_ &= ~flag_running;
0148     }
0149 
0150     template< typename Other >
0151     R * yield_to_( Other * other, typename Other::param_type * to)
0152     {
0153         BOOST_ASSERT( is_running() );
0154         BOOST_ASSERT( ! is_complete() );
0155         BOOST_ASSERT( ! other->is_running() );
0156         BOOST_ASSERT( ! other->is_complete() );
0157 
0158         other->caller_ = caller_;
0159         flags_ &= ~flag_running;
0160         param_type * from(
0161             static_cast< param_type * >(
0162                 callee_.jump(
0163                     other->callee_,
0164                     to) ) );
0165         flags_ |= flag_running;
0166         if ( from->do_unwind) throw forced_unwind();
0167         BOOST_ASSERT( from->data);
0168         return from->data;
0169     }
0170 };
0171 
0172 template< typename R >
0173 class symmetric_coroutine_impl< R & > : private noncopyable
0174 {
0175 public:
0176     typedef parameters< R & >                         param_type;
0177 
0178     symmetric_coroutine_impl( preallocated const& palloc,
0179                               bool unwind) BOOST_NOEXCEPT :
0180         flags_( 0),
0181         caller_(),
0182         callee_( trampoline< symmetric_coroutine_impl< R > >, palloc)
0183     {
0184         if ( unwind) flags_ |= flag_force_unwind;
0185     }
0186 
0187     virtual ~symmetric_coroutine_impl() {}
0188 
0189     bool force_unwind() const BOOST_NOEXCEPT
0190     { return 0 != ( flags_ & flag_force_unwind); }
0191 
0192     bool unwind_requested() const BOOST_NOEXCEPT
0193     { return 0 != ( flags_ & flag_unwind_stack); }
0194 
0195     bool is_started() const BOOST_NOEXCEPT
0196     { return 0 != ( flags_ & flag_started); }
0197 
0198     bool is_running() const BOOST_NOEXCEPT
0199     { return 0 != ( flags_ & flag_running); }
0200 
0201     bool is_complete() const BOOST_NOEXCEPT
0202     { return 0 != ( flags_ & flag_complete); }
0203 
0204     void unwind_stack() BOOST_NOEXCEPT
0205     {
0206         if ( is_started() && ! is_complete() && force_unwind() )
0207         {
0208             flags_ |= flag_unwind_stack;
0209             flags_ |= flag_running;
0210             param_type to( unwind_t::force_unwind);
0211             caller_.jump(
0212                 callee_,
0213                 & to);
0214             flags_ &= ~flag_running;
0215             flags_ &= ~flag_unwind_stack;
0216 
0217             BOOST_ASSERT( is_complete() );
0218         }
0219     }
0220 
0221     void resume( R & arg) BOOST_NOEXCEPT
0222     {
0223         param_type to( & arg, this);
0224         resume_( & to);
0225     }
0226 
0227     R * yield()
0228     {
0229         BOOST_ASSERT( is_running() );
0230         BOOST_ASSERT( ! is_complete() );
0231 
0232         flags_ &= ~flag_running;
0233         param_type to;
0234         param_type * from(
0235             static_cast< param_type * >(
0236                 callee_.jump(
0237                     caller_,
0238                     & to) ) );
0239         flags_ |= flag_running;
0240         if ( from->do_unwind) throw forced_unwind();
0241         BOOST_ASSERT( from->data);
0242         return from->data;
0243     }
0244 
0245     template< typename X >
0246     R * yield_to( symmetric_coroutine_impl< X > * other, X x)
0247     {
0248         typename symmetric_coroutine_impl< X >::param_type to( & x, other);
0249         return yield_to_( other, & to);
0250     }
0251 
0252     template< typename X >
0253     R * yield_to( symmetric_coroutine_impl< X & > * other, X & x)
0254     {
0255         typename symmetric_coroutine_impl< X & >::param_type to( & x, other);
0256         return yield_to_( other, & to);
0257     }
0258 
0259     template< typename X >
0260     R * yield_to( symmetric_coroutine_impl< X > * other)
0261     {
0262         typename symmetric_coroutine_impl< X >::param_type to( other);
0263         return yield_to_( other, & to);
0264     }
0265 
0266     virtual void run( R *) BOOST_NOEXCEPT = 0;
0267 
0268     virtual void destroy() = 0;
0269 
0270 protected:
0271     template< typename X >
0272     friend class symmetric_coroutine_impl;
0273 
0274     int                 flags_;
0275     coroutine_context   caller_;
0276     coroutine_context   callee_;
0277 
0278     void resume_( param_type * to) BOOST_NOEXCEPT
0279     {
0280         BOOST_ASSERT( ! is_running() );
0281         BOOST_ASSERT( ! is_complete() );
0282 
0283         flags_ |= flag_running;
0284         caller_.jump(
0285             callee_,
0286             to);
0287         flags_ &= ~flag_running;
0288     }
0289 
0290     template< typename Other >
0291     R * yield_to_( Other * other, typename Other::param_type * to)
0292     {
0293         BOOST_ASSERT( is_running() );
0294         BOOST_ASSERT( ! is_complete() );
0295         BOOST_ASSERT( ! other->is_running() );
0296         BOOST_ASSERT( ! other->is_complete() );
0297 
0298         other->caller_ = caller_;
0299         flags_ &= ~flag_running;
0300         param_type * from(
0301             static_cast< param_type * >(
0302                 callee_.jump(
0303                     other->callee_,
0304                     to) ) );
0305         flags_ |= flag_running;
0306         if ( from->do_unwind) throw forced_unwind();
0307         BOOST_ASSERT( from->data);
0308         return from->data;
0309     }
0310 };
0311 
0312 template<>
0313 class symmetric_coroutine_impl< void > : private noncopyable
0314 {
0315 public:
0316     typedef parameters< void >                          param_type;
0317 
0318     symmetric_coroutine_impl( preallocated const& palloc,
0319                               bool unwind) BOOST_NOEXCEPT :
0320         flags_( 0),
0321         caller_(),
0322         callee_( trampoline_void< symmetric_coroutine_impl< void > >, palloc)
0323     {
0324         if ( unwind) flags_ |= flag_force_unwind;
0325     }
0326 
0327     virtual ~symmetric_coroutine_impl() {}
0328 
0329     inline bool force_unwind() const BOOST_NOEXCEPT
0330     { return 0 != ( flags_ & flag_force_unwind); }
0331 
0332     inline bool unwind_requested() const BOOST_NOEXCEPT
0333     { return 0 != ( flags_ & flag_unwind_stack); }
0334 
0335     inline bool is_started() const BOOST_NOEXCEPT
0336     { return 0 != ( flags_ & flag_started); }
0337 
0338     inline bool is_running() const BOOST_NOEXCEPT
0339     { return 0 != ( flags_ & flag_running); }
0340 
0341     inline bool is_complete() const BOOST_NOEXCEPT
0342     { return 0 != ( flags_ & flag_complete); }
0343 
0344     inline void unwind_stack() BOOST_NOEXCEPT
0345     {
0346         if ( is_started() && ! is_complete() && force_unwind() )
0347         {
0348             flags_ |= flag_unwind_stack;
0349             flags_ |= flag_running;
0350             param_type to( unwind_t::force_unwind);
0351             caller_.jump(
0352                 callee_,
0353                 & to);
0354             flags_ &= ~flag_running;
0355             flags_ &= ~flag_unwind_stack;
0356 
0357             BOOST_ASSERT( is_complete() );
0358         }
0359     }
0360 
0361     inline void resume() BOOST_NOEXCEPT
0362     {
0363         BOOST_ASSERT( ! is_running() );
0364         BOOST_ASSERT( ! is_complete() );
0365 
0366         param_type to( this);
0367         flags_ |= flag_running;
0368         caller_.jump(
0369             callee_,
0370             & to);
0371         flags_ &= ~flag_running;
0372     }
0373 
0374     inline void yield()
0375     {
0376         BOOST_ASSERT( is_running() );
0377         BOOST_ASSERT( ! is_complete() );
0378 
0379         flags_ &= ~flag_running;
0380         param_type to;
0381         param_type * from(
0382             static_cast< param_type * >(
0383                 callee_.jump(
0384                      caller_,
0385                     & to) ) );
0386         flags_ |= flag_running;
0387         if ( from->do_unwind) throw forced_unwind();
0388     }
0389 
0390     template< typename X >
0391     void yield_to( symmetric_coroutine_impl< X > * other, X x)
0392     {
0393         typename symmetric_coroutine_impl< X >::param_type to( & x, other);
0394         yield_to_( other, & to);
0395     }
0396 
0397     template< typename X >
0398     void yield_to( symmetric_coroutine_impl< X & > * other, X & x)
0399     {
0400         typename symmetric_coroutine_impl< X & >::param_type to( & x, other);
0401         yield_to_( other, & to);
0402     }
0403 
0404     template< typename X >
0405     void yield_to( symmetric_coroutine_impl< X > * other)
0406     {
0407         typename symmetric_coroutine_impl< X >::param_type to( other);
0408         yield_to_( other, & to);
0409     }
0410 
0411     virtual void run() BOOST_NOEXCEPT = 0;
0412 
0413     virtual void destroy() = 0;
0414 
0415 protected:
0416     template< typename X >
0417     friend class symmetric_coroutine_impl;
0418 
0419     int                 flags_;
0420     coroutine_context   caller_;
0421     coroutine_context   callee_;
0422 
0423     template< typename Other >
0424     void yield_to_( Other * other, typename Other::param_type * to)
0425     {
0426         BOOST_ASSERT( is_running() );
0427         BOOST_ASSERT( ! is_complete() );
0428         BOOST_ASSERT( ! other->is_running() );
0429         BOOST_ASSERT( ! other->is_complete() );
0430 
0431         other->caller_ = caller_;
0432         flags_ &= ~flag_running;
0433         param_type * from(
0434             static_cast< param_type * >(
0435                 callee_.jump(
0436                     other->callee_,
0437                     to) ) );
0438         flags_ |= flag_running;
0439         if ( from->do_unwind) throw forced_unwind();
0440     }
0441 };
0442 
0443 }}}
0444 
0445 #ifdef BOOST_HAS_ABI_HEADERS
0446 #  include BOOST_ABI_SUFFIX
0447 #endif
0448 
0449 #endif // BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_IMPL_H