spawn.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. //
  2. // impl/spawn.hpp
  3. // ~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2022 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 <template <typename, typename> class Associator,
  265. typename Handler, typename T, typename DefaultCandidate>
  266. struct associator<Associator,
  267. detail::coro_handler<Handler, T>,
  268. DefaultCandidate>
  269. : Associator<Handler, DefaultCandidate>
  270. {
  271. static typename Associator<Handler, DefaultCandidate>::type get(
  272. const detail::coro_handler<Handler, T>& h,
  273. const DefaultCandidate& c = DefaultCandidate()) BOOST_ASIO_NOEXCEPT
  274. {
  275. return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
  276. }
  277. };
  278. namespace detail {
  279. template <typename Handler, typename Function>
  280. struct spawn_data : private noncopyable
  281. {
  282. template <typename Hand, typename Func>
  283. spawn_data(BOOST_ASIO_MOVE_ARG(Hand) handler,
  284. bool call_handler, BOOST_ASIO_MOVE_ARG(Func) function)
  285. : handler_(BOOST_ASIO_MOVE_CAST(Hand)(handler)),
  286. call_handler_(call_handler),
  287. function_(BOOST_ASIO_MOVE_CAST(Func)(function))
  288. {
  289. }
  290. weak_ptr<typename basic_yield_context<Handler>::callee_type> coro_;
  291. Handler handler_;
  292. bool call_handler_;
  293. Function function_;
  294. };
  295. template <typename Handler, typename Function>
  296. struct coro_entry_point
  297. {
  298. void operator()(typename basic_yield_context<Handler>::caller_type& ca)
  299. {
  300. shared_ptr<spawn_data<Handler, Function> > data(data_);
  301. #if !defined(BOOST_COROUTINES_UNIDIRECT) && !defined(BOOST_COROUTINES_V2)
  302. ca(); // Yield until coroutine pointer has been initialised.
  303. #endif // !defined(BOOST_COROUTINES_UNIDIRECT) && !defined(BOOST_COROUTINES_V2)
  304. const basic_yield_context<Handler> yield(
  305. data->coro_, ca, data->handler_);
  306. (data->function_)(yield);
  307. if (data->call_handler_)
  308. BOOST_ASIO_MOVE_OR_LVALUE(Handler)(data->handler_)();
  309. }
  310. shared_ptr<spawn_data<Handler, Function> > data_;
  311. };
  312. template <typename Handler, typename Function>
  313. struct spawn_helper
  314. {
  315. typedef typename associated_allocator<Handler>::type allocator_type;
  316. allocator_type get_allocator() const BOOST_ASIO_NOEXCEPT
  317. {
  318. return (get_associated_allocator)(data_->handler_);
  319. }
  320. typedef typename associated_executor<Handler>::type executor_type;
  321. executor_type get_executor() const BOOST_ASIO_NOEXCEPT
  322. {
  323. return (get_associated_executor)(data_->handler_);
  324. }
  325. void operator()()
  326. {
  327. typedef typename basic_yield_context<Handler>::callee_type callee_type;
  328. coro_entry_point<Handler, Function> entry_point = { data_ };
  329. shared_ptr<callee_type> coro(new callee_type(entry_point, attributes_));
  330. data_->coro_ = coro;
  331. (*coro)();
  332. }
  333. shared_ptr<spawn_data<Handler, Function> > data_;
  334. boost::coroutines::attributes attributes_;
  335. };
  336. template <typename Function, typename Handler, typename Function1>
  337. inline asio_handler_invoke_is_deprecated
  338. asio_handler_invoke(Function& function,
  339. spawn_helper<Handler, Function1>* this_handler)
  340. {
  341. boost_asio_handler_invoke_helpers::invoke(
  342. function, this_handler->data_->handler_);
  343. #if defined(BOOST_ASIO_NO_DEPRECATED)
  344. return asio_handler_invoke_is_no_longer_used();
  345. #endif // defined(BOOST_ASIO_NO_DEPRECATED)
  346. }
  347. template <typename Function, typename Handler, typename Function1>
  348. inline asio_handler_invoke_is_deprecated
  349. asio_handler_invoke(const Function& function,
  350. spawn_helper<Handler, Function1>* this_handler)
  351. {
  352. boost_asio_handler_invoke_helpers::invoke(
  353. function, this_handler->data_->handler_);
  354. #if defined(BOOST_ASIO_NO_DEPRECATED)
  355. return asio_handler_invoke_is_no_longer_used();
  356. #endif // defined(BOOST_ASIO_NO_DEPRECATED)
  357. }
  358. inline void default_spawn_handler() {}
  359. } // namespace detail
  360. template <typename Function>
  361. inline void spawn(BOOST_ASIO_MOVE_ARG(Function) function,
  362. const boost::coroutines::attributes& attributes)
  363. {
  364. typedef typename decay<Function>::type function_type;
  365. typename associated_executor<function_type>::type ex(
  366. (get_associated_executor)(function));
  367. boost::asio::spawn(ex, BOOST_ASIO_MOVE_CAST(Function)(function), attributes);
  368. }
  369. template <typename Handler, typename Function>
  370. void spawn(BOOST_ASIO_MOVE_ARG(Handler) handler,
  371. BOOST_ASIO_MOVE_ARG(Function) function,
  372. const boost::coroutines::attributes& attributes,
  373. typename constraint<
  374. !is_executor<typename decay<Handler>::type>::value &&
  375. !execution::is_executor<typename decay<Handler>::type>::value &&
  376. !is_convertible<Handler&, execution_context&>::value>::type)
  377. {
  378. typedef typename decay<Handler>::type handler_type;
  379. typedef typename decay<Function>::type function_type;
  380. detail::spawn_helper<handler_type, function_type> helper;
  381. helper.data_.reset(
  382. new detail::spawn_data<handler_type, function_type>(
  383. BOOST_ASIO_MOVE_CAST(Handler)(handler), true,
  384. BOOST_ASIO_MOVE_CAST(Function)(function)));
  385. helper.attributes_ = attributes;
  386. boost::asio::dispatch(helper);
  387. }
  388. template <typename Handler, typename Function>
  389. void spawn(basic_yield_context<Handler> ctx,
  390. BOOST_ASIO_MOVE_ARG(Function) function,
  391. const boost::coroutines::attributes& attributes)
  392. {
  393. typedef typename decay<Function>::type function_type;
  394. Handler handler(ctx.handler_); // Explicit copy that might be moved from.
  395. detail::spawn_helper<Handler, function_type> helper;
  396. helper.data_.reset(
  397. new detail::spawn_data<Handler, function_type>(
  398. BOOST_ASIO_MOVE_CAST(Handler)(handler), false,
  399. BOOST_ASIO_MOVE_CAST(Function)(function)));
  400. helper.attributes_ = attributes;
  401. boost::asio::dispatch(helper);
  402. }
  403. template <typename Function, typename Executor>
  404. inline void spawn(const Executor& ex,
  405. BOOST_ASIO_MOVE_ARG(Function) function,
  406. const boost::coroutines::attributes& attributes,
  407. typename constraint<
  408. is_executor<Executor>::value || execution::is_executor<Executor>::value
  409. >::type)
  410. {
  411. boost::asio::spawn(boost::asio::strand<Executor>(ex),
  412. BOOST_ASIO_MOVE_CAST(Function)(function), attributes);
  413. }
  414. template <typename Function, typename Executor>
  415. inline void spawn(const strand<Executor>& ex,
  416. BOOST_ASIO_MOVE_ARG(Function) function,
  417. const boost::coroutines::attributes& attributes)
  418. {
  419. boost::asio::spawn(boost::asio::bind_executor(
  420. ex, &detail::default_spawn_handler),
  421. BOOST_ASIO_MOVE_CAST(Function)(function), attributes);
  422. }
  423. #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
  424. template <typename Function>
  425. inline void spawn(const boost::asio::io_context::strand& s,
  426. BOOST_ASIO_MOVE_ARG(Function) function,
  427. const boost::coroutines::attributes& attributes)
  428. {
  429. boost::asio::spawn(boost::asio::bind_executor(
  430. s, &detail::default_spawn_handler),
  431. BOOST_ASIO_MOVE_CAST(Function)(function), attributes);
  432. }
  433. #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
  434. template <typename Function, typename ExecutionContext>
  435. inline void spawn(ExecutionContext& ctx,
  436. BOOST_ASIO_MOVE_ARG(Function) function,
  437. const boost::coroutines::attributes& attributes,
  438. typename constraint<is_convertible<
  439. ExecutionContext&, execution_context&>::value>::type)
  440. {
  441. boost::asio::spawn(ctx.get_executor(),
  442. BOOST_ASIO_MOVE_CAST(Function)(function), attributes);
  443. }
  444. #endif // !defined(GENERATING_DOCUMENTATION)
  445. } // namespace asio
  446. } // namespace boost
  447. #include <boost/asio/detail/pop_options.hpp>
  448. #endif // BOOST_ASIO_IMPL_SPAWN_HPP