spawn.hpp 37 KB

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