1 2 // Copyright Oliver Kowalke 2009. 3 // Distributed under the Boost Software License, Version 1.0. 4 // (See accompanying file LICENSE_1_0.txt or copy at 5 // http://www.boost.org/LICENSE_1_0.txt) 6 7 #ifndef BOOST_COROUTINES_DETAIL_PULL_COROUTINE_IMPL_H 8 #define BOOST_COROUTINES_DETAIL_PULL_COROUTINE_IMPL_H 9 10 #include <boost/assert.hpp> 11 #include <boost/config.hpp> 12 #include <boost/exception_ptr.hpp> 13 #include <boost/throw_exception.hpp> 14 #include <boost/utility.hpp> 15 16 #include <boost/coroutine/detail/config.hpp> 17 #include <boost/coroutine/detail/coroutine_context.hpp> 18 #include <boost/coroutine/detail/flags.hpp> 19 #include <boost/coroutine/detail/parameters.hpp> 20 #include <boost/coroutine/detail/trampoline_pull.hpp> 21 #include <boost/coroutine/exceptions.hpp> 22 23 #ifdef BOOST_HAS_ABI_HEADERS 24 # include BOOST_ABI_PREFIX 25 #endif 26 27 namespace boost { 28 namespace coroutines { 29 30 struct stack_context; 31 32 namespace detail { 33 34 template< typename R > 35 class pull_coroutine_impl : private noncopyable 36 { 37 protected: 38 int flags_; 39 exception_ptr except_; 40 coroutine_context * caller_; 41 coroutine_context * callee_; 42 R * result_; 43 44 public: 45 typedef parameters< R > param_type; 46 pull_coroutine_impl(coroutine_context * caller,coroutine_context * callee,bool unwind)47 pull_coroutine_impl( coroutine_context * caller, 48 coroutine_context * callee, 49 bool unwind) : 50 flags_( 0), 51 except_(), 52 caller_( caller), 53 callee_( callee), 54 result_( 0) 55 { 56 if ( unwind) flags_ |= flag_force_unwind; 57 } 58 pull_coroutine_impl(coroutine_context * caller,coroutine_context * callee,bool unwind,R * result)59 pull_coroutine_impl( coroutine_context * caller, 60 coroutine_context * callee, 61 bool unwind, 62 R * result) : 63 flags_( 0), 64 except_(), 65 caller_( caller), 66 callee_( callee), 67 result_( result) 68 { 69 if ( unwind) flags_ |= flag_force_unwind; 70 } 71 ~pull_coroutine_impl()72 virtual ~pull_coroutine_impl() {} 73 force_unwind() const74 bool force_unwind() const BOOST_NOEXCEPT 75 { return 0 != ( flags_ & flag_force_unwind); } 76 unwind_requested() const77 bool unwind_requested() const BOOST_NOEXCEPT 78 { return 0 != ( flags_ & flag_unwind_stack); } 79 is_started() const80 bool is_started() const BOOST_NOEXCEPT 81 { return 0 != ( flags_ & flag_started); } 82 is_running() const83 bool is_running() const BOOST_NOEXCEPT 84 { return 0 != ( flags_ & flag_running); } 85 is_complete() const86 bool is_complete() const BOOST_NOEXCEPT 87 { return 0 != ( flags_ & flag_complete); } 88 unwind_stack()89 void unwind_stack() BOOST_NOEXCEPT 90 { 91 if ( is_started() && ! is_complete() && force_unwind() ) 92 { 93 flags_ |= flag_unwind_stack; 94 param_type to( unwind_t::force_unwind); 95 caller_->jump( 96 * callee_, 97 & to); 98 flags_ &= ~flag_unwind_stack; 99 100 BOOST_ASSERT( is_complete() ); 101 } 102 } 103 pull()104 void pull() 105 { 106 BOOST_ASSERT( ! is_running() ); 107 BOOST_ASSERT( ! is_complete() ); 108 109 flags_ |= flag_running; 110 param_type to( this); 111 param_type * from( 112 static_cast< param_type * >( 113 caller_->jump( 114 * callee_, 115 & to) ) ); 116 flags_ &= ~flag_running; 117 result_ = from->data; 118 if ( from->do_unwind) throw forced_unwind(); 119 if ( except_) rethrow_exception( except_); 120 } 121 has_result() const122 bool has_result() const 123 { return 0 != result_; } 124 get() const125 R get() const 126 { 127 if ( ! has_result() ) 128 boost::throw_exception( 129 invalid_result() ); 130 return * result_; 131 } 132 get_pointer() const133 R * get_pointer() const 134 { 135 if ( ! has_result() ) 136 boost::throw_exception( 137 invalid_result() ); 138 return result_; 139 } 140 141 virtual void destroy() = 0; 142 }; 143 144 template< typename R > 145 class pull_coroutine_impl< R & > : private noncopyable 146 { 147 protected: 148 int flags_; 149 exception_ptr except_; 150 coroutine_context * caller_; 151 coroutine_context * callee_; 152 R * result_; 153 154 public: 155 typedef parameters< R & > param_type; 156 pull_coroutine_impl(coroutine_context * caller,coroutine_context * callee,bool unwind)157 pull_coroutine_impl( coroutine_context * caller, 158 coroutine_context * callee, 159 bool unwind) : 160 flags_( 0), 161 except_(), 162 caller_( caller), 163 callee_( callee), 164 result_( 0) 165 { 166 if ( unwind) flags_ |= flag_force_unwind; 167 } 168 pull_coroutine_impl(coroutine_context * caller,coroutine_context * callee,bool unwind,R * result)169 pull_coroutine_impl( coroutine_context * caller, 170 coroutine_context * callee, 171 bool unwind, 172 R * result) : 173 flags_( 0), 174 except_(), 175 caller_( caller), 176 callee_( callee), 177 result_( result) 178 { 179 if ( unwind) flags_ |= flag_force_unwind; 180 } 181 ~pull_coroutine_impl()182 virtual ~pull_coroutine_impl() {} 183 force_unwind() const184 bool force_unwind() const BOOST_NOEXCEPT 185 { return 0 != ( flags_ & flag_force_unwind); } 186 unwind_requested() const187 bool unwind_requested() const BOOST_NOEXCEPT 188 { return 0 != ( flags_ & flag_unwind_stack); } 189 is_started() const190 bool is_started() const BOOST_NOEXCEPT 191 { return 0 != ( flags_ & flag_started); } 192 is_running() const193 bool is_running() const BOOST_NOEXCEPT 194 { return 0 != ( flags_ & flag_running); } 195 is_complete() const196 bool is_complete() const BOOST_NOEXCEPT 197 { return 0 != ( flags_ & flag_complete); } 198 unwind_stack()199 void unwind_stack() BOOST_NOEXCEPT 200 { 201 if ( is_started() && ! is_complete() && force_unwind() ) 202 { 203 flags_ |= flag_unwind_stack; 204 param_type to( unwind_t::force_unwind); 205 caller_->jump( 206 * callee_, 207 & to); 208 flags_ &= ~flag_unwind_stack; 209 210 BOOST_ASSERT( is_complete() ); 211 } 212 } 213 pull()214 void pull() 215 { 216 BOOST_ASSERT( ! is_running() ); 217 BOOST_ASSERT( ! is_complete() ); 218 219 flags_ |= flag_running; 220 param_type to( this); 221 param_type * from( 222 static_cast< param_type * >( 223 caller_->jump( 224 * callee_, 225 & to) ) ); 226 flags_ &= ~flag_running; 227 result_ = from->data; 228 if ( from->do_unwind) throw forced_unwind(); 229 if ( except_) rethrow_exception( except_); 230 } 231 has_result() const232 bool has_result() const 233 { return 0 != result_; } 234 get() const235 R & get() const 236 { 237 if ( ! has_result() ) 238 boost::throw_exception( 239 invalid_result() ); 240 return * result_; 241 } 242 get_pointer() const243 R * get_pointer() const 244 { 245 if ( ! has_result() ) 246 boost::throw_exception( 247 invalid_result() ); 248 return result_; 249 } 250 251 virtual void destroy() = 0; 252 }; 253 254 template<> 255 class pull_coroutine_impl< void > : private noncopyable 256 { 257 protected: 258 int flags_; 259 exception_ptr except_; 260 coroutine_context * caller_; 261 coroutine_context * callee_; 262 263 public: 264 typedef parameters< void > param_type; 265 pull_coroutine_impl(coroutine_context * caller,coroutine_context * callee,bool unwind)266 pull_coroutine_impl( coroutine_context * caller, 267 coroutine_context * callee, 268 bool unwind) : 269 flags_( 0), 270 except_(), 271 caller_( caller), 272 callee_( callee) 273 { 274 if ( unwind) flags_ |= flag_force_unwind; 275 } 276 ~pull_coroutine_impl()277 virtual ~pull_coroutine_impl() {} 278 force_unwind() const279 inline bool force_unwind() const BOOST_NOEXCEPT 280 { return 0 != ( flags_ & flag_force_unwind); } 281 unwind_requested() const282 inline bool unwind_requested() const BOOST_NOEXCEPT 283 { return 0 != ( flags_ & flag_unwind_stack); } 284 is_started() const285 inline bool is_started() const BOOST_NOEXCEPT 286 { return 0 != ( flags_ & flag_started); } 287 is_running() const288 inline bool is_running() const BOOST_NOEXCEPT 289 { return 0 != ( flags_ & flag_running); } 290 is_complete() const291 inline bool is_complete() const BOOST_NOEXCEPT 292 { return 0 != ( flags_ & flag_complete); } 293 unwind_stack()294 inline void unwind_stack() BOOST_NOEXCEPT 295 { 296 if ( is_started() && ! is_complete() && force_unwind() ) 297 { 298 flags_ |= flag_unwind_stack; 299 param_type to( unwind_t::force_unwind); 300 caller_->jump( 301 * callee_, 302 & to); 303 flags_ &= ~flag_unwind_stack; 304 305 BOOST_ASSERT( is_complete() ); 306 } 307 } 308 pull()309 inline void pull() 310 { 311 BOOST_ASSERT( ! is_running() ); 312 BOOST_ASSERT( ! is_complete() ); 313 314 flags_ |= flag_running; 315 param_type to( this); 316 param_type * from( 317 static_cast< param_type * >( 318 caller_->jump( 319 * callee_, 320 & to) ) ); 321 flags_ &= ~flag_running; 322 if ( from->do_unwind) throw forced_unwind(); 323 if ( except_) rethrow_exception( except_); 324 } 325 326 virtual void destroy() = 0; 327 }; 328 329 }}} 330 331 #ifdef BOOST_HAS_ABI_HEADERS 332 # include BOOST_ABI_SUFFIX 333 #endif 334 335 #endif // BOOST_COROUTINES_DETAIL_PULL_COROUTINE_IMPL_H 336