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