symmetric_coroutine_impl.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  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_SYMMETRIC_COROUTINE_IMPL_H
  6. #define BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_IMPL_H
  7. #include <boost/assert.hpp>
  8. #include <boost/config.hpp>
  9. #include <boost/cstdint.hpp>
  10. #include <boost/utility.hpp>
  11. #include <boost/coroutine/detail/config.hpp>
  12. #include <boost/coroutine/detail/coroutine_context.hpp>
  13. #include <boost/coroutine/detail/flags.hpp>
  14. #include <boost/coroutine/detail/parameters.hpp>
  15. #include <boost/coroutine/detail/preallocated.hpp>
  16. #include <boost/coroutine/detail/trampoline.hpp>
  17. #include <boost/coroutine/exceptions.hpp>
  18. #include <boost/coroutine/stack_context.hpp>
  19. #ifdef BOOST_HAS_ABI_HEADERS
  20. # include BOOST_ABI_PREFIX
  21. #endif
  22. namespace boost {
  23. namespace coroutines {
  24. namespace detail {
  25. template< typename R >
  26. class symmetric_coroutine_impl : private noncopyable
  27. {
  28. public:
  29. typedef parameters< R > param_type;
  30. symmetric_coroutine_impl( preallocated const& palloc,
  31. bool unwind) BOOST_NOEXCEPT :
  32. flags_( 0),
  33. caller_(),
  34. callee_( trampoline< symmetric_coroutine_impl< R > >, palloc)
  35. {
  36. if ( unwind) flags_ |= flag_force_unwind;
  37. }
  38. virtual ~symmetric_coroutine_impl() {}
  39. bool force_unwind() const BOOST_NOEXCEPT
  40. { return 0 != ( flags_ & flag_force_unwind); }
  41. bool unwind_requested() const BOOST_NOEXCEPT
  42. { return 0 != ( flags_ & flag_unwind_stack); }
  43. bool is_started() const BOOST_NOEXCEPT
  44. { return 0 != ( flags_ & flag_started); }
  45. bool is_running() const BOOST_NOEXCEPT
  46. { return 0 != ( flags_ & flag_running); }
  47. bool is_complete() const BOOST_NOEXCEPT
  48. { return 0 != ( flags_ & flag_complete); }
  49. void unwind_stack() BOOST_NOEXCEPT
  50. {
  51. if ( is_started() && ! is_complete() && force_unwind() )
  52. {
  53. flags_ |= flag_unwind_stack;
  54. flags_ |= flag_running;
  55. param_type to( unwind_t::force_unwind);
  56. caller_.jump(
  57. callee_,
  58. & to);
  59. flags_ &= ~flag_running;
  60. flags_ &= ~flag_unwind_stack;
  61. BOOST_ASSERT( is_complete() );
  62. }
  63. }
  64. void resume( R r) BOOST_NOEXCEPT
  65. {
  66. param_type to( const_cast< R * >( & r), this);
  67. resume_( & to);
  68. }
  69. R * yield()
  70. {
  71. BOOST_ASSERT( is_running() );
  72. BOOST_ASSERT( ! is_complete() );
  73. flags_ &= ~flag_running;
  74. param_type to;
  75. param_type * from(
  76. static_cast< param_type * >(
  77. callee_.jump(
  78. caller_,
  79. & to) ) );
  80. flags_ |= flag_running;
  81. if ( from->do_unwind) throw forced_unwind();
  82. BOOST_ASSERT( from->data);
  83. return from->data;
  84. }
  85. template< typename X >
  86. R * yield_to( symmetric_coroutine_impl< X > * other, X x)
  87. {
  88. typename symmetric_coroutine_impl< X >::param_type to( & x, other);
  89. return yield_to_( other, & to);
  90. }
  91. template< typename X >
  92. R * yield_to( symmetric_coroutine_impl< X & > * other, X & x)
  93. {
  94. typename symmetric_coroutine_impl< X & >::param_type to( & x, other);
  95. return yield_to_( other, & to);
  96. }
  97. template< typename X >
  98. R * yield_to( symmetric_coroutine_impl< X > * other)
  99. {
  100. typename symmetric_coroutine_impl< X >::param_type to( other);
  101. return yield_to_( other, & to);
  102. }
  103. virtual void run( R *) BOOST_NOEXCEPT = 0;
  104. virtual void destroy() = 0;
  105. protected:
  106. template< typename X >
  107. friend class symmetric_coroutine_impl;
  108. int flags_;
  109. coroutine_context caller_;
  110. coroutine_context callee_;
  111. void resume_( param_type * to) BOOST_NOEXCEPT
  112. {
  113. BOOST_ASSERT( ! is_running() );
  114. BOOST_ASSERT( ! is_complete() );
  115. flags_ |= flag_running;
  116. caller_.jump(
  117. callee_,
  118. to);
  119. flags_ &= ~flag_running;
  120. }
  121. template< typename Other >
  122. R * yield_to_( Other * other, typename Other::param_type * to)
  123. {
  124. BOOST_ASSERT( is_running() );
  125. BOOST_ASSERT( ! is_complete() );
  126. BOOST_ASSERT( ! other->is_running() );
  127. BOOST_ASSERT( ! other->is_complete() );
  128. other->caller_ = caller_;
  129. flags_ &= ~flag_running;
  130. param_type * from(
  131. static_cast< param_type * >(
  132. callee_.jump(
  133. other->callee_,
  134. to) ) );
  135. flags_ |= flag_running;
  136. if ( from->do_unwind) throw forced_unwind();
  137. BOOST_ASSERT( from->data);
  138. return from->data;
  139. }
  140. };
  141. template< typename R >
  142. class symmetric_coroutine_impl< R & > : private noncopyable
  143. {
  144. public:
  145. typedef parameters< R & > param_type;
  146. symmetric_coroutine_impl( preallocated const& palloc,
  147. bool unwind) BOOST_NOEXCEPT :
  148. flags_( 0),
  149. caller_(),
  150. callee_( trampoline< symmetric_coroutine_impl< R > >, palloc)
  151. {
  152. if ( unwind) flags_ |= flag_force_unwind;
  153. }
  154. virtual ~symmetric_coroutine_impl() {}
  155. bool force_unwind() const BOOST_NOEXCEPT
  156. { return 0 != ( flags_ & flag_force_unwind); }
  157. bool unwind_requested() const BOOST_NOEXCEPT
  158. { return 0 != ( flags_ & flag_unwind_stack); }
  159. bool is_started() const BOOST_NOEXCEPT
  160. { return 0 != ( flags_ & flag_started); }
  161. bool is_running() const BOOST_NOEXCEPT
  162. { return 0 != ( flags_ & flag_running); }
  163. bool is_complete() const BOOST_NOEXCEPT
  164. { return 0 != ( flags_ & flag_complete); }
  165. void unwind_stack() BOOST_NOEXCEPT
  166. {
  167. if ( is_started() && ! is_complete() && force_unwind() )
  168. {
  169. flags_ |= flag_unwind_stack;
  170. flags_ |= flag_running;
  171. param_type to( unwind_t::force_unwind);
  172. caller_.jump(
  173. callee_,
  174. & to);
  175. flags_ &= ~flag_running;
  176. flags_ &= ~flag_unwind_stack;
  177. BOOST_ASSERT( is_complete() );
  178. }
  179. }
  180. void resume( R & arg) BOOST_NOEXCEPT
  181. {
  182. param_type to( & arg, this);
  183. resume_( & to);
  184. }
  185. R * yield()
  186. {
  187. BOOST_ASSERT( is_running() );
  188. BOOST_ASSERT( ! is_complete() );
  189. flags_ &= ~flag_running;
  190. param_type to;
  191. param_type * from(
  192. static_cast< param_type * >(
  193. callee_.jump(
  194. caller_,
  195. & to) ) );
  196. flags_ |= flag_running;
  197. if ( from->do_unwind) throw forced_unwind();
  198. BOOST_ASSERT( from->data);
  199. return from->data;
  200. }
  201. template< typename X >
  202. R * yield_to( symmetric_coroutine_impl< X > * other, X x)
  203. {
  204. typename symmetric_coroutine_impl< X >::param_type to( & x, other);
  205. return yield_to_( other, & to);
  206. }
  207. template< typename X >
  208. R * yield_to( symmetric_coroutine_impl< X & > * other, X & x)
  209. {
  210. typename symmetric_coroutine_impl< X & >::param_type to( & x, other);
  211. return yield_to_( other, & to);
  212. }
  213. template< typename X >
  214. R * yield_to( symmetric_coroutine_impl< X > * other)
  215. {
  216. typename symmetric_coroutine_impl< X >::param_type to( other);
  217. return yield_to_( other, & to);
  218. }
  219. virtual void run( R *) BOOST_NOEXCEPT = 0;
  220. virtual void destroy() = 0;
  221. protected:
  222. template< typename X >
  223. friend class symmetric_coroutine_impl;
  224. int flags_;
  225. coroutine_context caller_;
  226. coroutine_context callee_;
  227. void resume_( param_type * to) BOOST_NOEXCEPT
  228. {
  229. BOOST_ASSERT( ! is_running() );
  230. BOOST_ASSERT( ! is_complete() );
  231. flags_ |= flag_running;
  232. caller_.jump(
  233. callee_,
  234. to);
  235. flags_ &= ~flag_running;
  236. }
  237. template< typename Other >
  238. R * yield_to_( Other * other, typename Other::param_type * to)
  239. {
  240. BOOST_ASSERT( is_running() );
  241. BOOST_ASSERT( ! is_complete() );
  242. BOOST_ASSERT( ! other->is_running() );
  243. BOOST_ASSERT( ! other->is_complete() );
  244. other->caller_ = caller_;
  245. flags_ &= ~flag_running;
  246. param_type * from(
  247. static_cast< param_type * >(
  248. callee_.jump(
  249. other->callee_,
  250. to) ) );
  251. flags_ |= flag_running;
  252. if ( from->do_unwind) throw forced_unwind();
  253. BOOST_ASSERT( from->data);
  254. return from->data;
  255. }
  256. };
  257. template<>
  258. class symmetric_coroutine_impl< void > : private noncopyable
  259. {
  260. public:
  261. typedef parameters< void > param_type;
  262. symmetric_coroutine_impl( preallocated const& palloc,
  263. bool unwind) BOOST_NOEXCEPT :
  264. flags_( 0),
  265. caller_(),
  266. callee_( trampoline_void< symmetric_coroutine_impl< void > >, palloc)
  267. {
  268. if ( unwind) flags_ |= flag_force_unwind;
  269. }
  270. virtual ~symmetric_coroutine_impl() {}
  271. inline bool force_unwind() const BOOST_NOEXCEPT
  272. { return 0 != ( flags_ & flag_force_unwind); }
  273. inline bool unwind_requested() const BOOST_NOEXCEPT
  274. { return 0 != ( flags_ & flag_unwind_stack); }
  275. inline bool is_started() const BOOST_NOEXCEPT
  276. { return 0 != ( flags_ & flag_started); }
  277. inline bool is_running() const BOOST_NOEXCEPT
  278. { return 0 != ( flags_ & flag_running); }
  279. inline bool is_complete() const BOOST_NOEXCEPT
  280. { return 0 != ( flags_ & flag_complete); }
  281. inline void unwind_stack() BOOST_NOEXCEPT
  282. {
  283. if ( is_started() && ! is_complete() && force_unwind() )
  284. {
  285. flags_ |= flag_unwind_stack;
  286. flags_ |= flag_running;
  287. param_type to( unwind_t::force_unwind);
  288. caller_.jump(
  289. callee_,
  290. & to);
  291. flags_ &= ~flag_running;
  292. flags_ &= ~flag_unwind_stack;
  293. BOOST_ASSERT( is_complete() );
  294. }
  295. }
  296. inline void resume() BOOST_NOEXCEPT
  297. {
  298. BOOST_ASSERT( ! is_running() );
  299. BOOST_ASSERT( ! is_complete() );
  300. param_type to( this);
  301. flags_ |= flag_running;
  302. caller_.jump(
  303. callee_,
  304. & to);
  305. flags_ &= ~flag_running;
  306. }
  307. inline void yield()
  308. {
  309. BOOST_ASSERT( is_running() );
  310. BOOST_ASSERT( ! is_complete() );
  311. flags_ &= ~flag_running;
  312. param_type to;
  313. param_type * from(
  314. static_cast< param_type * >(
  315. callee_.jump(
  316. caller_,
  317. & to) ) );
  318. flags_ |= flag_running;
  319. if ( from->do_unwind) throw forced_unwind();
  320. }
  321. template< typename X >
  322. void yield_to( symmetric_coroutine_impl< X > * other, X x)
  323. {
  324. typename symmetric_coroutine_impl< X >::param_type to( & x, other);
  325. yield_to_( other, & to);
  326. }
  327. template< typename X >
  328. void yield_to( symmetric_coroutine_impl< X & > * other, X & x)
  329. {
  330. typename symmetric_coroutine_impl< X & >::param_type to( & x, other);
  331. yield_to_( other, & to);
  332. }
  333. template< typename X >
  334. void yield_to( symmetric_coroutine_impl< X > * other)
  335. {
  336. typename symmetric_coroutine_impl< X >::param_type to( other);
  337. yield_to_( other, & to);
  338. }
  339. virtual void run() BOOST_NOEXCEPT = 0;
  340. virtual void destroy() = 0;
  341. protected:
  342. template< typename X >
  343. friend class symmetric_coroutine_impl;
  344. int flags_;
  345. coroutine_context caller_;
  346. coroutine_context callee_;
  347. template< typename Other >
  348. void yield_to_( Other * other, typename Other::param_type * to)
  349. {
  350. BOOST_ASSERT( is_running() );
  351. BOOST_ASSERT( ! is_complete() );
  352. BOOST_ASSERT( ! other->is_running() );
  353. BOOST_ASSERT( ! other->is_complete() );
  354. other->caller_ = caller_;
  355. flags_ &= ~flag_running;
  356. param_type * from(
  357. static_cast< param_type * >(
  358. callee_.jump(
  359. other->callee_,
  360. to) ) );
  361. flags_ |= flag_running;
  362. if ( from->do_unwind) throw forced_unwind();
  363. }
  364. };
  365. }}}
  366. #ifdef BOOST_HAS_ABI_HEADERS
  367. # include BOOST_ABI_SUFFIX
  368. #endif
  369. #endif // BOOST_COROUTINES_DETAIL_SYMMETRIC_COROUTINE_IMPL_H