pull_coroutine_impl.hpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  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_PULL_COROUTINE_IMPL_H
  6. #define BOOST_COROUTINES_DETAIL_PULL_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_pull.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 R >
  26. class pull_coroutine_impl : private noncopyable
  27. {
  28. protected:
  29. int flags_;
  30. exception_ptr except_;
  31. coroutine_context * caller_;
  32. coroutine_context * callee_;
  33. R * result_;
  34. public:
  35. typedef parameters< R > param_type;
  36. pull_coroutine_impl( coroutine_context * caller,
  37. coroutine_context * callee,
  38. bool unwind) :
  39. flags_( 0),
  40. except_(),
  41. caller_( caller),
  42. callee_( callee),
  43. result_( 0)
  44. {
  45. if ( unwind) flags_ |= flag_force_unwind;
  46. }
  47. pull_coroutine_impl( coroutine_context * caller,
  48. coroutine_context * callee,
  49. bool unwind,
  50. R * result) :
  51. flags_( 0),
  52. except_(),
  53. caller_( caller),
  54. callee_( callee),
  55. result_( result)
  56. {
  57. if ( unwind) flags_ |= flag_force_unwind;
  58. }
  59. virtual ~pull_coroutine_impl() {}
  60. bool force_unwind() const BOOST_NOEXCEPT
  61. { return 0 != ( flags_ & flag_force_unwind); }
  62. bool unwind_requested() const BOOST_NOEXCEPT
  63. { return 0 != ( flags_ & flag_unwind_stack); }
  64. bool is_started() const BOOST_NOEXCEPT
  65. { return 0 != ( flags_ & flag_started); }
  66. bool is_running() const BOOST_NOEXCEPT
  67. { return 0 != ( flags_ & flag_running); }
  68. bool is_complete() const BOOST_NOEXCEPT
  69. { return 0 != ( flags_ & flag_complete); }
  70. void unwind_stack() BOOST_NOEXCEPT
  71. {
  72. if ( is_started() && ! is_complete() && force_unwind() )
  73. {
  74. flags_ |= flag_unwind_stack;
  75. param_type to( unwind_t::force_unwind);
  76. caller_->jump(
  77. * callee_,
  78. & to);
  79. flags_ &= ~flag_unwind_stack;
  80. BOOST_ASSERT( is_complete() );
  81. }
  82. }
  83. void pull()
  84. {
  85. BOOST_ASSERT( ! is_running() );
  86. BOOST_ASSERT( ! is_complete() );
  87. flags_ |= flag_running;
  88. param_type to( this);
  89. param_type * from(
  90. static_cast< param_type * >(
  91. caller_->jump(
  92. * callee_,
  93. & to) ) );
  94. flags_ &= ~flag_running;
  95. result_ = from->data;
  96. if ( from->do_unwind) throw forced_unwind();
  97. if ( except_) rethrow_exception( except_);
  98. }
  99. bool has_result() const
  100. { return 0 != result_; }
  101. R get() const
  102. {
  103. if ( ! has_result() )
  104. boost::throw_exception(
  105. invalid_result() );
  106. return * result_;
  107. }
  108. R * get_pointer() const
  109. {
  110. if ( ! has_result() )
  111. boost::throw_exception(
  112. invalid_result() );
  113. return result_;
  114. }
  115. virtual void destroy() = 0;
  116. };
  117. template< typename R >
  118. class pull_coroutine_impl< R & > : private noncopyable
  119. {
  120. protected:
  121. int flags_;
  122. exception_ptr except_;
  123. coroutine_context * caller_;
  124. coroutine_context * callee_;
  125. R * result_;
  126. public:
  127. typedef parameters< R & > param_type;
  128. pull_coroutine_impl( coroutine_context * caller,
  129. coroutine_context * callee,
  130. bool unwind) :
  131. flags_( 0),
  132. except_(),
  133. caller_( caller),
  134. callee_( callee),
  135. result_( 0)
  136. {
  137. if ( unwind) flags_ |= flag_force_unwind;
  138. }
  139. pull_coroutine_impl( coroutine_context * caller,
  140. coroutine_context * callee,
  141. bool unwind,
  142. R * result) :
  143. flags_( 0),
  144. except_(),
  145. caller_( caller),
  146. callee_( callee),
  147. result_( result)
  148. {
  149. if ( unwind) flags_ |= flag_force_unwind;
  150. }
  151. virtual ~pull_coroutine_impl() {}
  152. bool force_unwind() const BOOST_NOEXCEPT
  153. { return 0 != ( flags_ & flag_force_unwind); }
  154. bool unwind_requested() const BOOST_NOEXCEPT
  155. { return 0 != ( flags_ & flag_unwind_stack); }
  156. bool is_started() const BOOST_NOEXCEPT
  157. { return 0 != ( flags_ & flag_started); }
  158. bool is_running() const BOOST_NOEXCEPT
  159. { return 0 != ( flags_ & flag_running); }
  160. bool is_complete() const BOOST_NOEXCEPT
  161. { return 0 != ( flags_ & flag_complete); }
  162. void unwind_stack() BOOST_NOEXCEPT
  163. {
  164. if ( is_started() && ! is_complete() && force_unwind() )
  165. {
  166. flags_ |= flag_unwind_stack;
  167. param_type to( unwind_t::force_unwind);
  168. caller_->jump(
  169. * callee_,
  170. & to);
  171. flags_ &= ~flag_unwind_stack;
  172. BOOST_ASSERT( is_complete() );
  173. }
  174. }
  175. void pull()
  176. {
  177. BOOST_ASSERT( ! is_running() );
  178. BOOST_ASSERT( ! is_complete() );
  179. flags_ |= flag_running;
  180. param_type to( this);
  181. param_type * from(
  182. static_cast< param_type * >(
  183. caller_->jump(
  184. * callee_,
  185. & to) ) );
  186. flags_ &= ~flag_running;
  187. result_ = from->data;
  188. if ( from->do_unwind) throw forced_unwind();
  189. if ( except_) rethrow_exception( except_);
  190. }
  191. bool has_result() const
  192. { return 0 != result_; }
  193. R & get() const
  194. {
  195. if ( ! has_result() )
  196. boost::throw_exception(
  197. invalid_result() );
  198. return * result_;
  199. }
  200. R * get_pointer() const
  201. {
  202. if ( ! has_result() )
  203. boost::throw_exception(
  204. invalid_result() );
  205. return result_;
  206. }
  207. virtual void destroy() = 0;
  208. };
  209. template<>
  210. class pull_coroutine_impl< void > : private noncopyable
  211. {
  212. protected:
  213. int flags_;
  214. exception_ptr except_;
  215. coroutine_context * caller_;
  216. coroutine_context * callee_;
  217. public:
  218. typedef parameters< void > param_type;
  219. pull_coroutine_impl( coroutine_context * caller,
  220. coroutine_context * callee,
  221. bool unwind) :
  222. flags_( 0),
  223. except_(),
  224. caller_( caller),
  225. callee_( callee)
  226. {
  227. if ( unwind) flags_ |= flag_force_unwind;
  228. }
  229. virtual ~pull_coroutine_impl() {}
  230. inline bool force_unwind() const BOOST_NOEXCEPT
  231. { return 0 != ( flags_ & flag_force_unwind); }
  232. inline bool unwind_requested() const BOOST_NOEXCEPT
  233. { return 0 != ( flags_ & flag_unwind_stack); }
  234. inline bool is_started() const BOOST_NOEXCEPT
  235. { return 0 != ( flags_ & flag_started); }
  236. inline bool is_running() const BOOST_NOEXCEPT
  237. { return 0 != ( flags_ & flag_running); }
  238. inline bool is_complete() const BOOST_NOEXCEPT
  239. { return 0 != ( flags_ & flag_complete); }
  240. inline void unwind_stack() BOOST_NOEXCEPT
  241. {
  242. if ( is_started() && ! is_complete() && force_unwind() )
  243. {
  244. flags_ |= flag_unwind_stack;
  245. param_type to( unwind_t::force_unwind);
  246. caller_->jump(
  247. * callee_,
  248. & to);
  249. flags_ &= ~flag_unwind_stack;
  250. BOOST_ASSERT( is_complete() );
  251. }
  252. }
  253. inline void pull()
  254. {
  255. BOOST_ASSERT( ! is_running() );
  256. BOOST_ASSERT( ! is_complete() );
  257. flags_ |= flag_running;
  258. param_type to( this);
  259. param_type * from(
  260. static_cast< param_type * >(
  261. caller_->jump(
  262. * callee_,
  263. & to) ) );
  264. flags_ &= ~flag_running;
  265. if ( from->do_unwind) throw forced_unwind();
  266. if ( except_) rethrow_exception( except_);
  267. }
  268. virtual void destroy() = 0;
  269. };
  270. }}}
  271. #ifdef BOOST_HAS_ABI_HEADERS
  272. # include BOOST_ABI_SUFFIX
  273. #endif
  274. #endif // BOOST_COROUTINES_DETAIL_PULL_COROUTINE_IMPL_H