File indexing completed on 2025-01-18 09:30:31
0001
0002
0003
0004
0005
0006
0007 #ifndef BOOST_COROUTINES_DETAIL_PULL_COROUTINE_IMPL_H
0008 #define BOOST_COROUTINES_DETAIL_PULL_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_pull.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 R >
0035 class pull_coroutine_impl : private noncopyable
0036 {
0037 protected:
0038 int flags_;
0039 exception_ptr except_;
0040 coroutine_context * caller_;
0041 coroutine_context * callee_;
0042 R * result_;
0043
0044 public:
0045 typedef parameters< R > param_type;
0046
0047 pull_coroutine_impl( coroutine_context * caller,
0048 coroutine_context * callee,
0049 bool unwind) :
0050 flags_( 0),
0051 except_(),
0052 caller_( caller),
0053 callee_( callee),
0054 result_( 0)
0055 {
0056 if ( unwind) flags_ |= flag_force_unwind;
0057 }
0058
0059 pull_coroutine_impl( coroutine_context * caller,
0060 coroutine_context * callee,
0061 bool unwind,
0062 R * result) :
0063 flags_( 0),
0064 except_(),
0065 caller_( caller),
0066 callee_( callee),
0067 result_( result)
0068 {
0069 if ( unwind) flags_ |= flag_force_unwind;
0070 }
0071
0072 virtual ~pull_coroutine_impl() {}
0073
0074 bool force_unwind() const BOOST_NOEXCEPT
0075 { return 0 != ( flags_ & flag_force_unwind); }
0076
0077 bool unwind_requested() const BOOST_NOEXCEPT
0078 { return 0 != ( flags_ & flag_unwind_stack); }
0079
0080 bool is_started() const BOOST_NOEXCEPT
0081 { return 0 != ( flags_ & flag_started); }
0082
0083 bool is_running() const BOOST_NOEXCEPT
0084 { return 0 != ( flags_ & flag_running); }
0085
0086 bool is_complete() const BOOST_NOEXCEPT
0087 { return 0 != ( flags_ & flag_complete); }
0088
0089 void unwind_stack() BOOST_NOEXCEPT
0090 {
0091 if ( is_started() && ! is_complete() && force_unwind() )
0092 {
0093 flags_ |= flag_unwind_stack;
0094 param_type to( unwind_t::force_unwind);
0095 caller_->jump(
0096 * callee_,
0097 & to);
0098 flags_ &= ~flag_unwind_stack;
0099
0100 BOOST_ASSERT( is_complete() );
0101 }
0102 }
0103
0104 void pull()
0105 {
0106 BOOST_ASSERT( ! is_running() );
0107 BOOST_ASSERT( ! is_complete() );
0108
0109 flags_ |= flag_running;
0110 param_type to( this);
0111 param_type * from(
0112 static_cast< param_type * >(
0113 caller_->jump(
0114 * callee_,
0115 & to) ) );
0116 flags_ &= ~flag_running;
0117 result_ = from->data;
0118 if ( from->do_unwind) throw forced_unwind();
0119 if ( except_) rethrow_exception( except_);
0120 }
0121
0122 bool has_result() const
0123 { return 0 != result_; }
0124
0125 R get() const
0126 {
0127 if ( ! has_result() )
0128 boost::throw_exception(
0129 invalid_result() );
0130 return * result_;
0131 }
0132
0133 R * get_pointer() const
0134 {
0135 if ( ! has_result() )
0136 boost::throw_exception(
0137 invalid_result() );
0138 return result_;
0139 }
0140
0141 virtual void destroy() = 0;
0142 };
0143
0144 template< typename R >
0145 class pull_coroutine_impl< R & > : private noncopyable
0146 {
0147 protected:
0148 int flags_;
0149 exception_ptr except_;
0150 coroutine_context * caller_;
0151 coroutine_context * callee_;
0152 R * result_;
0153
0154 public:
0155 typedef parameters< R & > param_type;
0156
0157 pull_coroutine_impl( coroutine_context * caller,
0158 coroutine_context * callee,
0159 bool unwind) :
0160 flags_( 0),
0161 except_(),
0162 caller_( caller),
0163 callee_( callee),
0164 result_( 0)
0165 {
0166 if ( unwind) flags_ |= flag_force_unwind;
0167 }
0168
0169 pull_coroutine_impl( coroutine_context * caller,
0170 coroutine_context * callee,
0171 bool unwind,
0172 R * result) :
0173 flags_( 0),
0174 except_(),
0175 caller_( caller),
0176 callee_( callee),
0177 result_( result)
0178 {
0179 if ( unwind) flags_ |= flag_force_unwind;
0180 }
0181
0182 virtual ~pull_coroutine_impl() {}
0183
0184 bool force_unwind() const BOOST_NOEXCEPT
0185 { return 0 != ( flags_ & flag_force_unwind); }
0186
0187 bool unwind_requested() const BOOST_NOEXCEPT
0188 { return 0 != ( flags_ & flag_unwind_stack); }
0189
0190 bool is_started() const BOOST_NOEXCEPT
0191 { return 0 != ( flags_ & flag_started); }
0192
0193 bool is_running() const BOOST_NOEXCEPT
0194 { return 0 != ( flags_ & flag_running); }
0195
0196 bool is_complete() const BOOST_NOEXCEPT
0197 { return 0 != ( flags_ & flag_complete); }
0198
0199 void unwind_stack() BOOST_NOEXCEPT
0200 {
0201 if ( is_started() && ! is_complete() && force_unwind() )
0202 {
0203 flags_ |= flag_unwind_stack;
0204 param_type to( unwind_t::force_unwind);
0205 caller_->jump(
0206 * callee_,
0207 & to);
0208 flags_ &= ~flag_unwind_stack;
0209
0210 BOOST_ASSERT( is_complete() );
0211 }
0212 }
0213
0214 void pull()
0215 {
0216 BOOST_ASSERT( ! is_running() );
0217 BOOST_ASSERT( ! is_complete() );
0218
0219 flags_ |= flag_running;
0220 param_type to( this);
0221 param_type * from(
0222 static_cast< param_type * >(
0223 caller_->jump(
0224 * callee_,
0225 & to) ) );
0226 flags_ &= ~flag_running;
0227 result_ = from->data;
0228 if ( from->do_unwind) throw forced_unwind();
0229 if ( except_) rethrow_exception( except_);
0230 }
0231
0232 bool has_result() const
0233 { return 0 != result_; }
0234
0235 R & get() const
0236 {
0237 if ( ! has_result() )
0238 boost::throw_exception(
0239 invalid_result() );
0240 return * result_;
0241 }
0242
0243 R * get_pointer() const
0244 {
0245 if ( ! has_result() )
0246 boost::throw_exception(
0247 invalid_result() );
0248 return result_;
0249 }
0250
0251 virtual void destroy() = 0;
0252 };
0253
0254 template<>
0255 class pull_coroutine_impl< void > : private noncopyable
0256 {
0257 protected:
0258 int flags_;
0259 exception_ptr except_;
0260 coroutine_context * caller_;
0261 coroutine_context * callee_;
0262
0263 public:
0264 typedef parameters< void > param_type;
0265
0266 pull_coroutine_impl( coroutine_context * caller,
0267 coroutine_context * callee,
0268 bool unwind) :
0269 flags_( 0),
0270 except_(),
0271 caller_( caller),
0272 callee_( callee)
0273 {
0274 if ( unwind) flags_ |= flag_force_unwind;
0275 }
0276
0277 virtual ~pull_coroutine_impl() {}
0278
0279 inline bool force_unwind() const BOOST_NOEXCEPT
0280 { return 0 != ( flags_ & flag_force_unwind); }
0281
0282 inline bool unwind_requested() const BOOST_NOEXCEPT
0283 { return 0 != ( flags_ & flag_unwind_stack); }
0284
0285 inline bool is_started() const BOOST_NOEXCEPT
0286 { return 0 != ( flags_ & flag_started); }
0287
0288 inline bool is_running() const BOOST_NOEXCEPT
0289 { return 0 != ( flags_ & flag_running); }
0290
0291 inline bool is_complete() const BOOST_NOEXCEPT
0292 { return 0 != ( flags_ & flag_complete); }
0293
0294 inline void unwind_stack() BOOST_NOEXCEPT
0295 {
0296 if ( is_started() && ! is_complete() && force_unwind() )
0297 {
0298 flags_ |= flag_unwind_stack;
0299 param_type to( unwind_t::force_unwind);
0300 caller_->jump(
0301 * callee_,
0302 & to);
0303 flags_ &= ~flag_unwind_stack;
0304
0305 BOOST_ASSERT( is_complete() );
0306 }
0307 }
0308
0309 inline void pull()
0310 {
0311 BOOST_ASSERT( ! is_running() );
0312 BOOST_ASSERT( ! is_complete() );
0313
0314 flags_ |= flag_running;
0315 param_type to( this);
0316 param_type * from(
0317 static_cast< param_type * >(
0318 caller_->jump(
0319 * callee_,
0320 & to) ) );
0321 flags_ &= ~flag_running;
0322 if ( from->do_unwind) throw forced_unwind();
0323 if ( except_) rethrow_exception( except_);
0324 }
0325
0326 virtual void destroy() = 0;
0327 };
0328
0329 }}}
0330
0331 #ifdef BOOST_HAS_ABI_HEADERS
0332 # include BOOST_ABI_SUFFIX
0333 #endif
0334
0335 #endif