基于C++ Coroutines提案 ‘Stackless Resumable Functions’编写的协程库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

state.cpp 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. #include "librf/librf.h"
  2. namespace librf
  3. {
  4. LIBRF_API state_base_t::~state_base_t()
  5. {
  6. }
  7. LIBRF_API void state_base_t::destroy_deallocate()
  8. {
  9. delete this;
  10. }
  11. LIBRF_API void state_base_t::resume()
  12. {
  13. if (likely(_coro))
  14. {
  15. coroutine_handle<> handler = _coro;
  16. _coro = nullptr;
  17. _scheduler->del_final(this);
  18. handler.resume();
  19. }
  20. }
  21. LIBRF_API bool state_base_t::has_handler() const noexcept
  22. {
  23. return (bool)_coro;
  24. }
  25. LIBRF_API state_base_t* state_base_t::get_parent() const noexcept
  26. {
  27. return nullptr;
  28. }
  29. LIBRF_API void state_future_t::destroy_deallocate()
  30. {
  31. size_t _Size = this->_alloc_size;
  32. #if RESUMEF_DEBUG_COUNTER
  33. std::cout << "destroy_deallocate, size=" << _Size << std::endl;
  34. #endif
  35. this->~state_future_t();
  36. _Alloc_char _Al;
  37. return _Al.deallocate(reinterpret_cast<char*>(this), _Size);
  38. }
  39. LIBRF_API state_generator_t* state_generator_t::_Alloc_state()
  40. {
  41. _Alloc_char _Al;
  42. size_t _Size = _Align_size<state_generator_t>();
  43. #if RESUMEF_DEBUG_COUNTER
  44. std::cout << "state_generator_t::alloc, size=" << sizeof(state_generator_t) << std::endl;
  45. #endif
  46. char* _Ptr = _Al.allocate(_Size);
  47. return new(_Ptr) state_generator_t();
  48. }
  49. LIBRF_API void state_generator_t::destroy_deallocate()
  50. {
  51. size_t _Size = _Align_size<state_generator_t>();
  52. #if RESUMEF_DEBUG_COUNTER
  53. std::cout << "destroy_deallocate, size=" << _Size << std::endl;
  54. #endif
  55. this->~state_generator_t();
  56. _Alloc_char _Al;
  57. return _Al.deallocate(reinterpret_cast<char*>(this), _Size);
  58. }
  59. LIBRF_API void state_generator_t::resume()
  60. {
  61. if (likely(_coro))
  62. {
  63. _coro.resume();
  64. if (likely(!_coro.done()))
  65. {
  66. _scheduler->add_generator(this);
  67. }
  68. else
  69. {
  70. coroutine_handle<> handler = _coro;
  71. _coro = nullptr;
  72. _scheduler->del_final(this);
  73. handler.destroy();
  74. }
  75. }
  76. }
  77. LIBRF_API bool state_generator_t::has_handler() const noexcept
  78. {
  79. return (bool)_coro;
  80. }
  81. LIBRF_API bool state_generator_t::switch_scheduler_await_suspend(scheduler_t* sch)
  82. {
  83. assert(sch != nullptr);
  84. if (_scheduler != nullptr)
  85. {
  86. if (_scheduler == sch) return false;
  87. auto task_ptr = _scheduler->del_switch(this);
  88. _scheduler = sch;
  89. if (task_ptr != nullptr)
  90. sch->add_switch(std::move(task_ptr));
  91. }
  92. else
  93. {
  94. _scheduler = sch;
  95. }
  96. return true;
  97. }
  98. LIBRF_API state_base_t* state_future_t::get_parent() const noexcept
  99. {
  100. return _parent;
  101. }
  102. LIBRF_API void state_future_t::resume()
  103. {
  104. std::unique_lock<lock_type> __guard(_mtx);
  105. if (_is_initor == initor_type::Initial)
  106. {
  107. assert((bool)_initor);
  108. coroutine_handle<> handler = _initor;
  109. _is_initor = initor_type::None;
  110. __guard.unlock();
  111. handler.resume();
  112. return;
  113. }
  114. if (_coro)
  115. {
  116. coroutine_handle<> handler = _coro;
  117. _coro = nullptr;
  118. __guard.unlock();
  119. handler.resume();
  120. return;
  121. }
  122. if (_is_initor == initor_type::Final)
  123. {
  124. assert((bool)_initor);
  125. coroutine_handle<> handler = _initor;
  126. _is_initor = initor_type::None;
  127. __guard.unlock();
  128. handler.destroy();
  129. return;
  130. }
  131. }
  132. LIBRF_API bool state_future_t::has_handler() const noexcept
  133. {
  134. scoped_lock<lock_type> __guard(this->_mtx);
  135. return has_handler_skip_lock();
  136. }
  137. LIBRF_API bool state_future_t::switch_scheduler_await_suspend(scheduler_t* sch)
  138. {
  139. assert(sch != nullptr);
  140. scoped_lock<lock_type> __guard(this->_mtx);
  141. if (_scheduler != nullptr)
  142. {
  143. if (_scheduler == sch) return false;
  144. auto task_ptr = _scheduler->del_switch(this);
  145. _scheduler = sch;
  146. if (task_ptr != nullptr)
  147. sch->add_switch(std::move(task_ptr));
  148. }
  149. else
  150. {
  151. _scheduler = sch;
  152. }
  153. if (_parent != nullptr)
  154. _parent->switch_scheduler_await_suspend(sch);
  155. return true;
  156. }
  157. LIBRF_API void state_t<void>::future_await_resume()
  158. {
  159. scoped_lock<lock_type> __guard(this->_mtx);
  160. if (this->_exception)
  161. std::rethrow_exception(std::move(this->_exception));
  162. if (this->_has_value.load(std::memory_order_acquire) == result_type::None)
  163. std::rethrow_exception(std::make_exception_ptr(future_exception{error_code::not_ready}));
  164. }
  165. LIBRF_API void state_t<void>::set_value()
  166. {
  167. scoped_lock<lock_type> __guard(this->_mtx);
  168. this->_has_value.store(result_type::Value, std::memory_order_release);
  169. scheduler_t* sch = this->get_scheduler();
  170. if (sch != nullptr)
  171. {
  172. if (this->has_handler_skip_lock())
  173. sch->add_generator(this);
  174. else
  175. sch->del_final(this);
  176. }
  177. }
  178. LIBRF_API void state_t<void>::set_exception(std::exception_ptr e)
  179. {
  180. scoped_lock<lock_type> __guard(this->_mtx);
  181. this->_exception = std::move(e);
  182. scheduler_t* sch = this->get_scheduler();
  183. if (sch != nullptr)
  184. {
  185. if (this->has_handler_skip_lock())
  186. sch->add_generator(this);
  187. else
  188. sch->del_final(this);
  189. }
  190. }
  191. }