pull_coroutine_object.hpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  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_OBJECT_H
  6. #define BOOST_COROUTINES_DETAIL_PULL_COROUTINE_OBJECT_H
  7. #include <boost/assert.hpp>
  8. #include <boost/config.hpp>
  9. #include <boost/context/detail/config.hpp>
  10. #include <boost/cstdint.hpp>
  11. #include <boost/exception_ptr.hpp>
  12. #include <boost/move/move.hpp>
  13. #include <boost/coroutine/detail/config.hpp>
  14. #include <boost/coroutine/detail/coroutine_context.hpp>
  15. #include <boost/coroutine/detail/flags.hpp>
  16. #include <boost/coroutine/detail/preallocated.hpp>
  17. #include <boost/coroutine/detail/pull_coroutine_impl.hpp>
  18. #include <boost/coroutine/detail/trampoline_pull.hpp>
  19. #include <boost/coroutine/exceptions.hpp>
  20. #include <boost/coroutine/flags.hpp>
  21. #include <boost/coroutine/stack_context.hpp>
  22. #ifdef BOOST_HAS_ABI_HEADERS
  23. # include BOOST_ABI_PREFIX
  24. #endif
  25. #if defined(BOOST_MSVC)
  26. # pragma warning(push)
  27. # pragma warning(disable:4355)
  28. #endif
  29. namespace boost {
  30. namespace coroutines {
  31. namespace detail {
  32. struct pull_coroutine_context
  33. {
  34. coroutine_context caller;
  35. coroutine_context callee;
  36. template< typename Coro >
  37. pull_coroutine_context( preallocated const& palloc, Coro *) :
  38. caller(),
  39. callee( trampoline_pull< Coro >, palloc)
  40. {}
  41. };
  42. template< typename PushCoro, typename R, typename Fn, typename StackAllocator >
  43. class pull_coroutine_object : private pull_coroutine_context,
  44. public pull_coroutine_impl< R >
  45. {
  46. private:
  47. typedef pull_coroutine_context ctx_t;
  48. typedef pull_coroutine_impl< R > base_t;
  49. typedef pull_coroutine_object< PushCoro, R, Fn, StackAllocator > obj_t;
  50. Fn fn_;
  51. stack_context stack_ctx_;
  52. StackAllocator stack_alloc_;
  53. static void deallocate_( obj_t * obj)
  54. {
  55. stack_context stack_ctx( obj->stack_ctx_);
  56. StackAllocator stack_alloc( obj->stack_alloc_);
  57. obj->unwind_stack();
  58. obj->~obj_t();
  59. stack_alloc.deallocate( stack_ctx);
  60. }
  61. public:
  62. #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
  63. pull_coroutine_object( Fn fn, attributes const& attrs,
  64. preallocated const& palloc,
  65. StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
  66. ctx_t( palloc, this),
  67. base_t( & this->caller,
  68. & this->callee,
  69. stack_unwind == attrs.do_unwind),
  70. fn_( fn),
  71. stack_ctx_( palloc.sctx),
  72. stack_alloc_( stack_alloc)
  73. {}
  74. #endif
  75. pull_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs,
  76. preallocated const& palloc,
  77. StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
  78. ctx_t( palloc, this),
  79. base_t( & this->caller,
  80. & this->callee,
  81. stack_unwind == attrs.do_unwind),
  82. #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
  83. fn_( fn),
  84. #else
  85. fn_( boost::forward< Fn >( fn) ),
  86. #endif
  87. stack_ctx_( palloc.sctx),
  88. stack_alloc_( stack_alloc)
  89. {}
  90. void run()
  91. {
  92. BOOST_ASSERT( ! base_t::unwind_requested() );
  93. base_t::flags_ |= flag_started;
  94. base_t::flags_ |= flag_running;
  95. // create push_coroutine
  96. typename PushCoro::synth_type b( & this->callee, & this->caller, false);
  97. PushCoro push_coro( synthesized_t::syntesized, b);
  98. try
  99. { fn_( push_coro); }
  100. catch ( forced_unwind const&)
  101. {}
  102. #if defined( BOOST_CONTEXT_HAS_CXXABI_H )
  103. catch ( abi::__forced_unwind const&)
  104. { throw; }
  105. #endif
  106. catch (...)
  107. { base_t::except_ = current_exception(); }
  108. base_t::flags_ |= flag_complete;
  109. base_t::flags_ &= ~flag_running;
  110. typename base_t::param_type to;
  111. this->callee.jump(
  112. this->caller,
  113. & to);
  114. BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
  115. }
  116. void destroy()
  117. { deallocate_( this); }
  118. };
  119. template< typename PushCoro, typename R, typename Fn, typename StackAllocator >
  120. class pull_coroutine_object< PushCoro, R &, Fn, StackAllocator > : private pull_coroutine_context,
  121. public pull_coroutine_impl< R & >
  122. {
  123. private:
  124. typedef pull_coroutine_context ctx_t;
  125. typedef pull_coroutine_impl< R & > base_t;
  126. typedef pull_coroutine_object< PushCoro, R &, Fn, StackAllocator > obj_t;
  127. Fn fn_;
  128. stack_context stack_ctx_;
  129. StackAllocator stack_alloc_;
  130. static void deallocate_( obj_t * obj)
  131. {
  132. stack_context stack_ctx( obj->stack_ctx_);
  133. StackAllocator stack_alloc( obj->stack_alloc_);
  134. obj->unwind_stack();
  135. obj->~obj_t();
  136. stack_alloc.deallocate( stack_ctx);
  137. }
  138. public:
  139. #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
  140. pull_coroutine_object( Fn fn, attributes const& attrs,
  141. preallocated const& palloc,
  142. StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
  143. ctx_t( palloc, this),
  144. base_t( & this->caller,
  145. & this->callee,
  146. stack_unwind == attrs.do_unwind),
  147. fn_( fn),
  148. stack_ctx_( palloc.sctx),
  149. stack_alloc_( stack_alloc)
  150. {}
  151. #endif
  152. pull_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs,
  153. preallocated const& palloc,
  154. StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
  155. ctx_t( palloc, this),
  156. base_t( & this->caller,
  157. & this->callee,
  158. stack_unwind == attrs.do_unwind),
  159. #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
  160. fn_( fn),
  161. #else
  162. fn_( boost::forward< Fn >( fn) ),
  163. #endif
  164. stack_ctx_( palloc.sctx),
  165. stack_alloc_( stack_alloc)
  166. {}
  167. void run()
  168. {
  169. BOOST_ASSERT( ! base_t::unwind_requested() );
  170. base_t::flags_ |= flag_started;
  171. base_t::flags_ |= flag_running;
  172. // create push_coroutine
  173. typename PushCoro::synth_type b( & this->callee, & this->caller, false);
  174. PushCoro push_coro( synthesized_t::syntesized, b);
  175. try
  176. { fn_( push_coro); }
  177. catch ( forced_unwind const&)
  178. {}
  179. #if defined( BOOST_CONTEXT_HAS_CXXABI_H )
  180. catch ( abi::__forced_unwind const&)
  181. { throw; }
  182. #endif
  183. catch (...)
  184. { base_t::except_ = current_exception(); }
  185. base_t::flags_ |= flag_complete;
  186. base_t::flags_ &= ~flag_running;
  187. typename base_t::param_type to;
  188. this->callee.jump(
  189. this->caller,
  190. & to);
  191. BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
  192. }
  193. void destroy()
  194. { deallocate_( this); }
  195. };
  196. template< typename PushCoro, typename Fn, typename StackAllocator >
  197. class pull_coroutine_object< PushCoro, void, Fn, StackAllocator > : private pull_coroutine_context,
  198. public pull_coroutine_impl< void >
  199. {
  200. private:
  201. typedef pull_coroutine_context ctx_t;
  202. typedef pull_coroutine_impl< void > base_t;
  203. typedef pull_coroutine_object< PushCoro, void, Fn, StackAllocator > obj_t;
  204. Fn fn_;
  205. stack_context stack_ctx_;
  206. StackAllocator stack_alloc_;
  207. static void deallocate_( obj_t * obj)
  208. {
  209. stack_context stack_ctx( obj->stack_ctx_);
  210. StackAllocator stack_alloc( obj->stack_alloc_);
  211. obj->unwind_stack();
  212. obj->~obj_t();
  213. stack_alloc.deallocate( stack_ctx);
  214. }
  215. public:
  216. #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
  217. pull_coroutine_object( Fn fn, attributes const& attrs,
  218. preallocated const& palloc,
  219. StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
  220. ctx_t( palloc, this),
  221. base_t( & this->caller,
  222. & this->callee,
  223. stack_unwind == attrs.do_unwind),
  224. fn_( fn),
  225. stack_ctx_( palloc.sctx),
  226. stack_alloc_( stack_alloc)
  227. {}
  228. #endif
  229. pull_coroutine_object( BOOST_RV_REF( Fn) fn, attributes const& attrs,
  230. preallocated const& palloc,
  231. StackAllocator const& stack_alloc) BOOST_NOEXCEPT :
  232. ctx_t( palloc, this),
  233. base_t( & this->caller,
  234. & this->callee,
  235. stack_unwind == attrs.do_unwind),
  236. #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
  237. fn_( fn),
  238. #else
  239. fn_( boost::forward< Fn >( fn) ),
  240. #endif
  241. stack_ctx_( palloc.sctx),
  242. stack_alloc_( stack_alloc)
  243. {}
  244. void run()
  245. {
  246. BOOST_ASSERT( ! base_t::unwind_requested() );
  247. base_t::flags_ |= flag_started;
  248. base_t::flags_ |= flag_running;
  249. // create push_coroutine
  250. typename PushCoro::synth_type b( & this->callee, & this->caller, false);
  251. PushCoro push_coro( synthesized_t::syntesized, b);
  252. try
  253. { fn_( push_coro); }
  254. catch ( forced_unwind const&)
  255. {}
  256. #if defined( BOOST_CONTEXT_HAS_CXXABI_H )
  257. catch ( abi::__forced_unwind const&)
  258. { throw; }
  259. #endif
  260. catch (...)
  261. { base_t::except_ = current_exception(); }
  262. base_t::flags_ |= flag_complete;
  263. base_t::flags_ &= ~flag_running;
  264. typename base_t::param_type to;
  265. this->callee.jump(
  266. this->caller,
  267. & to);
  268. BOOST_ASSERT_MSG( false, "pull_coroutine is complete");
  269. }
  270. void destroy()
  271. { deallocate_( this); }
  272. };
  273. }}}
  274. #if defined(BOOST_MSVC)
  275. # pragma warning(pop)
  276. #endif
  277. #ifdef BOOST_HAS_ABI_HEADERS
  278. # include BOOST_ABI_SUFFIX
  279. #endif
  280. #endif // BOOST_COROUTINES_DETAIL_PULL_COROUTINE_OBJECT_H