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