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