spawn.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. //
  2. // impl/spawn.hpp
  3. // ~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2018 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_SPAWN_HPP
  11. #define ASIO_IMPL_SPAWN_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/associated_allocator.hpp"
  17. #include "asio/associated_executor.hpp"
  18. #include "asio/async_result.hpp"
  19. #include "asio/bind_executor.hpp"
  20. #include "asio/detail/atomic_count.hpp"
  21. #include "asio/detail/handler_alloc_helpers.hpp"
  22. #include "asio/detail/handler_cont_helpers.hpp"
  23. #include "asio/detail/handler_invoke_helpers.hpp"
  24. #include "asio/detail/memory.hpp"
  25. #include "asio/detail/noncopyable.hpp"
  26. #include "asio/detail/type_traits.hpp"
  27. #include "asio/system_error.hpp"
  28. #include "asio/detail/push_options.hpp"
  29. namespace asio {
  30. namespace detail {
  31. template <typename Handler, typename T>
  32. class coro_handler
  33. {
  34. public:
  35. coro_handler(basic_yield_context<Handler> ctx)
  36. : coro_(ctx.coro_.lock()),
  37. ca_(ctx.ca_),
  38. handler_(ctx.handler_),
  39. ready_(0),
  40. ec_(ctx.ec_),
  41. value_(0)
  42. {
  43. }
  44. void operator()(T value)
  45. {
  46. *ec_ = asio::error_code();
  47. *value_ = ASIO_MOVE_CAST(T)(value);
  48. if (--*ready_ == 0)
  49. (*coro_)();
  50. }
  51. void operator()(asio::error_code ec, T value)
  52. {
  53. *ec_ = ec;
  54. *value_ = ASIO_MOVE_CAST(T)(value);
  55. if (--*ready_ == 0)
  56. (*coro_)();
  57. }
  58. //private:
  59. shared_ptr<typename basic_yield_context<Handler>::callee_type> coro_;
  60. typename basic_yield_context<Handler>::caller_type& ca_;
  61. Handler handler_;
  62. atomic_count* ready_;
  63. asio::error_code* ec_;
  64. T* value_;
  65. };
  66. template <typename Handler>
  67. class coro_handler<Handler, void>
  68. {
  69. public:
  70. coro_handler(basic_yield_context<Handler> ctx)
  71. : coro_(ctx.coro_.lock()),
  72. ca_(ctx.ca_),
  73. handler_(ctx.handler_),
  74. ready_(0),
  75. ec_(ctx.ec_)
  76. {
  77. }
  78. void operator()()
  79. {
  80. *ec_ = asio::error_code();
  81. if (--*ready_ == 0)
  82. (*coro_)();
  83. }
  84. void operator()(asio::error_code ec)
  85. {
  86. *ec_ = ec;
  87. if (--*ready_ == 0)
  88. (*coro_)();
  89. }
  90. //private:
  91. shared_ptr<typename basic_yield_context<Handler>::callee_type> coro_;
  92. typename basic_yield_context<Handler>::caller_type& ca_;
  93. Handler handler_;
  94. atomic_count* ready_;
  95. asio::error_code* ec_;
  96. };
  97. template <typename Handler, typename T>
  98. inline void* asio_handler_allocate(std::size_t size,
  99. coro_handler<Handler, T>* this_handler)
  100. {
  101. return asio_handler_alloc_helpers::allocate(
  102. size, this_handler->handler_);
  103. }
  104. template <typename Handler, typename T>
  105. inline void asio_handler_deallocate(void* pointer, std::size_t size,
  106. coro_handler<Handler, T>* this_handler)
  107. {
  108. asio_handler_alloc_helpers::deallocate(
  109. pointer, size, this_handler->handler_);
  110. }
  111. template <typename Handler, typename T>
  112. inline bool asio_handler_is_continuation(coro_handler<Handler, T>*)
  113. {
  114. return true;
  115. }
  116. template <typename Function, typename Handler, typename T>
  117. inline void asio_handler_invoke(Function& function,
  118. coro_handler<Handler, T>* this_handler)
  119. {
  120. asio_handler_invoke_helpers::invoke(
  121. function, this_handler->handler_);
  122. }
  123. template <typename Function, typename Handler, typename T>
  124. inline void asio_handler_invoke(const Function& function,
  125. coro_handler<Handler, T>* this_handler)
  126. {
  127. asio_handler_invoke_helpers::invoke(
  128. function, this_handler->handler_);
  129. }
  130. template <typename Handler, typename T>
  131. class coro_async_result
  132. {
  133. public:
  134. typedef coro_handler<Handler, T> completion_handler_type;
  135. typedef T return_type;
  136. explicit coro_async_result(completion_handler_type& h)
  137. : handler_(h),
  138. ca_(h.ca_),
  139. ready_(2)
  140. {
  141. h.ready_ = &ready_;
  142. out_ec_ = h.ec_;
  143. if (!out_ec_) h.ec_ = &ec_;
  144. h.value_ = &value_;
  145. }
  146. return_type get()
  147. {
  148. // Must not hold shared_ptr to coro while suspended.
  149. handler_.coro_.reset();
  150. if (--ready_ != 0)
  151. ca_();
  152. if (!out_ec_ && ec_) throw asio::system_error(ec_);
  153. return ASIO_MOVE_CAST(return_type)(value_);
  154. }
  155. private:
  156. completion_handler_type& handler_;
  157. typename basic_yield_context<Handler>::caller_type& ca_;
  158. atomic_count ready_;
  159. asio::error_code* out_ec_;
  160. asio::error_code ec_;
  161. return_type value_;
  162. };
  163. template <typename Handler>
  164. class coro_async_result<Handler, void>
  165. {
  166. public:
  167. typedef coro_handler<Handler, void> completion_handler_type;
  168. typedef void return_type;
  169. explicit coro_async_result(completion_handler_type& h)
  170. : handler_(h),
  171. ca_(h.ca_),
  172. ready_(2)
  173. {
  174. h.ready_ = &ready_;
  175. out_ec_ = h.ec_;
  176. if (!out_ec_) h.ec_ = &ec_;
  177. }
  178. void get()
  179. {
  180. // Must not hold shared_ptr to coro while suspended.
  181. handler_.coro_.reset();
  182. if (--ready_ != 0)
  183. ca_();
  184. if (!out_ec_ && ec_) throw asio::system_error(ec_);
  185. }
  186. private:
  187. completion_handler_type& handler_;
  188. typename basic_yield_context<Handler>::caller_type& ca_;
  189. atomic_count ready_;
  190. asio::error_code* out_ec_;
  191. asio::error_code ec_;
  192. };
  193. } // namespace detail
  194. #if !defined(GENERATING_DOCUMENTATION)
  195. template <typename Handler, typename ReturnType>
  196. class async_result<basic_yield_context<Handler>, ReturnType()>
  197. : public detail::coro_async_result<Handler, void>
  198. {
  199. public:
  200. explicit async_result(
  201. typename detail::coro_async_result<Handler,
  202. void>::completion_handler_type& h)
  203. : detail::coro_async_result<Handler, void>(h)
  204. {
  205. }
  206. };
  207. template <typename Handler, typename ReturnType, typename Arg1>
  208. class async_result<basic_yield_context<Handler>, ReturnType(Arg1)>
  209. : public detail::coro_async_result<Handler, typename decay<Arg1>::type>
  210. {
  211. public:
  212. explicit async_result(
  213. typename detail::coro_async_result<Handler,
  214. typename decay<Arg1>::type>::completion_handler_type& h)
  215. : detail::coro_async_result<Handler, typename decay<Arg1>::type>(h)
  216. {
  217. }
  218. };
  219. template <typename Handler, typename ReturnType>
  220. class async_result<basic_yield_context<Handler>,
  221. ReturnType(asio::error_code)>
  222. : public detail::coro_async_result<Handler, void>
  223. {
  224. public:
  225. explicit async_result(
  226. typename detail::coro_async_result<Handler,
  227. void>::completion_handler_type& h)
  228. : detail::coro_async_result<Handler, void>(h)
  229. {
  230. }
  231. };
  232. template <typename Handler, typename ReturnType, typename Arg2>
  233. class async_result<basic_yield_context<Handler>,
  234. ReturnType(asio::error_code, Arg2)>
  235. : public detail::coro_async_result<Handler, typename decay<Arg2>::type>
  236. {
  237. public:
  238. explicit async_result(
  239. typename detail::coro_async_result<Handler,
  240. typename decay<Arg2>::type>::completion_handler_type& h)
  241. : detail::coro_async_result<Handler, typename decay<Arg2>::type>(h)
  242. {
  243. }
  244. };
  245. #if !defined(ASIO_NO_DEPRECATED)
  246. template <typename Handler, typename ReturnType>
  247. struct handler_type<basic_yield_context<Handler>, ReturnType()>
  248. {
  249. typedef detail::coro_handler<Handler, void> type;
  250. };
  251. template <typename Handler, typename ReturnType, typename Arg1>
  252. struct handler_type<basic_yield_context<Handler>, ReturnType(Arg1)>
  253. {
  254. typedef detail::coro_handler<Handler, typename decay<Arg1>::type> type;
  255. };
  256. template <typename Handler, typename ReturnType>
  257. struct handler_type<basic_yield_context<Handler>,
  258. ReturnType(asio::error_code)>
  259. {
  260. typedef detail::coro_handler<Handler, void> type;
  261. };
  262. template <typename Handler, typename ReturnType, typename Arg2>
  263. struct handler_type<basic_yield_context<Handler>,
  264. ReturnType(asio::error_code, Arg2)>
  265. {
  266. typedef detail::coro_handler<Handler, typename decay<Arg2>::type> type;
  267. };
  268. template <typename Handler, typename T>
  269. class async_result<detail::coro_handler<Handler, T> >
  270. : public detail::coro_async_result<Handler, T>
  271. {
  272. public:
  273. typedef typename detail::coro_async_result<Handler, T>::return_type type;
  274. explicit async_result(
  275. typename detail::coro_async_result<Handler,
  276. T>::completion_handler_type& h)
  277. : detail::coro_async_result<Handler, T>(h)
  278. {
  279. }
  280. };
  281. #endif // !defined(ASIO_NO_DEPRECATED)
  282. template <typename Handler, typename T, typename Allocator>
  283. struct associated_allocator<detail::coro_handler<Handler, T>, Allocator>
  284. {
  285. typedef typename associated_allocator<Handler, Allocator>::type type;
  286. static type get(const detail::coro_handler<Handler, T>& h,
  287. const Allocator& a = Allocator()) ASIO_NOEXCEPT
  288. {
  289. return associated_allocator<Handler, Allocator>::get(h.handler_, a);
  290. }
  291. };
  292. template <typename Handler, typename T, typename Executor>
  293. struct associated_executor<detail::coro_handler<Handler, T>, Executor>
  294. {
  295. typedef typename associated_executor<Handler, Executor>::type type;
  296. static type get(const detail::coro_handler<Handler, T>& h,
  297. const Executor& ex = Executor()) ASIO_NOEXCEPT
  298. {
  299. return associated_executor<Handler, Executor>::get(h.handler_, ex);
  300. }
  301. };
  302. namespace detail {
  303. template <typename Handler, typename Function>
  304. struct spawn_data : private noncopyable
  305. {
  306. template <typename Hand, typename Func>
  307. spawn_data(ASIO_MOVE_ARG(Hand) handler,
  308. bool call_handler, ASIO_MOVE_ARG(Func) function)
  309. : handler_(ASIO_MOVE_CAST(Hand)(handler)),
  310. call_handler_(call_handler),
  311. function_(ASIO_MOVE_CAST(Func)(function))
  312. {
  313. }
  314. weak_ptr<typename basic_yield_context<Handler>::callee_type> coro_;
  315. Handler handler_;
  316. bool call_handler_;
  317. Function function_;
  318. };
  319. template <typename Handler, typename Function>
  320. struct coro_entry_point
  321. {
  322. void operator()(typename basic_yield_context<Handler>::caller_type& ca)
  323. {
  324. shared_ptr<spawn_data<Handler, Function> > data(data_);
  325. #if !defined(BOOST_COROUTINES_UNIDIRECT) && !defined(BOOST_COROUTINES_V2)
  326. ca(); // Yield until coroutine pointer has been initialised.
  327. #endif // !defined(BOOST_COROUTINES_UNIDIRECT) && !defined(BOOST_COROUTINES_V2)
  328. const basic_yield_context<Handler> yield(
  329. data->coro_, ca, data->handler_);
  330. (data->function_)(yield);
  331. if (data->call_handler_)
  332. (data->handler_)();
  333. }
  334. shared_ptr<spawn_data<Handler, Function> > data_;
  335. };
  336. template <typename Handler, typename Function>
  337. struct spawn_helper
  338. {
  339. void operator()()
  340. {
  341. typedef typename basic_yield_context<Handler>::callee_type callee_type;
  342. coro_entry_point<Handler, Function> entry_point = { data_ };
  343. shared_ptr<callee_type> coro(new callee_type(entry_point, attributes_));
  344. data_->coro_ = coro;
  345. (*coro)();
  346. }
  347. shared_ptr<spawn_data<Handler, Function> > data_;
  348. boost::coroutines::attributes attributes_;
  349. };
  350. template <typename Function, typename Handler, typename Function1>
  351. inline void asio_handler_invoke(Function& function,
  352. spawn_helper<Handler, Function1>* this_handler)
  353. {
  354. asio_handler_invoke_helpers::invoke(
  355. function, this_handler->data_->handler_);
  356. }
  357. template <typename Function, typename Handler, typename Function1>
  358. inline void asio_handler_invoke(const Function& function,
  359. spawn_helper<Handler, Function1>* this_handler)
  360. {
  361. asio_handler_invoke_helpers::invoke(
  362. function, this_handler->data_->handler_);
  363. }
  364. inline void default_spawn_handler() {}
  365. } // namespace detail
  366. template <typename Function>
  367. inline void spawn(ASIO_MOVE_ARG(Function) function,
  368. const boost::coroutines::attributes& attributes)
  369. {
  370. typedef typename decay<Function>::type function_type;
  371. typename associated_executor<function_type>::type ex(
  372. (get_associated_executor)(function));
  373. asio::spawn(ex, ASIO_MOVE_CAST(Function)(function), attributes);
  374. }
  375. template <typename Handler, typename Function>
  376. void spawn(ASIO_MOVE_ARG(Handler) handler,
  377. ASIO_MOVE_ARG(Function) function,
  378. const boost::coroutines::attributes& attributes,
  379. typename enable_if<!is_executor<typename decay<Handler>::type>::value &&
  380. !is_convertible<Handler&, execution_context&>::value>::type*)
  381. {
  382. typedef typename decay<Handler>::type handler_type;
  383. typedef typename decay<Function>::type function_type;
  384. typename associated_executor<handler_type>::type ex(
  385. (get_associated_executor)(handler));
  386. typename associated_allocator<handler_type>::type a(
  387. (get_associated_allocator)(handler));
  388. detail::spawn_helper<handler_type, function_type> helper;
  389. helper.data_.reset(
  390. new detail::spawn_data<handler_type, function_type>(
  391. ASIO_MOVE_CAST(Handler)(handler), true,
  392. ASIO_MOVE_CAST(Function)(function)));
  393. helper.attributes_ = attributes;
  394. ex.dispatch(helper, a);
  395. }
  396. template <typename Handler, typename Function>
  397. void spawn(basic_yield_context<Handler> ctx,
  398. ASIO_MOVE_ARG(Function) function,
  399. const boost::coroutines::attributes& attributes)
  400. {
  401. typedef typename decay<Function>::type function_type;
  402. Handler handler(ctx.handler_); // Explicit copy that might be moved from.
  403. typename associated_executor<Handler>::type ex(
  404. (get_associated_executor)(handler));
  405. typename associated_allocator<Handler>::type a(
  406. (get_associated_allocator)(handler));
  407. detail::spawn_helper<Handler, function_type> helper;
  408. helper.data_.reset(
  409. new detail::spawn_data<Handler, function_type>(
  410. ASIO_MOVE_CAST(Handler)(handler), false,
  411. ASIO_MOVE_CAST(Function)(function)));
  412. helper.attributes_ = attributes;
  413. ex.dispatch(helper, a);
  414. }
  415. template <typename Function, typename Executor>
  416. inline void spawn(const Executor& ex,
  417. ASIO_MOVE_ARG(Function) function,
  418. const boost::coroutines::attributes& attributes,
  419. typename enable_if<is_executor<Executor>::value>::type*)
  420. {
  421. asio::spawn(asio::strand<Executor>(ex),
  422. ASIO_MOVE_CAST(Function)(function), attributes);
  423. }
  424. template <typename Function, typename Executor>
  425. inline void spawn(const strand<Executor>& ex,
  426. ASIO_MOVE_ARG(Function) function,
  427. const boost::coroutines::attributes& attributes)
  428. {
  429. asio::spawn(asio::bind_executor(
  430. ex, &detail::default_spawn_handler),
  431. ASIO_MOVE_CAST(Function)(function), attributes);
  432. }
  433. template <typename Function>
  434. inline void spawn(const asio::io_context::strand& s,
  435. ASIO_MOVE_ARG(Function) function,
  436. const boost::coroutines::attributes& attributes)
  437. {
  438. asio::spawn(asio::bind_executor(
  439. s, &detail::default_spawn_handler),
  440. ASIO_MOVE_CAST(Function)(function), attributes);
  441. }
  442. template <typename Function, typename ExecutionContext>
  443. inline void spawn(ExecutionContext& ctx,
  444. ASIO_MOVE_ARG(Function) function,
  445. const boost::coroutines::attributes& attributes,
  446. typename enable_if<is_convertible<
  447. ExecutionContext&, execution_context&>::value>::type*)
  448. {
  449. asio::spawn(ctx.get_executor(),
  450. ASIO_MOVE_CAST(Function)(function), attributes);
  451. }
  452. #endif // !defined(GENERATING_DOCUMENTATION)
  453. } // namespace asio
  454. #include "asio/detail/pop_options.hpp"
  455. #endif // ASIO_IMPL_SPAWN_HPP