Audio plugin host https://kx.studio/carla
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.

awaitable.hpp 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. //
  2. // impl/awaitable.hpp
  3. // ~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #ifndef ASIO_IMPL_AWAITABLE_HPP
  11. #define ASIO_IMPL_AWAITABLE_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include "asio/detail/config.hpp"
  16. #include <exception>
  17. #include <new>
  18. #include <tuple>
  19. #include <utility>
  20. #include "asio/detail/thread_context.hpp"
  21. #include "asio/detail/thread_info_base.hpp"
  22. #include "asio/detail/type_traits.hpp"
  23. #include "asio/post.hpp"
  24. #include "asio/system_error.hpp"
  25. #include "asio/this_coro.hpp"
  26. #include "asio/detail/push_options.hpp"
  27. namespace asio {
  28. namespace detail {
  29. // An awaitable_thread represents a thread-of-execution that is composed of one
  30. // or more "stack frames", with each frame represented by an awaitable_frame.
  31. // All execution occurs in the context of the awaitable_thread's executor. An
  32. // awaitable_thread continues to "pump" the stack frames by repeatedly resuming
  33. // the top stack frame until the stack is empty, or until ownership of the
  34. // stack is transferred to another awaitable_thread object.
  35. //
  36. // +------------------------------------+
  37. // | top_of_stack_ |
  38. // | V
  39. // +--------------+---+ +-----------------+
  40. // | | | |
  41. // | awaitable_thread |<---------------------------+ awaitable_frame |
  42. // | | attached_thread_ | |
  43. // +--------------+---+ (Set only when +---+-------------+
  44. // | frames are being |
  45. // | actively pumped | caller_
  46. // | by a thread, and |
  47. // | then only for V
  48. // | the top frame.) +-----------------+
  49. // | | |
  50. // | | awaitable_frame |
  51. // | | |
  52. // | +---+-------------+
  53. // | |
  54. // | | caller_
  55. // | :
  56. // | :
  57. // | |
  58. // | V
  59. // | +-----------------+
  60. // | bottom_of_stack_ | |
  61. // +------------------------------->| awaitable_frame |
  62. // | |
  63. // +-----------------+
  64. template <typename Executor>
  65. class awaitable_frame_base
  66. {
  67. public:
  68. #if !defined(ASIO_DISABLE_AWAITABLE_FRAME_RECYCLING)
  69. void* operator new(std::size_t size)
  70. {
  71. return asio::detail::thread_info_base::allocate(
  72. asio::detail::thread_info_base::awaitable_frame_tag(),
  73. asio::detail::thread_context::thread_call_stack::top(),
  74. size);
  75. }
  76. void operator delete(void* pointer, std::size_t size)
  77. {
  78. asio::detail::thread_info_base::deallocate(
  79. asio::detail::thread_info_base::awaitable_frame_tag(),
  80. asio::detail::thread_context::thread_call_stack::top(),
  81. pointer, size);
  82. }
  83. #endif // !defined(ASIO_DISABLE_AWAITABLE_FRAME_RECYCLING)
  84. // The frame starts in a suspended state until the awaitable_thread object
  85. // pumps the stack.
  86. auto initial_suspend() noexcept
  87. {
  88. return suspend_always();
  89. }
  90. // On final suspension the frame is popped from the top of the stack.
  91. auto final_suspend() noexcept
  92. {
  93. struct result
  94. {
  95. awaitable_frame_base* this_;
  96. bool await_ready() const noexcept
  97. {
  98. return false;
  99. }
  100. void await_suspend(coroutine_handle<void>) noexcept
  101. {
  102. this_->pop_frame();
  103. }
  104. void await_resume() const noexcept
  105. {
  106. }
  107. };
  108. return result{this};
  109. }
  110. void set_except(std::exception_ptr e) noexcept
  111. {
  112. pending_exception_ = e;
  113. }
  114. void set_error(const asio::error_code& ec)
  115. {
  116. this->set_except(std::make_exception_ptr(asio::system_error(ec)));
  117. }
  118. void unhandled_exception()
  119. {
  120. set_except(std::current_exception());
  121. }
  122. void rethrow_exception()
  123. {
  124. if (pending_exception_)
  125. {
  126. std::exception_ptr ex = std::exchange(pending_exception_, nullptr);
  127. std::rethrow_exception(ex);
  128. }
  129. }
  130. template <typename T>
  131. auto await_transform(awaitable<T, Executor> a) const
  132. {
  133. return a;
  134. }
  135. // This await transformation obtains the associated executor of the thread of
  136. // execution.
  137. auto await_transform(this_coro::executor_t) noexcept
  138. {
  139. struct result
  140. {
  141. awaitable_frame_base* this_;
  142. bool await_ready() const noexcept
  143. {
  144. return true;
  145. }
  146. void await_suspend(coroutine_handle<void>) noexcept
  147. {
  148. }
  149. auto await_resume() const noexcept
  150. {
  151. return this_->attached_thread_->get_executor();
  152. }
  153. };
  154. return result{this};
  155. }
  156. // This await transformation is used to run an async operation's initiation
  157. // function object after the coroutine has been suspended. This ensures that
  158. // immediate resumption of the coroutine in another thread does not cause a
  159. // race condition.
  160. template <typename Function>
  161. auto await_transform(Function f,
  162. typename enable_if<
  163. is_convertible<
  164. typename result_of<Function(awaitable_frame_base*)>::type,
  165. awaitable_thread<Executor>*
  166. >::value
  167. >::type* = 0)
  168. {
  169. struct result
  170. {
  171. Function function_;
  172. awaitable_frame_base* this_;
  173. bool await_ready() const noexcept
  174. {
  175. return false;
  176. }
  177. void await_suspend(coroutine_handle<void>) noexcept
  178. {
  179. function_(this_);
  180. }
  181. void await_resume() const noexcept
  182. {
  183. }
  184. };
  185. return result{std::move(f), this};
  186. }
  187. void attach_thread(awaitable_thread<Executor>* handler) noexcept
  188. {
  189. attached_thread_ = handler;
  190. }
  191. awaitable_thread<Executor>* detach_thread() noexcept
  192. {
  193. return std::exchange(attached_thread_, nullptr);
  194. }
  195. void push_frame(awaitable_frame_base<Executor>* caller) noexcept
  196. {
  197. caller_ = caller;
  198. attached_thread_ = caller_->attached_thread_;
  199. attached_thread_->top_of_stack_ = this;
  200. caller_->attached_thread_ = nullptr;
  201. }
  202. void pop_frame() noexcept
  203. {
  204. if (caller_)
  205. caller_->attached_thread_ = attached_thread_;
  206. attached_thread_->top_of_stack_ = caller_;
  207. attached_thread_ = nullptr;
  208. caller_ = nullptr;
  209. }
  210. void resume()
  211. {
  212. coro_.resume();
  213. }
  214. void destroy()
  215. {
  216. coro_.destroy();
  217. }
  218. protected:
  219. coroutine_handle<void> coro_ = nullptr;
  220. awaitable_thread<Executor>* attached_thread_ = nullptr;
  221. awaitable_frame_base<Executor>* caller_ = nullptr;
  222. std::exception_ptr pending_exception_ = nullptr;
  223. };
  224. template <typename T, typename Executor>
  225. class awaitable_frame
  226. : public awaitable_frame_base<Executor>
  227. {
  228. public:
  229. awaitable_frame() noexcept
  230. {
  231. }
  232. awaitable_frame(awaitable_frame&& other) noexcept
  233. : awaitable_frame_base<Executor>(std::move(other))
  234. {
  235. }
  236. ~awaitable_frame()
  237. {
  238. if (has_result_)
  239. static_cast<T*>(static_cast<void*>(result_))->~T();
  240. }
  241. awaitable<T, Executor> get_return_object() noexcept
  242. {
  243. this->coro_ = coroutine_handle<awaitable_frame>::from_promise(*this);
  244. return awaitable<T, Executor>(this);
  245. };
  246. template <typename U>
  247. void return_value(U&& u)
  248. {
  249. new (&result_) T(std::forward<U>(u));
  250. has_result_ = true;
  251. }
  252. template <typename... Us>
  253. void return_values(Us&&... us)
  254. {
  255. this->return_value(std::forward_as_tuple(std::forward<Us>(us)...));
  256. }
  257. T get()
  258. {
  259. this->caller_ = nullptr;
  260. this->rethrow_exception();
  261. return std::move(*static_cast<T*>(static_cast<void*>(result_)));
  262. }
  263. private:
  264. alignas(T) unsigned char result_[sizeof(T)];
  265. bool has_result_ = false;
  266. };
  267. template <typename Executor>
  268. class awaitable_frame<void, Executor>
  269. : public awaitable_frame_base<Executor>
  270. {
  271. public:
  272. awaitable<void, Executor> get_return_object()
  273. {
  274. this->coro_ = coroutine_handle<awaitable_frame>::from_promise(*this);
  275. return awaitable<void, Executor>(this);
  276. };
  277. void return_void()
  278. {
  279. }
  280. void get()
  281. {
  282. this->caller_ = nullptr;
  283. this->rethrow_exception();
  284. }
  285. };
  286. template <typename Executor>
  287. class awaitable_thread
  288. {
  289. public:
  290. typedef Executor executor_type;
  291. // Construct from the entry point of a new thread of execution.
  292. awaitable_thread(awaitable<void, Executor> p, const Executor& ex)
  293. : bottom_of_stack_(std::move(p)),
  294. top_of_stack_(bottom_of_stack_.frame_),
  295. executor_(ex)
  296. {
  297. }
  298. // Transfer ownership from another awaitable_thread.
  299. awaitable_thread(awaitable_thread&& other) noexcept
  300. : bottom_of_stack_(std::move(other.bottom_of_stack_)),
  301. top_of_stack_(std::exchange(other.top_of_stack_, nullptr)),
  302. executor_(std::move(other.executor_))
  303. {
  304. }
  305. // Clean up with a last ditch effort to ensure the thread is unwound within
  306. // the context of the executor.
  307. ~awaitable_thread()
  308. {
  309. if (bottom_of_stack_.valid())
  310. {
  311. // Coroutine "stack unwinding" must be performed through the executor.
  312. (post)(executor_,
  313. [a = std::move(bottom_of_stack_)]() mutable
  314. {
  315. awaitable<void, Executor>(std::move(a));
  316. });
  317. }
  318. }
  319. executor_type get_executor() const noexcept
  320. {
  321. return executor_;
  322. }
  323. // Launch a new thread of execution.
  324. void launch()
  325. {
  326. top_of_stack_->attach_thread(this);
  327. pump();
  328. }
  329. protected:
  330. template <typename> friend class awaitable_frame_base;
  331. // Repeatedly resume the top stack frame until the stack is empty or until it
  332. // has been transferred to another resumable_thread object.
  333. void pump()
  334. {
  335. do top_of_stack_->resume(); while (top_of_stack_);
  336. if (bottom_of_stack_.valid())
  337. {
  338. awaitable<void, Executor> a(std::move(bottom_of_stack_));
  339. a.frame_->rethrow_exception();
  340. }
  341. }
  342. awaitable<void, Executor> bottom_of_stack_;
  343. awaitable_frame_base<Executor>* top_of_stack_;
  344. executor_type executor_;
  345. };
  346. } // namespace detail
  347. } // namespace asio
  348. #if !defined(GENERATING_DOCUMENTATION)
  349. namespace std { namespace experimental {
  350. template <typename T, typename Executor, typename... Args>
  351. struct coroutine_traits<asio::awaitable<T, Executor>, Args...>
  352. {
  353. typedef asio::detail::awaitable_frame<T, Executor> promise_type;
  354. };
  355. }} // namespace std::experimental
  356. #endif // !defined(GENERATING_DOCUMENTATION)
  357. #include "asio/detail/pop_options.hpp"
  358. #endif // ASIO_IMPL_AWAITABLE_HPP