spawn.hpp 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618
  1. //
  2. // impl/spawn.hpp
  3. // ~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2023 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_cancellation_slot.hpp>
  18. #include <boost/asio/associated_executor.hpp>
  19. #include <boost/asio/async_result.hpp>
  20. #include <boost/asio/bind_executor.hpp>
  21. #include <boost/asio/detail/atomic_count.hpp>
  22. #include <boost/asio/detail/bind_handler.hpp>
  23. #include <boost/asio/detail/handler_alloc_helpers.hpp>
  24. #include <boost/asio/detail/handler_cont_helpers.hpp>
  25. #include <boost/asio/detail/handler_invoke_helpers.hpp>
  26. #include <boost/asio/detail/memory.hpp>
  27. #include <boost/asio/detail/noncopyable.hpp>
  28. #include <boost/asio/detail/type_traits.hpp>
  29. #include <boost/asio/detail/utility.hpp>
  30. #include <boost/asio/detail/variadic_templates.hpp>
  31. #include <boost/system/system_error.hpp>
  32. #if defined(BOOST_ASIO_HAS_STD_TUPLE)
  33. # include <tuple>
  34. #endif // defined(BOOST_ASIO_HAS_STD_TUPLE)
  35. #if defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
  36. # include <boost/context/fiber.hpp>
  37. #endif // defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
  38. #include <boost/asio/detail/push_options.hpp>
  39. namespace boost {
  40. namespace asio {
  41. namespace detail {
  42. #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
  43. inline void spawned_thread_rethrow(void* ex)
  44. {
  45. if (*static_cast<exception_ptr*>(ex))
  46. rethrow_exception(*static_cast<exception_ptr*>(ex));
  47. }
  48. #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
  49. #if defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
  50. // Spawned thread implementation using Boost.Coroutine.
  51. class spawned_coroutine_thread : public spawned_thread_base
  52. {
  53. public:
  54. #if defined(BOOST_COROUTINES_UNIDIRECT) || defined(BOOST_COROUTINES_V2)
  55. typedef boost::coroutines::pull_coroutine<void> callee_type;
  56. typedef boost::coroutines::push_coroutine<void> caller_type;
  57. #else
  58. typedef boost::coroutines::coroutine<void()> callee_type;
  59. typedef boost::coroutines::coroutine<void()> caller_type;
  60. #endif
  61. spawned_coroutine_thread(caller_type& caller)
  62. : caller_(caller),
  63. on_suspend_fn_(0),
  64. on_suspend_arg_(0)
  65. {
  66. }
  67. template <typename F>
  68. static spawned_thread_base* spawn(BOOST_ASIO_MOVE_ARG(F) f,
  69. const boost::coroutines::attributes& attributes,
  70. cancellation_slot parent_cancel_slot = cancellation_slot(),
  71. cancellation_state cancel_state = cancellation_state())
  72. {
  73. spawned_coroutine_thread* spawned_thread = 0;
  74. callee_type callee(entry_point<typename decay<F>::type>(
  75. BOOST_ASIO_MOVE_CAST(F)(f), &spawned_thread), attributes);
  76. spawned_thread->callee_.swap(callee);
  77. spawned_thread->parent_cancellation_slot_ = parent_cancel_slot;
  78. spawned_thread->cancellation_state_ = cancel_state;
  79. return spawned_thread;
  80. }
  81. template <typename F>
  82. static spawned_thread_base* spawn(BOOST_ASIO_MOVE_ARG(F) f,
  83. cancellation_slot parent_cancel_slot = cancellation_slot(),
  84. cancellation_state cancel_state = cancellation_state())
  85. {
  86. return spawn(BOOST_ASIO_MOVE_CAST(F)(f), boost::coroutines::attributes(),
  87. parent_cancel_slot, cancel_state);
  88. }
  89. void resume()
  90. {
  91. callee_();
  92. if (on_suspend_fn_)
  93. {
  94. void (*fn)(void*) = on_suspend_fn_;
  95. void* arg = on_suspend_arg_;
  96. on_suspend_fn_ = 0;
  97. fn(arg);
  98. }
  99. }
  100. void suspend_with(void (*fn)(void*), void* arg)
  101. {
  102. if (throw_if_cancelled_)
  103. if (!!cancellation_state_.cancelled())
  104. throw_error(boost::asio::error::operation_aborted, "yield");
  105. has_context_switched_ = true;
  106. on_suspend_fn_ = fn;
  107. on_suspend_arg_ = arg;
  108. caller_();
  109. }
  110. void destroy()
  111. {
  112. callee_type callee;
  113. callee.swap(callee_);
  114. if (terminal_)
  115. callee();
  116. }
  117. private:
  118. template <typename Function>
  119. class entry_point
  120. {
  121. public:
  122. template <typename F>
  123. entry_point(BOOST_ASIO_MOVE_ARG(F) f,
  124. spawned_coroutine_thread** spawned_thread_out)
  125. : function_(BOOST_ASIO_MOVE_CAST(F)(f)),
  126. spawned_thread_out_(spawned_thread_out)
  127. {
  128. }
  129. void operator()(caller_type& caller)
  130. {
  131. Function function(BOOST_ASIO_MOVE_CAST(Function)(function_));
  132. spawned_coroutine_thread spawned_thread(caller);
  133. *spawned_thread_out_ = &spawned_thread;
  134. spawned_thread_out_ = 0;
  135. spawned_thread.suspend();
  136. #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
  137. try
  138. #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
  139. {
  140. function(&spawned_thread);
  141. spawned_thread.terminal_ = true;
  142. spawned_thread.suspend();
  143. }
  144. #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
  145. catch (const boost::coroutines::detail::forced_unwind&)
  146. {
  147. throw;
  148. }
  149. catch (...)
  150. {
  151. exception_ptr ex = current_exception();
  152. spawned_thread.terminal_ = true;
  153. spawned_thread.suspend_with(spawned_thread_rethrow, &ex);
  154. }
  155. #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
  156. }
  157. private:
  158. Function function_;
  159. spawned_coroutine_thread** spawned_thread_out_;
  160. };
  161. caller_type& caller_;
  162. callee_type callee_;
  163. void (*on_suspend_fn_)(void*);
  164. void* on_suspend_arg_;
  165. };
  166. #endif // defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
  167. #if defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
  168. // Spawned thread implementation using Boost.Context's fiber.
  169. class spawned_fiber_thread : public spawned_thread_base
  170. {
  171. public:
  172. typedef boost::context::fiber fiber_type;
  173. spawned_fiber_thread(BOOST_ASIO_MOVE_ARG(fiber_type) caller)
  174. : caller_(BOOST_ASIO_MOVE_CAST(fiber_type)(caller)),
  175. on_suspend_fn_(0),
  176. on_suspend_arg_(0)
  177. {
  178. }
  179. template <typename StackAllocator, typename F>
  180. static spawned_thread_base* spawn(allocator_arg_t,
  181. BOOST_ASIO_MOVE_ARG(StackAllocator) stack_allocator,
  182. BOOST_ASIO_MOVE_ARG(F) f,
  183. cancellation_slot parent_cancel_slot = cancellation_slot(),
  184. cancellation_state cancel_state = cancellation_state())
  185. {
  186. spawned_fiber_thread* spawned_thread = 0;
  187. fiber_type callee(allocator_arg_t(),
  188. BOOST_ASIO_MOVE_CAST(StackAllocator)(stack_allocator),
  189. entry_point<typename decay<F>::type>(
  190. BOOST_ASIO_MOVE_CAST(F)(f), &spawned_thread));
  191. callee = fiber_type(BOOST_ASIO_MOVE_CAST(fiber_type)(callee)).resume();
  192. spawned_thread->callee_ = BOOST_ASIO_MOVE_CAST(fiber_type)(callee);
  193. spawned_thread->parent_cancellation_slot_ = parent_cancel_slot;
  194. spawned_thread->cancellation_state_ = cancel_state;
  195. return spawned_thread;
  196. }
  197. template <typename F>
  198. static spawned_thread_base* spawn(BOOST_ASIO_MOVE_ARG(F) f,
  199. cancellation_slot parent_cancel_slot = cancellation_slot(),
  200. cancellation_state cancel_state = cancellation_state())
  201. {
  202. return spawn(allocator_arg_t(), boost::context::fixedsize_stack(),
  203. BOOST_ASIO_MOVE_CAST(F)(f), parent_cancel_slot, cancel_state);
  204. }
  205. void resume()
  206. {
  207. callee_ = fiber_type(BOOST_ASIO_MOVE_CAST(fiber_type)(callee_)).resume();
  208. if (on_suspend_fn_)
  209. {
  210. void (*fn)(void*) = on_suspend_fn_;
  211. void* arg = on_suspend_arg_;
  212. on_suspend_fn_ = 0;
  213. fn(arg);
  214. }
  215. }
  216. void suspend_with(void (*fn)(void*), void* arg)
  217. {
  218. if (throw_if_cancelled_)
  219. if (!!cancellation_state_.cancelled())
  220. throw_error(boost::asio::error::operation_aborted, "yield");
  221. has_context_switched_ = true;
  222. on_suspend_fn_ = fn;
  223. on_suspend_arg_ = arg;
  224. caller_ = fiber_type(BOOST_ASIO_MOVE_CAST(fiber_type)(caller_)).resume();
  225. }
  226. void destroy()
  227. {
  228. fiber_type callee = BOOST_ASIO_MOVE_CAST(fiber_type)(callee_);
  229. if (terminal_)
  230. fiber_type(BOOST_ASIO_MOVE_CAST(fiber_type)(callee)).resume();
  231. }
  232. private:
  233. template <typename Function>
  234. class entry_point
  235. {
  236. public:
  237. template <typename F>
  238. entry_point(BOOST_ASIO_MOVE_ARG(F) f,
  239. spawned_fiber_thread** spawned_thread_out)
  240. : function_(BOOST_ASIO_MOVE_CAST(F)(f)),
  241. spawned_thread_out_(spawned_thread_out)
  242. {
  243. }
  244. fiber_type operator()(BOOST_ASIO_MOVE_ARG(fiber_type) caller)
  245. {
  246. Function function(BOOST_ASIO_MOVE_CAST(Function)(function_));
  247. spawned_fiber_thread spawned_thread(
  248. BOOST_ASIO_MOVE_CAST(fiber_type)(caller));
  249. *spawned_thread_out_ = &spawned_thread;
  250. spawned_thread_out_ = 0;
  251. spawned_thread.suspend();
  252. #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
  253. try
  254. #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
  255. {
  256. function(&spawned_thread);
  257. spawned_thread.terminal_ = true;
  258. spawned_thread.suspend();
  259. }
  260. #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
  261. catch (const boost::context::detail::forced_unwind&)
  262. {
  263. throw;
  264. }
  265. catch (...)
  266. {
  267. exception_ptr ex = current_exception();
  268. spawned_thread.terminal_ = true;
  269. spawned_thread.suspend_with(spawned_thread_rethrow, &ex);
  270. }
  271. #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
  272. return BOOST_ASIO_MOVE_CAST(fiber_type)(spawned_thread.caller_);
  273. }
  274. private:
  275. Function function_;
  276. spawned_fiber_thread** spawned_thread_out_;
  277. };
  278. fiber_type caller_;
  279. fiber_type callee_;
  280. void (*on_suspend_fn_)(void*);
  281. void* on_suspend_arg_;
  282. };
  283. #endif // defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
  284. #if defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
  285. typedef spawned_fiber_thread default_spawned_thread_type;
  286. #elif defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
  287. typedef spawned_coroutine_thread default_spawned_thread_type;
  288. #else
  289. # error No spawn() implementation available
  290. #endif
  291. // Helper class to perform the initial resume on the correct executor.
  292. class spawned_thread_resumer
  293. {
  294. public:
  295. explicit spawned_thread_resumer(spawned_thread_base* spawned_thread)
  296. : spawned_thread_(spawned_thread)
  297. {
  298. #if !defined(BOOST_ASIO_HAS_MOVE)
  299. spawned_thread->detach();
  300. spawned_thread->attach(&spawned_thread_);
  301. #endif // !defined(BOOST_ASIO_HAS_MOVE)
  302. }
  303. #if defined(BOOST_ASIO_HAS_MOVE)
  304. spawned_thread_resumer(spawned_thread_resumer&& other) BOOST_ASIO_NOEXCEPT
  305. : spawned_thread_(other.spawned_thread_)
  306. {
  307. other.spawned_thread_ = 0;
  308. }
  309. #else // defined(BOOST_ASIO_HAS_MOVE)
  310. spawned_thread_resumer(
  311. const spawned_thread_resumer& other) BOOST_ASIO_NOEXCEPT
  312. : spawned_thread_(other.spawned_thread_)
  313. {
  314. spawned_thread_->detach();
  315. spawned_thread_->attach(&spawned_thread_);
  316. }
  317. #endif // defined(BOOST_ASIO_HAS_MOVE)
  318. ~spawned_thread_resumer()
  319. {
  320. if (spawned_thread_)
  321. spawned_thread_->destroy();
  322. }
  323. void operator()()
  324. {
  325. #if defined(BOOST_ASIO_HAS_MOVE)
  326. spawned_thread_->attach(&spawned_thread_);
  327. #endif // defined(BOOST_ASIO_HAS_MOVE)
  328. spawned_thread_->resume();
  329. }
  330. private:
  331. spawned_thread_base* spawned_thread_;
  332. };
  333. // Helper class to ensure spawned threads are destroyed on the correct executor.
  334. class spawned_thread_destroyer
  335. {
  336. public:
  337. explicit spawned_thread_destroyer(spawned_thread_base* spawned_thread)
  338. : spawned_thread_(spawned_thread)
  339. {
  340. spawned_thread->detach();
  341. #if !defined(BOOST_ASIO_HAS_MOVE)
  342. spawned_thread->attach(&spawned_thread_);
  343. #endif // !defined(BOOST_ASIO_HAS_MOVE)
  344. }
  345. #if defined(BOOST_ASIO_HAS_MOVE)
  346. spawned_thread_destroyer(spawned_thread_destroyer&& other) BOOST_ASIO_NOEXCEPT
  347. : spawned_thread_(other.spawned_thread_)
  348. {
  349. other.spawned_thread_ = 0;
  350. }
  351. #else // defined(BOOST_ASIO_HAS_MOVE)
  352. spawned_thread_destroyer(
  353. const spawned_thread_destroyer& other) BOOST_ASIO_NOEXCEPT
  354. : spawned_thread_(other.spawned_thread_)
  355. {
  356. spawned_thread_->detach();
  357. spawned_thread_->attach(&spawned_thread_);
  358. }
  359. #endif // defined(BOOST_ASIO_HAS_MOVE)
  360. ~spawned_thread_destroyer()
  361. {
  362. if (spawned_thread_)
  363. spawned_thread_->destroy();
  364. }
  365. void operator()()
  366. {
  367. if (spawned_thread_)
  368. {
  369. spawned_thread_->destroy();
  370. spawned_thread_ = 0;
  371. }
  372. }
  373. private:
  374. spawned_thread_base* spawned_thread_;
  375. };
  376. // Base class for all completion handlers associated with a spawned thread.
  377. template <typename Executor>
  378. class spawn_handler_base
  379. {
  380. public:
  381. typedef Executor executor_type;
  382. typedef cancellation_slot cancellation_slot_type;
  383. spawn_handler_base(const basic_yield_context<Executor>& yield)
  384. : yield_(yield),
  385. spawned_thread_(yield.spawned_thread_)
  386. {
  387. spawned_thread_->detach();
  388. #if !defined(BOOST_ASIO_HAS_MOVE)
  389. spawned_thread_->attach(&spawned_thread_);
  390. #endif // !defined(BOOST_ASIO_HAS_MOVE)
  391. }
  392. #if defined(BOOST_ASIO_HAS_MOVE)
  393. spawn_handler_base(spawn_handler_base&& other) BOOST_ASIO_NOEXCEPT
  394. : yield_(other.yield_),
  395. spawned_thread_(other.spawned_thread_)
  396. {
  397. other.spawned_thread_ = 0;
  398. }
  399. #else // defined(BOOST_ASIO_HAS_MOVE)
  400. spawn_handler_base(const spawn_handler_base& other) BOOST_ASIO_NOEXCEPT
  401. : yield_(other.yield_),
  402. spawned_thread_(other.spawned_thread_)
  403. {
  404. spawned_thread_->detach();
  405. spawned_thread_->attach(&spawned_thread_);
  406. }
  407. #endif // defined(BOOST_ASIO_HAS_MOVE)
  408. ~spawn_handler_base()
  409. {
  410. if (spawned_thread_)
  411. (post)(yield_.executor_, spawned_thread_destroyer(spawned_thread_));
  412. }
  413. executor_type get_executor() const BOOST_ASIO_NOEXCEPT
  414. {
  415. return yield_.executor_;
  416. }
  417. cancellation_slot_type get_cancellation_slot() const BOOST_ASIO_NOEXCEPT
  418. {
  419. return spawned_thread_->get_cancellation_slot();
  420. }
  421. void resume()
  422. {
  423. spawned_thread_resumer resumer(spawned_thread_);
  424. spawned_thread_ = 0;
  425. resumer();
  426. }
  427. protected:
  428. const basic_yield_context<Executor>& yield_;
  429. spawned_thread_base* spawned_thread_;
  430. };
  431. // Completion handlers for when basic_yield_context is used as a token.
  432. template <typename Executor, typename Signature>
  433. class spawn_handler;
  434. template <typename Executor, typename R>
  435. class spawn_handler<Executor, R()>
  436. : public spawn_handler_base<Executor>
  437. {
  438. public:
  439. typedef void return_type;
  440. struct result_type {};
  441. spawn_handler(const basic_yield_context<Executor>& yield, result_type&)
  442. : spawn_handler_base<Executor>(yield)
  443. {
  444. }
  445. void operator()()
  446. {
  447. this->resume();
  448. }
  449. static return_type on_resume(result_type&)
  450. {
  451. }
  452. };
  453. template <typename Executor, typename R>
  454. class spawn_handler<Executor, R(boost::system::error_code)>
  455. : public spawn_handler_base<Executor>
  456. {
  457. public:
  458. typedef void return_type;
  459. typedef boost::system::error_code* result_type;
  460. spawn_handler(const basic_yield_context<Executor>& yield, result_type& result)
  461. : spawn_handler_base<Executor>(yield),
  462. result_(result)
  463. {
  464. }
  465. void operator()(boost::system::error_code ec)
  466. {
  467. if (this->yield_.ec_)
  468. {
  469. *this->yield_.ec_ = ec;
  470. result_ = 0;
  471. }
  472. else
  473. result_ = &ec;
  474. this->resume();
  475. }
  476. static return_type on_resume(result_type& result)
  477. {
  478. if (result)
  479. throw_error(*result);
  480. }
  481. private:
  482. result_type& result_;
  483. };
  484. template <typename Executor, typename R>
  485. class spawn_handler<Executor, R(exception_ptr)>
  486. : public spawn_handler_base<Executor>
  487. {
  488. public:
  489. typedef void return_type;
  490. typedef exception_ptr* result_type;
  491. spawn_handler(const basic_yield_context<Executor>& yield, result_type& result)
  492. : spawn_handler_base<Executor>(yield),
  493. result_(result)
  494. {
  495. }
  496. void operator()(exception_ptr ex)
  497. {
  498. result_ = &ex;
  499. this->resume();
  500. }
  501. static return_type on_resume(result_type& result)
  502. {
  503. if (result)
  504. rethrow_exception(*result);
  505. }
  506. private:
  507. result_type& result_;
  508. };
  509. template <typename Executor, typename R, typename T>
  510. class spawn_handler<Executor, R(T)>
  511. : public spawn_handler_base<Executor>
  512. {
  513. public:
  514. typedef T return_type;
  515. typedef return_type* result_type;
  516. spawn_handler(const basic_yield_context<Executor>& yield, result_type& result)
  517. : spawn_handler_base<Executor>(yield),
  518. result_(result)
  519. {
  520. }
  521. void operator()(T value)
  522. {
  523. result_ = &value;
  524. this->resume();
  525. }
  526. static return_type on_resume(result_type& result)
  527. {
  528. return BOOST_ASIO_MOVE_CAST(return_type)(*result);
  529. }
  530. private:
  531. result_type& result_;
  532. };
  533. template <typename Executor, typename R, typename T>
  534. class spawn_handler<Executor, R(boost::system::error_code, T)>
  535. : public spawn_handler_base<Executor>
  536. {
  537. public:
  538. typedef T return_type;
  539. struct result_type
  540. {
  541. boost::system::error_code* ec_;
  542. return_type* value_;
  543. };
  544. spawn_handler(const basic_yield_context<Executor>& yield, result_type& result)
  545. : spawn_handler_base<Executor>(yield),
  546. result_(result)
  547. {
  548. }
  549. void operator()(boost::system::error_code ec, T value)
  550. {
  551. if (this->yield_.ec_)
  552. {
  553. *this->yield_.ec_ = ec;
  554. result_.ec_ = 0;
  555. }
  556. else
  557. result_.ec_ = &ec;
  558. result_.value_ = &value;
  559. this->resume();
  560. }
  561. static return_type on_resume(result_type& result)
  562. {
  563. if (result.ec_)
  564. throw_error(*result.ec_);
  565. return BOOST_ASIO_MOVE_CAST(return_type)(*result.value_);
  566. }
  567. private:
  568. result_type& result_;
  569. };
  570. template <typename Executor, typename R, typename T>
  571. class spawn_handler<Executor, R(exception_ptr, T)>
  572. : public spawn_handler_base<Executor>
  573. {
  574. public:
  575. typedef T return_type;
  576. struct result_type
  577. {
  578. exception_ptr ex_;
  579. return_type* value_;
  580. };
  581. spawn_handler(const basic_yield_context<Executor>& yield, result_type& result)
  582. : spawn_handler_base<Executor>(yield),
  583. result_(result)
  584. {
  585. }
  586. void operator()(exception_ptr ex, T value)
  587. {
  588. result_.ex_ = &ex;
  589. result_.value_ = &value;
  590. this->resume();
  591. }
  592. static return_type on_resume(result_type& result)
  593. {
  594. if (result.ex_)
  595. rethrow_exception(*result.ex_);
  596. return BOOST_ASIO_MOVE_CAST(return_type)(*result.value_);
  597. }
  598. private:
  599. result_type& result_;
  600. };
  601. #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) \
  602. && defined(BOOST_ASIO_HAS_STD_TUPLE)
  603. template <typename Executor, typename R, typename... Ts>
  604. class spawn_handler<Executor, R(Ts...)>
  605. : public spawn_handler_base<Executor>
  606. {
  607. public:
  608. typedef std::tuple<Ts...> return_type;
  609. typedef return_type* result_type;
  610. spawn_handler(const basic_yield_context<Executor>& yield, result_type& result)
  611. : spawn_handler_base<Executor>(yield),
  612. result_(result)
  613. {
  614. }
  615. template <typename... Args>
  616. void operator()(BOOST_ASIO_MOVE_ARG(Args)... args)
  617. {
  618. return_type value(BOOST_ASIO_MOVE_CAST(Args)(args)...);
  619. result_ = &value;
  620. this->resume();
  621. }
  622. static return_type on_resume(result_type& result)
  623. {
  624. return BOOST_ASIO_MOVE_CAST(return_type)(*result);
  625. }
  626. private:
  627. result_type& result_;
  628. };
  629. template <typename Executor, typename R, typename... Ts>
  630. class spawn_handler<Executor, R(boost::system::error_code, Ts...)>
  631. : public spawn_handler_base<Executor>
  632. {
  633. public:
  634. typedef std::tuple<Ts...> return_type;
  635. struct result_type
  636. {
  637. boost::system::error_code* ec_;
  638. return_type* value_;
  639. };
  640. spawn_handler(const basic_yield_context<Executor>& yield, result_type& result)
  641. : spawn_handler_base<Executor>(yield),
  642. result_(result)
  643. {
  644. }
  645. template <typename... Args>
  646. void operator()(boost::system::error_code ec,
  647. BOOST_ASIO_MOVE_ARG(Args)... args)
  648. {
  649. return_type value(BOOST_ASIO_MOVE_CAST(Args)(args)...);
  650. if (this->yield_.ec_)
  651. {
  652. *this->yield_.ec_ = ec;
  653. result_.ec_ = 0;
  654. }
  655. else
  656. result_.ec_ = &ec;
  657. result_.value_ = &value;
  658. this->resume();
  659. }
  660. static return_type on_resume(result_type& result)
  661. {
  662. if (result.ec_)
  663. throw_error(*result.ec_);
  664. return BOOST_ASIO_MOVE_CAST(return_type)(*result.value_);
  665. }
  666. private:
  667. result_type& result_;
  668. };
  669. template <typename Executor, typename R, typename... Ts>
  670. class spawn_handler<Executor, R(exception_ptr, Ts...)>
  671. : public spawn_handler_base<Executor>
  672. {
  673. public:
  674. typedef std::tuple<Ts...> return_type;
  675. struct result_type
  676. {
  677. exception_ptr ex_;
  678. return_type* value_;
  679. };
  680. spawn_handler(const basic_yield_context<Executor>& yield, result_type& result)
  681. : spawn_handler_base<Executor>(yield),
  682. result_(result)
  683. {
  684. }
  685. template <typename... Args>
  686. void operator()(exception_ptr ex, BOOST_ASIO_MOVE_ARG(Args)... args)
  687. {
  688. return_type value(BOOST_ASIO_MOVE_CAST(Args)(args)...);
  689. result_.ex_ = &ex;
  690. result_.value_ = &value;
  691. this->resume();
  692. }
  693. static return_type on_resume(result_type& result)
  694. {
  695. if (result.ex_)
  696. rethrow_exception(*result.ex_);
  697. return BOOST_ASIO_MOVE_CAST(return_type)(*result.value_);
  698. }
  699. private:
  700. result_type& result_;
  701. };
  702. #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
  703. // && defined(BOOST_ASIO_HAS_STD_TUPLE)
  704. template <typename Executor, typename Signature>
  705. inline bool asio_handler_is_continuation(spawn_handler<Executor, Signature>*)
  706. {
  707. return true;
  708. }
  709. } // namespace detail
  710. template <typename Executor, typename Signature>
  711. class async_result<basic_yield_context<Executor>, Signature>
  712. {
  713. public:
  714. typedef typename detail::spawn_handler<Executor, Signature> handler_type;
  715. typedef typename handler_type::return_type return_type;
  716. #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
  717. # if defined(BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES)
  718. template <typename Initiation, typename... InitArgs>
  719. static return_type initiate(BOOST_ASIO_MOVE_ARG(Initiation) init,
  720. const basic_yield_context<Executor>& yield,
  721. BOOST_ASIO_MOVE_ARG(InitArgs)... init_args)
  722. {
  723. typename handler_type::result_type result
  724. = typename handler_type::result_type();
  725. yield.spawned_thread_->suspend_with(
  726. [&]()
  727. {
  728. BOOST_ASIO_MOVE_CAST(Initiation)(init)(
  729. handler_type(yield, result),
  730. BOOST_ASIO_MOVE_CAST(InitArgs)(init_args)...);
  731. });
  732. return handler_type::on_resume(result);
  733. }
  734. # else // defined(BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES)
  735. template <typename Initiation, typename... InitArgs>
  736. struct suspend_with_helper
  737. {
  738. typename handler_type::result_type& result_;
  739. BOOST_ASIO_MOVE_ARG(Initiation) init_;
  740. const basic_yield_context<Executor>& yield_;
  741. std::tuple<BOOST_ASIO_MOVE_ARG(InitArgs)...> init_args_;
  742. template <std::size_t... I>
  743. void do_invoke(detail::index_sequence<I...>)
  744. {
  745. BOOST_ASIO_MOVE_CAST(Initiation)(init_)(
  746. handler_type(yield_, result_),
  747. BOOST_ASIO_MOVE_CAST(InitArgs)(std::get<I>(init_args_))...);
  748. }
  749. void operator()()
  750. {
  751. this->do_invoke(detail::make_index_sequence<sizeof...(InitArgs)>());
  752. }
  753. };
  754. template <typename Initiation, typename... InitArgs>
  755. static return_type initiate(BOOST_ASIO_MOVE_ARG(Initiation) init,
  756. const basic_yield_context<Executor>& yield,
  757. BOOST_ASIO_MOVE_ARG(InitArgs)... init_args)
  758. {
  759. typename handler_type::result_type result
  760. = typename handler_type::result_type();
  761. yield.spawned_thread_->suspend_with(
  762. suspend_with_helper<Initiation, InitArgs...>{
  763. result, BOOST_ASIO_MOVE_CAST(Initiation)(init), yield,
  764. std::tuple<BOOST_ASIO_MOVE_ARG(InitArgs)...>(
  765. BOOST_ASIO_MOVE_CAST(InitArgs)(init_args)...)});
  766. return handler_type::on_resume(result);
  767. }
  768. # endif // defined(BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES)
  769. #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
  770. template <typename Initiation>
  771. static return_type initiate(Initiation init,
  772. const basic_yield_context<Executor>& yield)
  773. {
  774. typename handler_type::result_type result
  775. = typename handler_type::result_type();
  776. struct on_suspend
  777. {
  778. Initiation& init_;
  779. const basic_yield_context<Executor>& yield_;
  780. typename handler_type::result_type& result_;
  781. void do_call()
  782. {
  783. BOOST_ASIO_MOVE_CAST(Initiation)(init_)(
  784. handler_type(yield_, result_));
  785. }
  786. static void call(void* arg)
  787. {
  788. static_cast<on_suspend*>(arg)->do_call();
  789. }
  790. } o = { init, yield, result };
  791. yield.spawned_thread_->suspend_with(&on_suspend::call, &o);
  792. return handler_type::on_resume(result);
  793. }
  794. #define BOOST_ASIO_PRIVATE_ON_SUSPEND_MEMBERS(n) \
  795. BOOST_ASIO_PRIVATE_ON_SUSPEND_MEMBERS_##n
  796. #define BOOST_ASIO_PRIVATE_ON_SUSPEND_MEMBERS_1 \
  797. T1& x1;
  798. #define BOOST_ASIO_PRIVATE_ON_SUSPEND_MEMBERS_2 \
  799. T1& x1; T2& x2;
  800. #define BOOST_ASIO_PRIVATE_ON_SUSPEND_MEMBERS_3 \
  801. T1& x1; T2& x2; T3& x3;
  802. #define BOOST_ASIO_PRIVATE_ON_SUSPEND_MEMBERS_4 \
  803. T1& x1; T2& x2; T3& x3; T4& x4;
  804. #define BOOST_ASIO_PRIVATE_ON_SUSPEND_MEMBERS_5 \
  805. T1& x1; T2& x2; T3& x3; T4& x4; T5& x5;
  806. #define BOOST_ASIO_PRIVATE_ON_SUSPEND_MEMBERS_6 \
  807. T1& x1; T2& x2; T3& x3; T4& x4; T5& x5; T6& x6;
  808. #define BOOST_ASIO_PRIVATE_ON_SUSPEND_MEMBERS_7 \
  809. T1& x1; T2& x2; T3& x3; T4& x4; T5& x5; T6& x6; T7& x7;
  810. #define BOOST_ASIO_PRIVATE_ON_SUSPEND_MEMBERS_8 \
  811. T1& x1; T2& x2; T3& x3; T4& x4; T5& x5; T6& x6; T7& x7; T8& x8;
  812. #define BOOST_ASIO_PRIVATE_INITIATE_DEF(n) \
  813. template <typename Initiation, BOOST_ASIO_VARIADIC_TPARAMS(n)> \
  814. static return_type initiate(Initiation init, \
  815. const basic_yield_context<Executor>& yield, \
  816. BOOST_ASIO_VARIADIC_BYVAL_PARAMS(n)) \
  817. { \
  818. typename handler_type::result_type result \
  819. = typename handler_type::result_type(); \
  820. \
  821. struct on_suspend \
  822. { \
  823. Initiation& init; \
  824. const basic_yield_context<Executor>& yield; \
  825. typename handler_type::result_type& result; \
  826. BOOST_ASIO_PRIVATE_ON_SUSPEND_MEMBERS(n) \
  827. \
  828. void do_call() \
  829. { \
  830. BOOST_ASIO_MOVE_CAST(Initiation)(init)( \
  831. handler_type(yield, result), \
  832. BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \
  833. } \
  834. \
  835. static void call(void* arg) \
  836. { \
  837. static_cast<on_suspend*>(arg)->do_call(); \
  838. } \
  839. } o = { init, yield, result, BOOST_ASIO_VARIADIC_BYVAL_ARGS(n) }; \
  840. \
  841. yield.spawned_thread_->suspend_with(&on_suspend::call, &o); \
  842. \
  843. return handler_type::on_resume(result); \
  844. } \
  845. /**/
  846. BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_INITIATE_DEF)
  847. #undef BOOST_ASIO_PRIVATE_INITIATE_DEF
  848. #undef BOOST_ASIO_PRIVATE_ON_SUSPEND_MEMBERS
  849. #undef BOOST_ASIO_PRIVATE_ON_SUSPEND_MEMBERS_1
  850. #undef BOOST_ASIO_PRIVATE_ON_SUSPEND_MEMBERS_2
  851. #undef BOOST_ASIO_PRIVATE_ON_SUSPEND_MEMBERS_3
  852. #undef BOOST_ASIO_PRIVATE_ON_SUSPEND_MEMBERS_4
  853. #undef BOOST_ASIO_PRIVATE_ON_SUSPEND_MEMBERS_5
  854. #undef BOOST_ASIO_PRIVATE_ON_SUSPEND_MEMBERS_6
  855. #undef BOOST_ASIO_PRIVATE_ON_SUSPEND_MEMBERS_7
  856. #undef BOOST_ASIO_PRIVATE_ON_SUSPEND_MEMBERS_8
  857. #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
  858. };
  859. namespace detail {
  860. template <typename Executor, typename Function, typename Handler>
  861. class spawn_entry_point
  862. {
  863. public:
  864. template <typename F, typename H>
  865. spawn_entry_point(const Executor& ex,
  866. BOOST_ASIO_MOVE_ARG(F) f, BOOST_ASIO_MOVE_ARG(H) h)
  867. : executor_(ex),
  868. function_(BOOST_ASIO_MOVE_CAST(F)(f)),
  869. handler_(BOOST_ASIO_MOVE_CAST(H)(h)),
  870. work_(handler_, executor_)
  871. {
  872. }
  873. void operator()(spawned_thread_base* spawned_thread)
  874. {
  875. const basic_yield_context<Executor> yield(spawned_thread, executor_);
  876. this->call(yield,
  877. void_type<typename result_of<Function(
  878. basic_yield_context<Executor>)>::type>());
  879. }
  880. private:
  881. void call(const basic_yield_context<Executor>& yield, void_type<void>)
  882. {
  883. #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
  884. try
  885. #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
  886. {
  887. function_(yield);
  888. if (!yield.spawned_thread_->has_context_switched())
  889. (post)(yield);
  890. detail::binder1<Handler, exception_ptr>
  891. handler(handler_, exception_ptr());
  892. work_.complete(handler, handler.handler_);
  893. }
  894. #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
  895. # if defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
  896. catch (const boost::context::detail::forced_unwind&)
  897. {
  898. throw;
  899. }
  900. # endif // defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
  901. # if defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
  902. catch (const boost::coroutines::detail::forced_unwind&)
  903. {
  904. throw;
  905. }
  906. # endif // defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
  907. catch (...)
  908. {
  909. exception_ptr ex = current_exception();
  910. if (!yield.spawned_thread_->has_context_switched())
  911. (post)(yield);
  912. detail::binder1<Handler, exception_ptr> handler(handler_, ex);
  913. work_.complete(handler, handler.handler_);
  914. }
  915. #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
  916. }
  917. template <typename T>
  918. void call(const basic_yield_context<Executor>& yield, void_type<T>)
  919. {
  920. #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
  921. try
  922. #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
  923. {
  924. T result(function_(yield));
  925. if (!yield.spawned_thread_->has_context_switched())
  926. (post)(yield);
  927. detail::binder2<Handler, exception_ptr, T>
  928. handler(handler_, exception_ptr(), BOOST_ASIO_MOVE_CAST(T)(result));
  929. work_.complete(handler, handler.handler_);
  930. }
  931. #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
  932. # if defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
  933. catch (const boost::context::detail::forced_unwind&)
  934. {
  935. throw;
  936. }
  937. # endif // defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
  938. # if defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
  939. catch (const boost::coroutines::detail::forced_unwind&)
  940. {
  941. throw;
  942. }
  943. # endif // defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
  944. catch (...)
  945. {
  946. exception_ptr ex = current_exception();
  947. if (!yield.spawned_thread_->has_context_switched())
  948. (post)(yield);
  949. detail::binder2<Handler, exception_ptr, T> handler(handler_, ex, T());
  950. work_.complete(handler, handler.handler_);
  951. }
  952. #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
  953. }
  954. Executor executor_;
  955. Function function_;
  956. Handler handler_;
  957. handler_work<Handler, Executor> work_;
  958. };
  959. struct spawn_cancellation_signal_emitter
  960. {
  961. cancellation_signal* signal_;
  962. cancellation_type_t type_;
  963. void operator()()
  964. {
  965. signal_->emit(type_);
  966. }
  967. };
  968. template <typename Handler, typename Executor, typename = void>
  969. class spawn_cancellation_handler
  970. {
  971. public:
  972. spawn_cancellation_handler(const Handler&, const Executor& ex)
  973. : ex_(ex)
  974. {
  975. }
  976. cancellation_slot slot()
  977. {
  978. return signal_.slot();
  979. }
  980. void operator()(cancellation_type_t type)
  981. {
  982. spawn_cancellation_signal_emitter emitter = { &signal_, type };
  983. (dispatch)(ex_, emitter);
  984. }
  985. private:
  986. cancellation_signal signal_;
  987. Executor ex_;
  988. };
  989. template <typename Handler, typename Executor>
  990. class spawn_cancellation_handler<Handler, Executor,
  991. typename enable_if<
  992. is_same<
  993. typename associated_executor<Handler,
  994. Executor>::asio_associated_executor_is_unspecialised,
  995. void
  996. >::value
  997. >::type>
  998. {
  999. public:
  1000. spawn_cancellation_handler(const Handler&, const Executor&)
  1001. {
  1002. }
  1003. cancellation_slot slot()
  1004. {
  1005. return signal_.slot();
  1006. }
  1007. void operator()(cancellation_type_t type)
  1008. {
  1009. signal_.emit(type);
  1010. }
  1011. private:
  1012. cancellation_signal signal_;
  1013. };
  1014. template <typename Executor>
  1015. class initiate_spawn
  1016. {
  1017. public:
  1018. typedef Executor executor_type;
  1019. explicit initiate_spawn(const executor_type& ex)
  1020. : executor_(ex)
  1021. {
  1022. }
  1023. executor_type get_executor() const BOOST_ASIO_NOEXCEPT
  1024. {
  1025. return executor_;
  1026. }
  1027. template <typename Handler, typename F>
  1028. void operator()(BOOST_ASIO_MOVE_ARG(Handler) handler,
  1029. BOOST_ASIO_MOVE_ARG(F) f) const
  1030. {
  1031. typedef typename decay<Handler>::type handler_type;
  1032. typedef typename decay<F>::type function_type;
  1033. typedef spawn_cancellation_handler<
  1034. handler_type, Executor> cancel_handler_type;
  1035. typename associated_cancellation_slot<handler_type>::type slot
  1036. = boost::asio::get_associated_cancellation_slot(handler);
  1037. cancel_handler_type* cancel_handler = slot.is_connected()
  1038. ? &slot.template emplace<cancel_handler_type>(handler, executor_)
  1039. : 0;
  1040. cancellation_slot proxy_slot(
  1041. cancel_handler
  1042. ? cancel_handler->slot()
  1043. : cancellation_slot());
  1044. cancellation_state cancel_state(proxy_slot);
  1045. (dispatch)(executor_,
  1046. spawned_thread_resumer(
  1047. default_spawned_thread_type::spawn(
  1048. spawn_entry_point<Executor, function_type, handler_type>(
  1049. executor_, BOOST_ASIO_MOVE_CAST(F)(f),
  1050. BOOST_ASIO_MOVE_CAST(Handler)(handler)),
  1051. proxy_slot, cancel_state)));
  1052. }
  1053. #if defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
  1054. template <typename Handler, typename StackAllocator, typename F>
  1055. void operator()(BOOST_ASIO_MOVE_ARG(Handler) handler, allocator_arg_t,
  1056. BOOST_ASIO_MOVE_ARG(StackAllocator) stack_allocator,
  1057. BOOST_ASIO_MOVE_ARG(F) f) const
  1058. {
  1059. typedef typename decay<Handler>::type handler_type;
  1060. typedef typename decay<F>::type function_type;
  1061. typedef spawn_cancellation_handler<
  1062. handler_type, Executor> cancel_handler_type;
  1063. typename associated_cancellation_slot<handler_type>::type slot
  1064. = boost::asio::get_associated_cancellation_slot(handler);
  1065. cancel_handler_type* cancel_handler = slot.is_connected()
  1066. ? &slot.template emplace<cancel_handler_type>(handler, executor_)
  1067. : 0;
  1068. cancellation_slot proxy_slot(
  1069. cancel_handler
  1070. ? cancel_handler->slot()
  1071. : cancellation_slot());
  1072. cancellation_state cancel_state(proxy_slot);
  1073. (dispatch)(executor_,
  1074. spawned_thread_resumer(
  1075. spawned_fiber_thread::spawn(allocator_arg_t(),
  1076. BOOST_ASIO_MOVE_CAST(StackAllocator)(stack_allocator),
  1077. spawn_entry_point<Executor, function_type, handler_type>(
  1078. executor_, BOOST_ASIO_MOVE_CAST(F)(f),
  1079. BOOST_ASIO_MOVE_CAST(Handler)(handler)),
  1080. proxy_slot, cancel_state)));
  1081. }
  1082. #endif // defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
  1083. private:
  1084. executor_type executor_;
  1085. };
  1086. } // namespace detail
  1087. template <typename Executor, typename F,
  1088. BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
  1089. typename result_of<F(basic_yield_context<Executor>)>::type>::type)
  1090. CompletionToken>
  1091. inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX(CompletionToken,
  1092. typename detail::spawn_signature<
  1093. typename result_of<F(basic_yield_context<Executor>)>::type>::type)
  1094. spawn(const Executor& ex, BOOST_ASIO_MOVE_ARG(F) function,
  1095. BOOST_ASIO_MOVE_ARG(CompletionToken) token,
  1096. #if defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
  1097. typename constraint<
  1098. !is_same<
  1099. typename decay<CompletionToken>::type,
  1100. boost::coroutines::attributes
  1101. >::value
  1102. >::type,
  1103. #endif // defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
  1104. typename constraint<
  1105. is_executor<Executor>::value || execution::is_executor<Executor>::value
  1106. >::type)
  1107. BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_SUFFIX((
  1108. async_initiate<CompletionToken,
  1109. typename detail::spawn_signature<
  1110. typename result_of<F(basic_yield_context<Executor>)>::type>::type>(
  1111. declval<detail::initiate_spawn<Executor> >(),
  1112. token, BOOST_ASIO_MOVE_CAST(F)(function))))
  1113. {
  1114. return async_initiate<CompletionToken,
  1115. typename detail::spawn_signature<
  1116. typename result_of<F(basic_yield_context<Executor>)>::type>::type>(
  1117. detail::initiate_spawn<Executor>(ex),
  1118. token, BOOST_ASIO_MOVE_CAST(F)(function));
  1119. }
  1120. template <typename ExecutionContext, typename F,
  1121. BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
  1122. typename result_of<F(basic_yield_context<
  1123. typename ExecutionContext::executor_type>)>::type>::type)
  1124. CompletionToken>
  1125. inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX(CompletionToken,
  1126. typename detail::spawn_signature<
  1127. typename result_of<F(basic_yield_context<
  1128. typename ExecutionContext::executor_type>)>::type>::type)
  1129. spawn(ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(F) function,
  1130. BOOST_ASIO_MOVE_ARG(CompletionToken) token,
  1131. #if defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
  1132. typename constraint<
  1133. !is_same<
  1134. typename decay<CompletionToken>::type,
  1135. boost::coroutines::attributes
  1136. >::value
  1137. >::type,
  1138. #endif // defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
  1139. typename constraint<
  1140. is_convertible<ExecutionContext&, execution_context&>::value
  1141. >::type)
  1142. BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_SUFFIX((
  1143. async_initiate<CompletionToken,
  1144. typename detail::spawn_signature<
  1145. typename result_of<F(basic_yield_context<
  1146. typename ExecutionContext::executor_type>)>::type>::type>(
  1147. declval<detail::initiate_spawn<
  1148. typename ExecutionContext::executor_type> >(),
  1149. token, BOOST_ASIO_MOVE_CAST(F)(function))))
  1150. {
  1151. return (spawn)(ctx.get_executor(), BOOST_ASIO_MOVE_CAST(F)(function),
  1152. BOOST_ASIO_MOVE_CAST(CompletionToken)(token));
  1153. }
  1154. template <typename Executor, typename F,
  1155. BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
  1156. typename result_of<F(basic_yield_context<Executor>)>::type>::type)
  1157. CompletionToken>
  1158. inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX(CompletionToken,
  1159. typename detail::spawn_signature<
  1160. typename result_of<F(basic_yield_context<Executor>)>::type>::type)
  1161. spawn(const basic_yield_context<Executor>& ctx,
  1162. BOOST_ASIO_MOVE_ARG(F) function,
  1163. BOOST_ASIO_MOVE_ARG(CompletionToken) token,
  1164. #if defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
  1165. typename constraint<
  1166. !is_same<
  1167. typename decay<CompletionToken>::type,
  1168. boost::coroutines::attributes
  1169. >::value
  1170. >::type,
  1171. #endif // defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
  1172. typename constraint<
  1173. is_executor<Executor>::value || execution::is_executor<Executor>::value
  1174. >::type)
  1175. BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_SUFFIX((
  1176. async_initiate<CompletionToken,
  1177. typename detail::spawn_signature<
  1178. typename result_of<F(basic_yield_context<Executor>)>::type>::type>(
  1179. declval<detail::initiate_spawn<Executor> >(),
  1180. token, BOOST_ASIO_MOVE_CAST(F)(function))))
  1181. {
  1182. return (spawn)(ctx.get_executor(), BOOST_ASIO_MOVE_CAST(F)(function),
  1183. BOOST_ASIO_MOVE_CAST(CompletionToken)(token));
  1184. }
  1185. #if defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
  1186. template <typename Executor, typename StackAllocator, typename F,
  1187. BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
  1188. typename result_of<F(basic_yield_context<Executor>)>::type>::type)
  1189. CompletionToken>
  1190. inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX(CompletionToken,
  1191. typename detail::spawn_signature<
  1192. typename result_of<F(basic_yield_context<Executor>)>::type>::type)
  1193. spawn(const Executor& ex, allocator_arg_t,
  1194. BOOST_ASIO_MOVE_ARG(StackAllocator) stack_allocator,
  1195. BOOST_ASIO_MOVE_ARG(F) function,
  1196. BOOST_ASIO_MOVE_ARG(CompletionToken) token,
  1197. typename constraint<
  1198. is_executor<Executor>::value || execution::is_executor<Executor>::value
  1199. >::type)
  1200. BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_SUFFIX((
  1201. async_initiate<CompletionToken,
  1202. typename detail::spawn_signature<
  1203. typename result_of<F(basic_yield_context<Executor>)>::type>::type>(
  1204. declval<detail::initiate_spawn<Executor> >(),
  1205. token, allocator_arg_t(),
  1206. BOOST_ASIO_MOVE_CAST(StackAllocator)(stack_allocator),
  1207. BOOST_ASIO_MOVE_CAST(F)(function))))
  1208. {
  1209. return async_initiate<CompletionToken,
  1210. typename detail::spawn_signature<
  1211. typename result_of<F(basic_yield_context<Executor>)>::type>::type>(
  1212. detail::initiate_spawn<Executor>(ex), token, allocator_arg_t(),
  1213. BOOST_ASIO_MOVE_CAST(StackAllocator)(stack_allocator),
  1214. BOOST_ASIO_MOVE_CAST(F)(function));
  1215. }
  1216. template <typename ExecutionContext, typename StackAllocator, typename F,
  1217. BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
  1218. typename result_of<F(basic_yield_context<
  1219. typename ExecutionContext::executor_type>)>::type>::type)
  1220. CompletionToken>
  1221. inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX(CompletionToken,
  1222. typename detail::spawn_signature<
  1223. typename result_of<F(basic_yield_context<
  1224. typename ExecutionContext::executor_type>)>::type>::type)
  1225. spawn(ExecutionContext& ctx, allocator_arg_t,
  1226. BOOST_ASIO_MOVE_ARG(StackAllocator) stack_allocator,
  1227. BOOST_ASIO_MOVE_ARG(F) function,
  1228. BOOST_ASIO_MOVE_ARG(CompletionToken) token,
  1229. typename constraint<
  1230. is_convertible<ExecutionContext&, execution_context&>::value
  1231. >::type)
  1232. BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_SUFFIX((
  1233. async_initiate<CompletionToken,
  1234. typename detail::spawn_signature<
  1235. typename result_of<F(basic_yield_context<
  1236. typename ExecutionContext::executor_type>)>::type>::type>(
  1237. declval<detail::initiate_spawn<
  1238. typename ExecutionContext::executor_type> >(),
  1239. token, allocator_arg_t(),
  1240. BOOST_ASIO_MOVE_CAST(StackAllocator)(stack_allocator),
  1241. BOOST_ASIO_MOVE_CAST(F)(function))))
  1242. {
  1243. return (spawn)(ctx.get_executor(), allocator_arg_t(),
  1244. BOOST_ASIO_MOVE_CAST(StackAllocator)(stack_allocator),
  1245. BOOST_ASIO_MOVE_CAST(F)(function),
  1246. BOOST_ASIO_MOVE_CAST(CompletionToken)(token));
  1247. }
  1248. template <typename Executor, typename StackAllocator, typename F,
  1249. BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
  1250. typename result_of<F(basic_yield_context<Executor>)>::type>::type)
  1251. CompletionToken>
  1252. inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX(CompletionToken,
  1253. typename detail::spawn_signature<
  1254. typename result_of<F(basic_yield_context<Executor>)>::type>::type)
  1255. spawn(const basic_yield_context<Executor>& ctx, allocator_arg_t,
  1256. BOOST_ASIO_MOVE_ARG(StackAllocator) stack_allocator,
  1257. BOOST_ASIO_MOVE_ARG(F) function,
  1258. BOOST_ASIO_MOVE_ARG(CompletionToken) token,
  1259. typename constraint<
  1260. is_executor<Executor>::value || execution::is_executor<Executor>::value
  1261. >::type)
  1262. BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_SUFFIX((
  1263. async_initiate<CompletionToken,
  1264. typename detail::spawn_signature<
  1265. typename result_of<F(basic_yield_context<Executor>)>::type>::type>(
  1266. declval<detail::initiate_spawn<Executor> >(),
  1267. token, allocator_arg_t(),
  1268. BOOST_ASIO_MOVE_CAST(StackAllocator)(stack_allocator),
  1269. BOOST_ASIO_MOVE_CAST(F)(function))))
  1270. {
  1271. return (spawn)(ctx.get_executor(), allocator_arg_t(),
  1272. BOOST_ASIO_MOVE_CAST(StackAllocator)(stack_allocator),
  1273. BOOST_ASIO_MOVE_CAST(F)(function),
  1274. BOOST_ASIO_MOVE_CAST(CompletionToken)(token));
  1275. }
  1276. #endif // defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
  1277. #if defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
  1278. namespace detail {
  1279. template <typename Executor, typename Function, typename Handler>
  1280. class old_spawn_entry_point
  1281. {
  1282. public:
  1283. template <typename F, typename H>
  1284. old_spawn_entry_point(const Executor& ex,
  1285. BOOST_ASIO_MOVE_ARG(F) f, BOOST_ASIO_MOVE_ARG(H) h)
  1286. : executor_(ex),
  1287. function_(BOOST_ASIO_MOVE_CAST(F)(f)),
  1288. handler_(BOOST_ASIO_MOVE_CAST(H)(h))
  1289. {
  1290. }
  1291. void operator()(spawned_thread_base* spawned_thread)
  1292. {
  1293. const basic_yield_context<Executor> yield(spawned_thread, executor_);
  1294. this->call(yield,
  1295. void_type<typename result_of<Function(
  1296. basic_yield_context<Executor>)>::type>());
  1297. }
  1298. private:
  1299. void call(const basic_yield_context<Executor>& yield, void_type<void>)
  1300. {
  1301. function_(yield);
  1302. BOOST_ASIO_MOVE_OR_LVALUE(Handler)(handler_)();
  1303. }
  1304. template <typename T>
  1305. void call(const basic_yield_context<Executor>& yield, void_type<T>)
  1306. {
  1307. BOOST_ASIO_MOVE_OR_LVALUE(Handler)(handler_)(function_(yield));
  1308. }
  1309. Executor executor_;
  1310. Function function_;
  1311. Handler handler_;
  1312. };
  1313. inline void default_spawn_handler() {}
  1314. } // namespace detail
  1315. template <typename Function>
  1316. inline void spawn(BOOST_ASIO_MOVE_ARG(Function) function,
  1317. const boost::coroutines::attributes& attributes)
  1318. {
  1319. typedef typename decay<Function>::type function_type;
  1320. typename associated_executor<function_type>::type ex(
  1321. (get_associated_executor)(function));
  1322. boost::asio::spawn(ex, BOOST_ASIO_MOVE_CAST(Function)(function), attributes);
  1323. }
  1324. template <typename Handler, typename Function>
  1325. void spawn(BOOST_ASIO_MOVE_ARG(Handler) handler,
  1326. BOOST_ASIO_MOVE_ARG(Function) function,
  1327. const boost::coroutines::attributes& attributes,
  1328. typename constraint<
  1329. !is_executor<typename decay<Handler>::type>::value &&
  1330. !execution::is_executor<typename decay<Handler>::type>::value &&
  1331. !is_convertible<Handler&, execution_context&>::value>::type)
  1332. {
  1333. typedef typename decay<Handler>::type handler_type;
  1334. typedef typename decay<Function>::type function_type;
  1335. typedef typename associated_executor<handler_type>::type executor_type;
  1336. executor_type ex((get_associated_executor)(handler));
  1337. (dispatch)(ex,
  1338. detail::spawned_thread_resumer(
  1339. detail::spawned_coroutine_thread::spawn(
  1340. detail::old_spawn_entry_point<executor_type,
  1341. function_type, void (*)()>(
  1342. ex, BOOST_ASIO_MOVE_CAST(Function)(function),
  1343. &detail::default_spawn_handler), attributes)));
  1344. }
  1345. template <typename Executor, typename Function>
  1346. void spawn(basic_yield_context<Executor> ctx,
  1347. BOOST_ASIO_MOVE_ARG(Function) function,
  1348. const boost::coroutines::attributes& attributes)
  1349. {
  1350. typedef typename decay<Function>::type function_type;
  1351. (dispatch)(ctx.get_executor(),
  1352. detail::spawned_thread_resumer(
  1353. detail::spawned_coroutine_thread::spawn(
  1354. detail::old_spawn_entry_point<Executor,
  1355. function_type, void (*)()>(ctx.get_executor(),
  1356. BOOST_ASIO_MOVE_CAST(Function)(function),
  1357. &detail::default_spawn_handler), attributes)));
  1358. }
  1359. template <typename Function, typename Executor>
  1360. inline void spawn(const Executor& ex,
  1361. BOOST_ASIO_MOVE_ARG(Function) function,
  1362. const boost::coroutines::attributes& attributes,
  1363. typename constraint<
  1364. is_executor<Executor>::value || execution::is_executor<Executor>::value
  1365. >::type)
  1366. {
  1367. boost::asio::spawn(boost::asio::strand<Executor>(ex),
  1368. BOOST_ASIO_MOVE_CAST(Function)(function), attributes);
  1369. }
  1370. template <typename Function, typename Executor>
  1371. inline void spawn(const strand<Executor>& ex,
  1372. BOOST_ASIO_MOVE_ARG(Function) function,
  1373. const boost::coroutines::attributes& attributes)
  1374. {
  1375. boost::asio::spawn(boost::asio::bind_executor(
  1376. ex, &detail::default_spawn_handler),
  1377. BOOST_ASIO_MOVE_CAST(Function)(function), attributes);
  1378. }
  1379. #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
  1380. template <typename Function>
  1381. inline void spawn(const boost::asio::io_context::strand& s,
  1382. BOOST_ASIO_MOVE_ARG(Function) function,
  1383. const boost::coroutines::attributes& attributes)
  1384. {
  1385. boost::asio::spawn(boost::asio::bind_executor(
  1386. s, &detail::default_spawn_handler),
  1387. BOOST_ASIO_MOVE_CAST(Function)(function), attributes);
  1388. }
  1389. #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
  1390. template <typename Function, typename ExecutionContext>
  1391. inline void spawn(ExecutionContext& ctx,
  1392. BOOST_ASIO_MOVE_ARG(Function) function,
  1393. const boost::coroutines::attributes& attributes,
  1394. typename constraint<is_convertible<
  1395. ExecutionContext&, execution_context&>::value>::type)
  1396. {
  1397. boost::asio::spawn(ctx.get_executor(),
  1398. BOOST_ASIO_MOVE_CAST(Function)(function), attributes);
  1399. }
  1400. #endif // defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
  1401. } // namespace asio
  1402. } // namespace boost
  1403. #include <boost/asio/detail/pop_options.hpp>
  1404. #endif // BOOST_ASIO_IMPL_SPAWN_HPP