spawn.hpp 16 KB

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