File indexing completed on 2025-01-18 09:30:31
0001
0002
0003
0004
0005
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