use_awaitable.hpp 8.0 KB

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