use_awaitable.hpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. //
  2. // impl/use_awaitable.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2023 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_USE_AWAITABLE_HPP
  11. #define ASIO_IMPL_USE_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 "asio/async_result.hpp"
  17. #include "asio/cancellation_signal.hpp"
  18. #include "asio/detail/push_options.hpp"
  19. namespace asio {
  20. namespace detail {
  21. template <typename Executor, typename T>
  22. class awaitable_handler_base
  23. : public awaitable_thread<Executor>
  24. {
  25. public:
  26. typedef void result_type;
  27. typedef awaitable<T, Executor> awaitable_type;
  28. // Construct from the entry point of a new thread of execution.
  29. awaitable_handler_base(awaitable<awaitable_thread_entry_point, Executor> a,
  30. const Executor& ex, cancellation_slot pcs, cancellation_state cs)
  31. : awaitable_thread<Executor>(std::move(a), ex, pcs, cs)
  32. {
  33. }
  34. // Transfer ownership from another awaitable_thread.
  35. explicit awaitable_handler_base(awaitable_thread<Executor>* h)
  36. : awaitable_thread<Executor>(std::move(*h))
  37. {
  38. }
  39. protected:
  40. awaitable_frame<T, Executor>* frame() noexcept
  41. {
  42. return static_cast<awaitable_frame<T, Executor>*>(
  43. this->entry_point()->top_of_stack_);
  44. }
  45. };
  46. template <typename, typename...>
  47. class awaitable_handler;
  48. template <typename Executor>
  49. class awaitable_handler<Executor>
  50. : public awaitable_handler_base<Executor, void>
  51. {
  52. public:
  53. using awaitable_handler_base<Executor, void>::awaitable_handler_base;
  54. void operator()()
  55. {
  56. this->frame()->attach_thread(this);
  57. this->frame()->return_void();
  58. this->frame()->clear_cancellation_slot();
  59. this->frame()->pop_frame();
  60. this->pump();
  61. }
  62. };
  63. template <typename Executor>
  64. class awaitable_handler<Executor, asio::error_code>
  65. : public awaitable_handler_base<Executor, void>
  66. {
  67. public:
  68. using awaitable_handler_base<Executor, void>::awaitable_handler_base;
  69. void operator()(const asio::error_code& ec)
  70. {
  71. this->frame()->attach_thread(this);
  72. if (ec)
  73. this->frame()->set_error(ec);
  74. else
  75. this->frame()->return_void();
  76. this->frame()->clear_cancellation_slot();
  77. this->frame()->pop_frame();
  78. this->pump();
  79. }
  80. };
  81. template <typename Executor>
  82. class awaitable_handler<Executor, std::exception_ptr>
  83. : public awaitable_handler_base<Executor, void>
  84. {
  85. public:
  86. using awaitable_handler_base<Executor, void>::awaitable_handler_base;
  87. void operator()(std::exception_ptr ex)
  88. {
  89. this->frame()->attach_thread(this);
  90. if (ex)
  91. this->frame()->set_except(ex);
  92. else
  93. this->frame()->return_void();
  94. this->frame()->clear_cancellation_slot();
  95. this->frame()->pop_frame();
  96. this->pump();
  97. }
  98. };
  99. template <typename Executor, typename T>
  100. class awaitable_handler<Executor, T>
  101. : public awaitable_handler_base<Executor, T>
  102. {
  103. public:
  104. using awaitable_handler_base<Executor, T>::awaitable_handler_base;
  105. template <typename Arg>
  106. void operator()(Arg&& arg)
  107. {
  108. this->frame()->attach_thread(this);
  109. this->frame()->return_value(std::forward<Arg>(arg));
  110. this->frame()->clear_cancellation_slot();
  111. this->frame()->pop_frame();
  112. this->pump();
  113. }
  114. };
  115. template <typename Executor, typename T>
  116. class awaitable_handler<Executor, asio::error_code, T>
  117. : public awaitable_handler_base<Executor, T>
  118. {
  119. public:
  120. using awaitable_handler_base<Executor, T>::awaitable_handler_base;
  121. template <typename Arg>
  122. void operator()(const asio::error_code& ec, Arg&& arg)
  123. {
  124. this->frame()->attach_thread(this);
  125. if (ec)
  126. this->frame()->set_error(ec);
  127. else
  128. this->frame()->return_value(std::forward<Arg>(arg));
  129. this->frame()->clear_cancellation_slot();
  130. this->frame()->pop_frame();
  131. this->pump();
  132. }
  133. };
  134. template <typename Executor, typename T>
  135. class awaitable_handler<Executor, std::exception_ptr, T>
  136. : public awaitable_handler_base<Executor, T>
  137. {
  138. public:
  139. using awaitable_handler_base<Executor, T>::awaitable_handler_base;
  140. template <typename Arg>
  141. void operator()(std::exception_ptr ex, Arg&& arg)
  142. {
  143. this->frame()->attach_thread(this);
  144. if (ex)
  145. this->frame()->set_except(ex);
  146. else
  147. this->frame()->return_value(std::forward<Arg>(arg));
  148. this->frame()->clear_cancellation_slot();
  149. this->frame()->pop_frame();
  150. this->pump();
  151. }
  152. };
  153. template <typename Executor, typename... Ts>
  154. class awaitable_handler
  155. : public awaitable_handler_base<Executor, std::tuple<Ts...>>
  156. {
  157. public:
  158. using awaitable_handler_base<Executor,
  159. std::tuple<Ts...>>::awaitable_handler_base;
  160. template <typename... Args>
  161. void operator()(Args&&... args)
  162. {
  163. this->frame()->attach_thread(this);
  164. this->frame()->return_values(std::forward<Args>(args)...);
  165. this->frame()->clear_cancellation_slot();
  166. this->frame()->pop_frame();
  167. this->pump();
  168. }
  169. };
  170. template <typename Executor, typename... Ts>
  171. class awaitable_handler<Executor, asio::error_code, Ts...>
  172. : public awaitable_handler_base<Executor, std::tuple<Ts...>>
  173. {
  174. public:
  175. using awaitable_handler_base<Executor,
  176. std::tuple<Ts...>>::awaitable_handler_base;
  177. template <typename... Args>
  178. void operator()(const asio::error_code& ec, Args&&... args)
  179. {
  180. this->frame()->attach_thread(this);
  181. if (ec)
  182. this->frame()->set_error(ec);
  183. else
  184. this->frame()->return_values(std::forward<Args>(args)...);
  185. this->frame()->clear_cancellation_slot();
  186. this->frame()->pop_frame();
  187. this->pump();
  188. }
  189. };
  190. template <typename Executor, typename... Ts>
  191. class awaitable_handler<Executor, std::exception_ptr, Ts...>
  192. : public awaitable_handler_base<Executor, std::tuple<Ts...>>
  193. {
  194. public:
  195. using awaitable_handler_base<Executor,
  196. std::tuple<Ts...>>::awaitable_handler_base;
  197. template <typename... Args>
  198. void operator()(std::exception_ptr ex, Args&&... args)
  199. {
  200. this->frame()->attach_thread(this);
  201. if (ex)
  202. this->frame()->set_except(ex);
  203. else
  204. this->frame()->return_values(std::forward<Args>(args)...);
  205. this->frame()->clear_cancellation_slot();
  206. this->frame()->pop_frame();
  207. this->pump();
  208. }
  209. };
  210. } // namespace detail
  211. #if !defined(GENERATING_DOCUMENTATION)
  212. #if defined(_MSC_VER)
  213. template <typename T>
  214. T dummy_return()
  215. {
  216. return std::move(*static_cast<T*>(nullptr));
  217. }
  218. template <>
  219. inline void dummy_return()
  220. {
  221. }
  222. #endif // defined(_MSC_VER)
  223. template <typename Executor, typename R, typename... Args>
  224. class async_result<use_awaitable_t<Executor>, R(Args...)>
  225. {
  226. public:
  227. typedef typename detail::awaitable_handler<
  228. Executor, decay_t<Args>...> handler_type;
  229. typedef typename handler_type::awaitable_type return_type;
  230. template <typename Initiation, typename... InitArgs>
  231. #if defined(__APPLE_CC__) && (__clang_major__ == 13)
  232. __attribute__((noinline))
  233. #endif // defined(__APPLE_CC__) && (__clang_major__ == 13)
  234. static handler_type* do_init(
  235. detail::awaitable_frame_base<Executor>* frame, Initiation& initiation,
  236. use_awaitable_t<Executor> u, InitArgs&... args)
  237. {
  238. (void)u;
  239. ASIO_HANDLER_LOCATION((u.file_name_, u.line_, u.function_name_));
  240. handler_type handler(frame->detach_thread());
  241. std::move(initiation)(std::move(handler), std::move(args)...);
  242. return nullptr;
  243. }
  244. template <typename Initiation, typename... InitArgs>
  245. static return_type initiate(Initiation initiation,
  246. use_awaitable_t<Executor> u, InitArgs... args)
  247. {
  248. co_await [&] (auto* frame)
  249. {
  250. return do_init(frame, initiation, u, args...);
  251. };
  252. for (;;) {} // Never reached.
  253. #if defined(_MSC_VER)
  254. co_return dummy_return<typename return_type::value_type>();
  255. #endif // defined(_MSC_VER)
  256. }
  257. };
  258. #endif // !defined(GENERATING_DOCUMENTATION)
  259. } // namespace asio
  260. #include "asio/detail/pop_options.hpp"
  261. #endif // ASIO_IMPL_USE_AWAITABLE_HPP