co_spawn.hpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. //
  2. // impl/co_spawn.hpp
  3. // ~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2021 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_CO_SPAWN_HPP
  11. #define BOOST_ASIO_IMPL_CO_SPAWN_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/awaitable.hpp>
  17. #include <boost/asio/dispatch.hpp>
  18. #include <boost/asio/execution/outstanding_work.hpp>
  19. #include <boost/asio/post.hpp>
  20. #include <boost/asio/prefer.hpp>
  21. #include <boost/asio/use_awaitable.hpp>
  22. #include <boost/asio/detail/push_options.hpp>
  23. namespace boost {
  24. namespace asio {
  25. namespace detail {
  26. template <typename Executor, typename = void>
  27. class co_spawn_work_guard
  28. {
  29. public:
  30. typedef typename decay<
  31. typename prefer_result<Executor,
  32. execution::outstanding_work_t::tracked_t
  33. >::type
  34. >::type executor_type;
  35. co_spawn_work_guard(const Executor& ex)
  36. : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
  37. {
  38. }
  39. executor_type get_executor() const BOOST_ASIO_NOEXCEPT
  40. {
  41. return executor_;
  42. }
  43. private:
  44. executor_type executor_;
  45. };
  46. #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
  47. template <typename Executor>
  48. struct co_spawn_work_guard<Executor,
  49. typename enable_if<
  50. !execution::is_executor<Executor>::value
  51. >::type> : executor_work_guard<Executor>
  52. {
  53. co_spawn_work_guard(const Executor& ex)
  54. : executor_work_guard<Executor>(ex)
  55. {
  56. }
  57. };
  58. #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
  59. template <typename Executor>
  60. inline co_spawn_work_guard<Executor>
  61. make_co_spawn_work_guard(const Executor& ex)
  62. {
  63. return co_spawn_work_guard<Executor>(ex);
  64. }
  65. template <typename T, typename Executor, typename F, typename Handler>
  66. awaitable<void, Executor> co_spawn_entry_point(
  67. awaitable<T, Executor>*, Executor ex, F f, Handler handler)
  68. {
  69. auto spawn_work = make_co_spawn_work_guard(ex);
  70. auto handler_work = make_co_spawn_work_guard(
  71. boost::asio::get_associated_executor(handler, ex));
  72. (void) co_await (post)(spawn_work.get_executor(),
  73. use_awaitable_t<Executor>{});
  74. bool done = false;
  75. try
  76. {
  77. T t = co_await f();
  78. done = true;
  79. (dispatch)(handler_work.get_executor(),
  80. [handler = std::move(handler), t = std::move(t)]() mutable
  81. {
  82. handler(std::exception_ptr(), std::move(t));
  83. });
  84. }
  85. catch (...)
  86. {
  87. if (done)
  88. throw;
  89. (dispatch)(handler_work.get_executor(),
  90. [handler = std::move(handler), e = std::current_exception()]() mutable
  91. {
  92. handler(e, T());
  93. });
  94. }
  95. }
  96. template <typename Executor, typename F, typename Handler>
  97. awaitable<void, Executor> co_spawn_entry_point(
  98. awaitable<void, Executor>*, Executor ex, F f, Handler handler)
  99. {
  100. auto spawn_work = make_co_spawn_work_guard(ex);
  101. auto handler_work = make_co_spawn_work_guard(
  102. boost::asio::get_associated_executor(handler, ex));
  103. (void) co_await (post)(spawn_work.get_executor(),
  104. use_awaitable_t<Executor>{__FILE__, __LINE__, "co_spawn_entry_point"});
  105. std::exception_ptr e = nullptr;
  106. try
  107. {
  108. co_await f();
  109. }
  110. catch (...)
  111. {
  112. e = std::current_exception();
  113. }
  114. (dispatch)(handler_work.get_executor(),
  115. [handler = std::move(handler), e]() mutable
  116. {
  117. handler(e);
  118. });
  119. }
  120. template <typename T, typename Executor>
  121. class awaitable_as_function
  122. {
  123. public:
  124. explicit awaitable_as_function(awaitable<T, Executor>&& a)
  125. : awaitable_(std::move(a))
  126. {
  127. }
  128. awaitable<T, Executor> operator()()
  129. {
  130. return std::move(awaitable_);
  131. }
  132. private:
  133. awaitable<T, Executor> awaitable_;
  134. };
  135. template <typename Executor>
  136. class initiate_co_spawn
  137. {
  138. public:
  139. typedef Executor executor_type;
  140. template <typename OtherExecutor>
  141. explicit initiate_co_spawn(const OtherExecutor& ex)
  142. : ex_(ex)
  143. {
  144. }
  145. executor_type get_executor() const BOOST_ASIO_NOEXCEPT
  146. {
  147. return ex_;
  148. }
  149. template <typename Handler, typename F>
  150. void operator()(Handler&& handler, F&& f) const
  151. {
  152. typedef typename result_of<F()>::type awaitable_type;
  153. auto a = (co_spawn_entry_point)(static_cast<awaitable_type*>(nullptr),
  154. ex_, std::forward<F>(f), std::forward<Handler>(handler));
  155. awaitable_handler<executor_type, void>(std::move(a), ex_).launch();
  156. }
  157. private:
  158. Executor ex_;
  159. };
  160. } // namespace detail
  161. template <typename Executor, typename T, typename AwaitableExecutor,
  162. BOOST_ASIO_COMPLETION_TOKEN_FOR(
  163. void(std::exception_ptr, T)) CompletionToken>
  164. inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
  165. CompletionToken, void(std::exception_ptr, T))
  166. co_spawn(const Executor& ex,
  167. awaitable<T, AwaitableExecutor> a, CompletionToken&& token,
  168. typename constraint<
  169. (is_executor<Executor>::value || execution::is_executor<Executor>::value)
  170. && is_convertible<Executor, AwaitableExecutor>::value
  171. >::type)
  172. {
  173. return async_initiate<CompletionToken, void(std::exception_ptr, T)>(
  174. detail::initiate_co_spawn<AwaitableExecutor>(AwaitableExecutor(ex)),
  175. token, detail::awaitable_as_function<T, AwaitableExecutor>(std::move(a)));
  176. }
  177. template <typename Executor, typename AwaitableExecutor,
  178. BOOST_ASIO_COMPLETION_TOKEN_FOR(
  179. void(std::exception_ptr)) CompletionToken>
  180. inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
  181. CompletionToken, void(std::exception_ptr))
  182. co_spawn(const Executor& ex,
  183. awaitable<void, AwaitableExecutor> a, CompletionToken&& token,
  184. typename constraint<
  185. (is_executor<Executor>::value || execution::is_executor<Executor>::value)
  186. && is_convertible<Executor, AwaitableExecutor>::value
  187. >::type)
  188. {
  189. return async_initiate<CompletionToken, void(std::exception_ptr)>(
  190. detail::initiate_co_spawn<AwaitableExecutor>(AwaitableExecutor(ex)),
  191. token, detail::awaitable_as_function<
  192. void, AwaitableExecutor>(std::move(a)));
  193. }
  194. template <typename ExecutionContext, typename T, typename AwaitableExecutor,
  195. BOOST_ASIO_COMPLETION_TOKEN_FOR(
  196. void(std::exception_ptr, T)) CompletionToken>
  197. inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
  198. CompletionToken, void(std::exception_ptr, T))
  199. co_spawn(ExecutionContext& ctx,
  200. awaitable<T, AwaitableExecutor> a, CompletionToken&& token,
  201. typename constraint<
  202. is_convertible<ExecutionContext&, execution_context&>::value
  203. && is_convertible<typename ExecutionContext::executor_type,
  204. AwaitableExecutor>::value
  205. >::type)
  206. {
  207. return (co_spawn)(ctx.get_executor(), std::move(a),
  208. std::forward<CompletionToken>(token));
  209. }
  210. template <typename ExecutionContext, typename AwaitableExecutor,
  211. BOOST_ASIO_COMPLETION_TOKEN_FOR(
  212. void(std::exception_ptr)) CompletionToken>
  213. inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
  214. CompletionToken, void(std::exception_ptr))
  215. co_spawn(ExecutionContext& ctx,
  216. awaitable<void, AwaitableExecutor> a, CompletionToken&& token,
  217. typename constraint<
  218. is_convertible<ExecutionContext&, execution_context&>::value
  219. && is_convertible<typename ExecutionContext::executor_type,
  220. AwaitableExecutor>::value
  221. >::type)
  222. {
  223. return (co_spawn)(ctx.get_executor(), std::move(a),
  224. std::forward<CompletionToken>(token));
  225. }
  226. template <typename Executor, typename F,
  227. BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<
  228. typename result_of<F()>::type>::type) CompletionToken>
  229. inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
  230. typename detail::awaitable_signature<typename result_of<F()>::type>::type)
  231. co_spawn(const Executor& ex, F&& f, CompletionToken&& token,
  232. typename constraint<
  233. is_executor<Executor>::value || execution::is_executor<Executor>::value
  234. >::type)
  235. {
  236. return async_initiate<CompletionToken,
  237. typename detail::awaitable_signature<typename result_of<F()>::type>::type>(
  238. detail::initiate_co_spawn<
  239. typename result_of<F()>::type::executor_type>(ex),
  240. token, std::forward<F>(f));
  241. }
  242. template <typename ExecutionContext, typename F,
  243. BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<
  244. typename result_of<F()>::type>::type) CompletionToken>
  245. inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
  246. typename detail::awaitable_signature<typename result_of<F()>::type>::type)
  247. co_spawn(ExecutionContext& ctx, F&& f, CompletionToken&& token,
  248. typename constraint<
  249. is_convertible<ExecutionContext&, execution_context&>::value
  250. >::type)
  251. {
  252. return (co_spawn)(ctx.get_executor(), std::forward<F>(f),
  253. std::forward<CompletionToken>(token));
  254. }
  255. } // namespace asio
  256. } // namespace boost
  257. #include <boost/asio/detail/pop_options.hpp>
  258. #endif // BOOST_ASIO_IMPL_CO_SPAWN_HPP