push_coroutine_impl.hpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. // Copyright Oliver Kowalke 2009.
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See accompanying file LICENSE_1_0.txt or copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_IMPL_H
  6. #define BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_IMPL_H
  7. #include <boost/assert.hpp>
  8. #include <boost/config.hpp>
  9. #include <boost/exception_ptr.hpp>
  10. #include <boost/throw_exception.hpp>
  11. #include <boost/utility.hpp>
  12. #include <boost/coroutine/detail/config.hpp>
  13. #include <boost/coroutine/detail/coroutine_context.hpp>
  14. #include <boost/coroutine/detail/flags.hpp>
  15. #include <boost/coroutine/detail/parameters.hpp>
  16. #include <boost/coroutine/detail/trampoline_push.hpp>
  17. #include <boost/coroutine/exceptions.hpp>
  18. #ifdef BOOST_HAS_ABI_HEADERS
  19. # include BOOST_ABI_PREFIX
  20. #endif
  21. namespace boost {
  22. namespace coroutines {
  23. struct stack_context;
  24. namespace detail {
  25. template< typename Arg >
  26. class push_coroutine_impl : private noncopyable
  27. {
  28. protected:
  29. int flags_;
  30. exception_ptr except_;
  31. coroutine_context * caller_;
  32. coroutine_context * callee_;
  33. public:
  34. typedef parameters< Arg > param_type;
  35. push_coroutine_impl( coroutine_context * caller,
  36. coroutine_context * callee,
  37. bool unwind) :
  38. flags_( 0),
  39. except_(),
  40. caller_( caller),
  41. callee_( callee)
  42. {
  43. if ( unwind) flags_ |= flag_force_unwind;
  44. }
  45. virtual ~push_coroutine_impl() {}
  46. bool force_unwind() const BOOST_NOEXCEPT
  47. { return 0 != ( flags_ & flag_force_unwind); }
  48. bool unwind_requested() const BOOST_NOEXCEPT
  49. { return 0 != ( flags_ & flag_unwind_stack); }
  50. bool is_started() const BOOST_NOEXCEPT
  51. { return 0 != ( flags_ & flag_started); }
  52. bool is_running() const BOOST_NOEXCEPT
  53. { return 0 != ( flags_ & flag_running); }
  54. bool is_complete() const BOOST_NOEXCEPT
  55. { return 0 != ( flags_ & flag_complete); }
  56. void unwind_stack() BOOST_NOEXCEPT
  57. {
  58. if ( is_started() && ! is_complete() && force_unwind() )
  59. {
  60. flags_ |= flag_unwind_stack;
  61. param_type to( unwind_t::force_unwind);
  62. caller_->jump(
  63. * callee_,
  64. & to);
  65. flags_ &= ~flag_unwind_stack;
  66. BOOST_ASSERT( is_complete() );
  67. }
  68. }
  69. void push( Arg const& arg)
  70. {
  71. BOOST_ASSERT( ! is_running() );
  72. BOOST_ASSERT( ! is_complete() );
  73. flags_ |= flag_running;
  74. param_type to( const_cast< Arg * >( & arg), this);
  75. param_type * from(
  76. static_cast< param_type * >(
  77. caller_->jump(
  78. * callee_,
  79. & to) ) );
  80. flags_ &= ~flag_running;
  81. if ( from->do_unwind) throw forced_unwind();
  82. if ( except_) rethrow_exception( except_);
  83. }
  84. void push( BOOST_RV_REF( Arg) arg)
  85. {
  86. BOOST_ASSERT( ! is_running() );
  87. BOOST_ASSERT( ! is_complete() );
  88. flags_ |= flag_running;
  89. param_type to( const_cast< Arg * >( & arg), this);
  90. param_type * from(
  91. static_cast< param_type * >(
  92. caller_->jump(
  93. * callee_,
  94. & to) ) );
  95. flags_ &= ~flag_running;
  96. if ( from->do_unwind) throw forced_unwind();
  97. if ( except_) rethrow_exception( except_);
  98. }
  99. virtual void destroy() = 0;
  100. };
  101. template< typename Arg >
  102. class push_coroutine_impl< Arg & > : private noncopyable
  103. {
  104. protected:
  105. int flags_;
  106. exception_ptr except_;
  107. coroutine_context * caller_;
  108. coroutine_context * callee_;
  109. public:
  110. typedef parameters< Arg & > param_type;
  111. push_coroutine_impl( coroutine_context * caller,
  112. coroutine_context * callee,
  113. bool unwind) :
  114. flags_( 0),
  115. except_(),
  116. caller_( caller),
  117. callee_( callee)
  118. {
  119. if ( unwind) flags_ |= flag_force_unwind;
  120. }
  121. virtual ~push_coroutine_impl() {}
  122. bool force_unwind() const BOOST_NOEXCEPT
  123. { return 0 != ( flags_ & flag_force_unwind); }
  124. bool unwind_requested() const BOOST_NOEXCEPT
  125. { return 0 != ( flags_ & flag_unwind_stack); }
  126. bool is_started() const BOOST_NOEXCEPT
  127. { return 0 != ( flags_ & flag_started); }
  128. bool is_running() const BOOST_NOEXCEPT
  129. { return 0 != ( flags_ & flag_running); }
  130. bool is_complete() const BOOST_NOEXCEPT
  131. { return 0 != ( flags_ & flag_complete); }
  132. void unwind_stack() BOOST_NOEXCEPT
  133. {
  134. if ( is_started() && ! is_complete() && force_unwind() )
  135. {
  136. flags_ |= flag_unwind_stack;
  137. param_type to( unwind_t::force_unwind);
  138. caller_->jump(
  139. * callee_,
  140. & to);
  141. flags_ &= ~flag_unwind_stack;
  142. BOOST_ASSERT( is_complete() );
  143. }
  144. }
  145. void push( Arg & arg)
  146. {
  147. BOOST_ASSERT( ! is_running() );
  148. BOOST_ASSERT( ! is_complete() );
  149. flags_ |= flag_running;
  150. param_type to( & arg, this);
  151. param_type * from(
  152. static_cast< param_type * >(
  153. caller_->jump(
  154. * callee_,
  155. & to) ) );
  156. flags_ &= ~flag_running;
  157. if ( from->do_unwind) throw forced_unwind();
  158. if ( except_) rethrow_exception( except_);
  159. }
  160. virtual void destroy() = 0;
  161. };
  162. template<>
  163. class push_coroutine_impl< void > : private noncopyable
  164. {
  165. protected:
  166. int flags_;
  167. exception_ptr except_;
  168. coroutine_context * caller_;
  169. coroutine_context * callee_;
  170. public:
  171. typedef parameters< void > param_type;
  172. push_coroutine_impl( coroutine_context * caller,
  173. coroutine_context * callee,
  174. bool unwind) :
  175. flags_( 0),
  176. except_(),
  177. caller_( caller),
  178. callee_( callee)
  179. {
  180. if ( unwind) flags_ |= flag_force_unwind;
  181. }
  182. virtual ~push_coroutine_impl() {}
  183. inline bool force_unwind() const BOOST_NOEXCEPT
  184. { return 0 != ( flags_ & flag_force_unwind); }
  185. inline bool unwind_requested() const BOOST_NOEXCEPT
  186. { return 0 != ( flags_ & flag_unwind_stack); }
  187. inline bool is_started() const BOOST_NOEXCEPT
  188. { return 0 != ( flags_ & flag_started); }
  189. inline bool is_running() const BOOST_NOEXCEPT
  190. { return 0 != ( flags_ & flag_running); }
  191. inline bool is_complete() const BOOST_NOEXCEPT
  192. { return 0 != ( flags_ & flag_complete); }
  193. inline void unwind_stack() BOOST_NOEXCEPT
  194. {
  195. if ( is_started() && ! is_complete() && force_unwind() )
  196. {
  197. flags_ |= flag_unwind_stack;
  198. param_type to( unwind_t::force_unwind);
  199. caller_->jump(
  200. * callee_,
  201. & to);
  202. flags_ &= ~flag_unwind_stack;
  203. BOOST_ASSERT( is_complete() );
  204. }
  205. }
  206. inline void push()
  207. {
  208. BOOST_ASSERT( ! is_running() );
  209. BOOST_ASSERT( ! is_complete() );
  210. flags_ |= flag_running;
  211. param_type to( this);
  212. param_type * from(
  213. static_cast< param_type * >(
  214. caller_->jump(
  215. * callee_,
  216. & to) ) );
  217. flags_ &= ~flag_running;
  218. if ( from->do_unwind) throw forced_unwind();
  219. if ( except_) rethrow_exception( except_);
  220. }
  221. virtual void destroy() = 0;
  222. };
  223. }}}
  224. #ifdef BOOST_HAS_ABI_HEADERS
  225. # include BOOST_ABI_SUFFIX
  226. #endif
  227. #endif // BOOST_COROUTINES_DETAIL_PUSH_COROUTINE_IMPL_H