spawn.hpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872
  1. //
  2. // spawn.hpp
  3. // ~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #ifndef ASIO_SPAWN_HPP
  11. #define ASIO_SPAWN_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include "asio/detail/config.hpp"
  16. #include "asio/any_io_executor.hpp"
  17. #include "asio/cancellation_signal.hpp"
  18. #include "asio/cancellation_state.hpp"
  19. #include "asio/detail/exception.hpp"
  20. #include "asio/detail/memory.hpp"
  21. #include "asio/detail/type_traits.hpp"
  22. #include "asio/io_context.hpp"
  23. #include "asio/is_executor.hpp"
  24. #include "asio/strand.hpp"
  25. #if defined(ASIO_HAS_BOOST_COROUTINE)
  26. # include <boost/coroutine/all.hpp>
  27. #endif // defined(ASIO_HAS_BOOST_COROUTINE)
  28. #include "asio/detail/push_options.hpp"
  29. namespace asio {
  30. namespace detail {
  31. // Base class for all spawn()-ed thread implementations.
  32. class spawned_thread_base
  33. {
  34. public:
  35. spawned_thread_base()
  36. : owner_(0),
  37. has_context_switched_(false),
  38. throw_if_cancelled_(false),
  39. terminal_(false)
  40. {
  41. }
  42. virtual ~spawned_thread_base() {}
  43. virtual void resume() = 0;
  44. virtual void suspend_with(void (*fn)(void*), void* arg) = 0;
  45. virtual void destroy() = 0;
  46. void attach(spawned_thread_base** owner)
  47. {
  48. owner_ = owner;
  49. *owner_ = this;
  50. }
  51. void detach()
  52. {
  53. if (owner_)
  54. *owner_ = 0;
  55. owner_ = 0;
  56. }
  57. void suspend()
  58. {
  59. suspend_with(0, 0);
  60. }
  61. template <typename F>
  62. void suspend_with(F f)
  63. {
  64. suspend_with(&spawned_thread_base::call<F>, &f);
  65. }
  66. cancellation_slot get_cancellation_slot() const noexcept
  67. {
  68. return cancellation_state_.slot();
  69. }
  70. cancellation_state get_cancellation_state() const noexcept
  71. {
  72. return cancellation_state_;
  73. }
  74. void reset_cancellation_state()
  75. {
  76. cancellation_state_ = cancellation_state(parent_cancellation_slot_);
  77. }
  78. template <typename Filter>
  79. void reset_cancellation_state(Filter filter)
  80. {
  81. cancellation_state_ = cancellation_state(
  82. parent_cancellation_slot_, filter, filter);
  83. }
  84. template <typename InFilter, typename OutFilter>
  85. void reset_cancellation_state(InFilter in_filter, OutFilter out_filter)
  86. {
  87. cancellation_state_ = cancellation_state(
  88. parent_cancellation_slot_, in_filter, out_filter);
  89. }
  90. cancellation_type_t cancelled() const noexcept
  91. {
  92. return cancellation_state_.cancelled();
  93. }
  94. bool has_context_switched() const noexcept
  95. {
  96. return has_context_switched_;
  97. }
  98. bool throw_if_cancelled() const noexcept
  99. {
  100. return throw_if_cancelled_;
  101. }
  102. void throw_if_cancelled(bool value) noexcept
  103. {
  104. throw_if_cancelled_ = value;
  105. }
  106. protected:
  107. spawned_thread_base** owner_; // Points to data member in active handler.
  108. asio::cancellation_slot parent_cancellation_slot_;
  109. asio::cancellation_state cancellation_state_;
  110. bool has_context_switched_;
  111. bool throw_if_cancelled_;
  112. bool terminal_;
  113. private:
  114. // Disallow copying and assignment.
  115. spawned_thread_base(const spawned_thread_base&) = delete;
  116. spawned_thread_base& operator=(const spawned_thread_base&) = delete;
  117. template <typename F>
  118. static void call(void* f)
  119. {
  120. (*static_cast<F*>(f))();
  121. }
  122. };
  123. template <typename T>
  124. struct spawn_signature
  125. {
  126. typedef void type(exception_ptr, T);
  127. };
  128. template <>
  129. struct spawn_signature<void>
  130. {
  131. typedef void type(exception_ptr);
  132. };
  133. template <typename Executor>
  134. class initiate_spawn;
  135. } // namespace detail
  136. /// A @ref completion_token that represents the currently executing coroutine.
  137. /**
  138. * The basic_yield_context class is a completion token type that is used to
  139. * represent the currently executing stackful coroutine. A basic_yield_context
  140. * object may be passed as a completion token to an asynchronous operation. For
  141. * example:
  142. *
  143. * @code template <typename Executor>
  144. * void my_coroutine(basic_yield_context<Executor> yield)
  145. * {
  146. * ...
  147. * std::size_t n = my_socket.async_read_some(buffer, yield);
  148. * ...
  149. * } @endcode
  150. *
  151. * The initiating function (async_read_some in the above example) suspends the
  152. * current coroutine. The coroutine is resumed when the asynchronous operation
  153. * completes, and the result of the operation is returned.
  154. */
  155. template <typename Executor>
  156. class basic_yield_context
  157. {
  158. public:
  159. /// The executor type associated with the yield context.
  160. typedef Executor executor_type;
  161. /// The cancellation slot type associated with the yield context.
  162. typedef cancellation_slot cancellation_slot_type;
  163. /// Construct a yield context from another yield context type.
  164. /**
  165. * Requires that OtherExecutor be convertible to Executor.
  166. */
  167. template <typename OtherExecutor>
  168. basic_yield_context(const basic_yield_context<OtherExecutor>& other,
  169. constraint_t<
  170. is_convertible<OtherExecutor, Executor>::value
  171. > = 0)
  172. : spawned_thread_(other.spawned_thread_),
  173. executor_(other.executor_),
  174. ec_(other.ec_)
  175. {
  176. }
  177. /// Get the executor associated with the yield context.
  178. executor_type get_executor() const noexcept
  179. {
  180. return executor_;
  181. }
  182. /// Get the cancellation slot associated with the coroutine.
  183. cancellation_slot_type get_cancellation_slot() const noexcept
  184. {
  185. return spawned_thread_->get_cancellation_slot();
  186. }
  187. /// Get the cancellation state associated with the coroutine.
  188. cancellation_state get_cancellation_state() const noexcept
  189. {
  190. return spawned_thread_->get_cancellation_state();
  191. }
  192. /// Reset the cancellation state associated with the coroutine.
  193. /**
  194. * Let <tt>P</tt> be the cancellation slot associated with the current
  195. * coroutine's @ref spawn completion handler. Assigns a new
  196. * asio::cancellation_state object <tt>S</tt>, constructed as
  197. * <tt>S(P)</tt>, into the current coroutine's cancellation state object.
  198. */
  199. void reset_cancellation_state() const
  200. {
  201. spawned_thread_->reset_cancellation_state();
  202. }
  203. /// Reset the cancellation state associated with the coroutine.
  204. /**
  205. * Let <tt>P</tt> be the cancellation slot associated with the current
  206. * coroutine's @ref spawn completion handler. Assigns a new
  207. * asio::cancellation_state object <tt>S</tt>, constructed as <tt>S(P,
  208. * std::forward<Filter>(filter))</tt>, into the current coroutine's
  209. * cancellation state object.
  210. */
  211. template <typename Filter>
  212. void reset_cancellation_state(Filter&& filter) const
  213. {
  214. spawned_thread_->reset_cancellation_state(
  215. static_cast<Filter&&>(filter));
  216. }
  217. /// Reset the cancellation state associated with the coroutine.
  218. /**
  219. * Let <tt>P</tt> be the cancellation slot associated with the current
  220. * coroutine's @ref spawn completion handler. Assigns a new
  221. * asio::cancellation_state object <tt>S</tt>, constructed as <tt>S(P,
  222. * std::forward<InFilter>(in_filter),
  223. * std::forward<OutFilter>(out_filter))</tt>, into the current coroutine's
  224. * cancellation state object.
  225. */
  226. template <typename InFilter, typename OutFilter>
  227. void reset_cancellation_state(InFilter&& in_filter,
  228. OutFilter&& out_filter) const
  229. {
  230. spawned_thread_->reset_cancellation_state(
  231. static_cast<InFilter&&>(in_filter),
  232. static_cast<OutFilter&&>(out_filter));
  233. }
  234. /// Determine whether the current coroutine has been cancelled.
  235. cancellation_type_t cancelled() const noexcept
  236. {
  237. return spawned_thread_->cancelled();
  238. }
  239. /// Determine whether the coroutine throws if trying to suspend when it has
  240. /// been cancelled.
  241. bool throw_if_cancelled() const noexcept
  242. {
  243. return spawned_thread_->throw_if_cancelled();
  244. }
  245. /// Set whether the coroutine throws if trying to suspend when it has been
  246. /// cancelled.
  247. void throw_if_cancelled(bool value) const noexcept
  248. {
  249. spawned_thread_->throw_if_cancelled(value);
  250. }
  251. /// Return a yield context that sets the specified error_code.
  252. /**
  253. * By default, when a yield context is used with an asynchronous operation, a
  254. * non-success error_code is converted to system_error and thrown. This
  255. * operator may be used to specify an error_code object that should instead be
  256. * set with the asynchronous operation's result. For example:
  257. *
  258. * @code template <typename Executor>
  259. * void my_coroutine(basic_yield_context<Executor> yield)
  260. * {
  261. * ...
  262. * std::size_t n = my_socket.async_read_some(buffer, yield[ec]);
  263. * if (ec)
  264. * {
  265. * // An error occurred.
  266. * }
  267. * ...
  268. * } @endcode
  269. */
  270. basic_yield_context operator[](asio::error_code& ec) const
  271. {
  272. basic_yield_context tmp(*this);
  273. tmp.ec_ = &ec;
  274. return tmp;
  275. }
  276. #if !defined(GENERATING_DOCUMENTATION)
  277. //private:
  278. basic_yield_context(detail::spawned_thread_base* spawned_thread,
  279. const Executor& ex)
  280. : spawned_thread_(spawned_thread),
  281. executor_(ex),
  282. ec_(0)
  283. {
  284. }
  285. detail::spawned_thread_base* spawned_thread_;
  286. Executor executor_;
  287. asio::error_code* ec_;
  288. #endif // !defined(GENERATING_DOCUMENTATION)
  289. };
  290. /// A @ref completion_token object that represents the currently executing
  291. /// coroutine.
  292. typedef basic_yield_context<any_io_executor> yield_context;
  293. /**
  294. * @defgroup spawn asio::spawn
  295. *
  296. * @brief Start a new stackful coroutine.
  297. *
  298. * The spawn() function is a high-level wrapper over the Boost.Coroutine
  299. * library. This function enables programs to implement asynchronous logic in a
  300. * synchronous manner, as illustrated by the following example:
  301. *
  302. * @code asio::spawn(my_strand, do_echo, asio::detached);
  303. *
  304. * // ...
  305. *
  306. * void do_echo(asio::yield_context yield)
  307. * {
  308. * try
  309. * {
  310. * char data[128];
  311. * for (;;)
  312. * {
  313. * std::size_t length =
  314. * my_socket.async_read_some(
  315. * asio::buffer(data), yield);
  316. *
  317. * asio::async_write(my_socket,
  318. * asio::buffer(data, length), yield);
  319. * }
  320. * }
  321. * catch (std::exception& e)
  322. * {
  323. * // ...
  324. * }
  325. * } @endcode
  326. */
  327. /*@{*/
  328. /// Start a new stackful coroutine that executes on a given executor.
  329. /**
  330. * This function is used to launch a new stackful coroutine.
  331. *
  332. * @param ex Identifies the executor that will run the stackful coroutine.
  333. *
  334. * @param function The coroutine function. The function must be callable the
  335. * signature:
  336. * @code void function(basic_yield_context<Executor> yield); @endcode
  337. *
  338. * @param token The @ref completion_token that will handle the notification
  339. * that the coroutine has completed. If the return type @c R of @c function is
  340. * @c void, the function signature of the completion handler must be:
  341. *
  342. * @code void handler(std::exception_ptr); @endcode
  343. * Otherwise, the function signature of the completion handler must be:
  344. * @code void handler(std::exception_ptr, R); @endcode
  345. *
  346. * @par Completion Signature
  347. * @code void(std::exception_ptr, R) @endcode
  348. * where @c R is the return type of the function object.
  349. *
  350. * @par Per-Operation Cancellation
  351. * The new thread of execution is created with a cancellation state that
  352. * supports @c cancellation_type::terminal values only. To change the
  353. * cancellation state, call the basic_yield_context member function
  354. * @c reset_cancellation_state.
  355. */
  356. template <typename Executor, typename F,
  357. ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
  358. result_of_t<F(basic_yield_context<Executor>)>>::type)
  359. CompletionToken = default_completion_token_t<Executor>>
  360. auto spawn(const Executor& ex, F&& function,
  361. CompletionToken&& token = default_completion_token_t<Executor>(),
  362. #if defined(ASIO_HAS_BOOST_COROUTINE)
  363. constraint_t<
  364. !is_same<
  365. decay_t<CompletionToken>,
  366. boost::coroutines::attributes
  367. >::value
  368. > = 0,
  369. #endif // defined(ASIO_HAS_BOOST_COROUTINE)
  370. constraint_t<
  371. is_executor<Executor>::value || execution::is_executor<Executor>::value
  372. > = 0)
  373. -> decltype(
  374. async_initiate<CompletionToken,
  375. typename detail::spawn_signature<
  376. result_of_t<F(basic_yield_context<Executor>)>>::type>(
  377. declval<detail::initiate_spawn<Executor>>(),
  378. token, static_cast<F&&>(function)));
  379. /// Start a new stackful coroutine that executes on a given execution context.
  380. /**
  381. * This function is used to launch a new stackful coroutine.
  382. *
  383. * @param ctx Identifies the execution context that will run the stackful
  384. * coroutine.
  385. *
  386. * @param function The coroutine function. The function must be callable the
  387. * signature:
  388. * @code void function(basic_yield_context<Executor> yield); @endcode
  389. *
  390. * @param token The @ref completion_token that will handle the notification
  391. * that the coroutine has completed. If the return type @c R of @c function is
  392. * @c void, the function signature of the completion handler must be:
  393. *
  394. * @code void handler(std::exception_ptr); @endcode
  395. * Otherwise, the function signature of the completion handler must be:
  396. * @code void handler(std::exception_ptr, R); @endcode
  397. *
  398. * @par Completion Signature
  399. * @code void(std::exception_ptr, R) @endcode
  400. * where @c R is the return type of the function object.
  401. *
  402. * @par Per-Operation Cancellation
  403. * The new thread of execution is created with a cancellation state that
  404. * supports @c cancellation_type::terminal values only. To change the
  405. * cancellation state, call the basic_yield_context member function
  406. * @c reset_cancellation_state.
  407. */
  408. template <typename ExecutionContext, typename F,
  409. ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
  410. result_of_t<F(basic_yield_context<
  411. typename ExecutionContext::executor_type>)>>::type)
  412. CompletionToken = default_completion_token_t<
  413. typename ExecutionContext::executor_type>>
  414. auto spawn(ExecutionContext& ctx, F&& function,
  415. CompletionToken&& token
  416. = default_completion_token_t<typename ExecutionContext::executor_type>(),
  417. #if defined(ASIO_HAS_BOOST_COROUTINE)
  418. constraint_t<
  419. !is_same<
  420. decay_t<CompletionToken>,
  421. boost::coroutines::attributes
  422. >::value
  423. > = 0,
  424. #endif // defined(ASIO_HAS_BOOST_COROUTINE)
  425. constraint_t<
  426. is_convertible<ExecutionContext&, execution_context&>::value
  427. > = 0)
  428. -> decltype(
  429. async_initiate<CompletionToken,
  430. typename detail::spawn_signature<
  431. result_of_t<F(basic_yield_context<
  432. typename ExecutionContext::executor_type>)>>::type>(
  433. declval<detail::initiate_spawn<
  434. typename ExecutionContext::executor_type>>(),
  435. token, static_cast<F&&>(function)));
  436. /// Start a new stackful coroutine, inheriting the executor of another.
  437. /**
  438. * This function is used to launch a new stackful coroutine.
  439. *
  440. * @param ctx Identifies the current coroutine as a parent of the new
  441. * coroutine. This specifies that the new coroutine should inherit the executor
  442. * of the parent. For example, if the parent coroutine is executing in a
  443. * particular strand, then the new coroutine will execute in the same strand.
  444. *
  445. * @param function The coroutine function. The function must be callable the
  446. * signature:
  447. * @code void function(basic_yield_context<Executor> yield); @endcode
  448. *
  449. * @param token The @ref completion_token that will handle the notification
  450. * that the coroutine has completed. If the return type @c R of @c function is
  451. * @c void, the function signature of the completion handler must be:
  452. *
  453. * @code void handler(std::exception_ptr); @endcode
  454. * Otherwise, the function signature of the completion handler must be:
  455. * @code void handler(std::exception_ptr, R); @endcode
  456. *
  457. * @par Completion Signature
  458. * @code void(std::exception_ptr, R) @endcode
  459. * where @c R is the return type of the function object.
  460. *
  461. * @par Per-Operation Cancellation
  462. * The new thread of execution is created with a cancellation state that
  463. * supports @c cancellation_type::terminal values only. To change the
  464. * cancellation state, call the basic_yield_context member function
  465. * @c reset_cancellation_state.
  466. */
  467. template <typename Executor, typename F,
  468. ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
  469. result_of_t<F(basic_yield_context<Executor>)>>::type)
  470. CompletionToken = default_completion_token_t<Executor>>
  471. auto spawn(const basic_yield_context<Executor>& ctx, F&& function,
  472. CompletionToken&& token = default_completion_token_t<Executor>(),
  473. #if defined(ASIO_HAS_BOOST_COROUTINE)
  474. constraint_t<
  475. !is_same<
  476. decay_t<CompletionToken>,
  477. boost::coroutines::attributes
  478. >::value
  479. > = 0,
  480. #endif // defined(ASIO_HAS_BOOST_COROUTINE)
  481. constraint_t<
  482. is_executor<Executor>::value || execution::is_executor<Executor>::value
  483. > = 0)
  484. -> decltype(
  485. async_initiate<CompletionToken,
  486. typename detail::spawn_signature<
  487. result_of_t<F(basic_yield_context<Executor>)>>::type>(
  488. declval<detail::initiate_spawn<Executor>>(),
  489. token, static_cast<F&&>(function)));
  490. #if defined(ASIO_HAS_BOOST_CONTEXT_FIBER) \
  491. || defined(GENERATING_DOCUMENTATION)
  492. /// Start a new stackful coroutine that executes on a given executor.
  493. /**
  494. * This function is used to launch a new stackful coroutine using the
  495. * specified stack allocator.
  496. *
  497. * @param ex Identifies the executor that will run the stackful coroutine.
  498. *
  499. * @param stack_allocator Denotes the allocator to be used to allocate the
  500. * underlying coroutine's stack. The type must satisfy the stack-allocator
  501. * concept defined by the Boost.Context library.
  502. *
  503. * @param function The coroutine function. The function must be callable the
  504. * signature:
  505. * @code void function(basic_yield_context<Executor> yield); @endcode
  506. *
  507. * @param token The @ref completion_token that will handle the notification
  508. * that the coroutine has completed. If the return type @c R of @c function is
  509. * @c void, the function signature of the completion handler must be:
  510. *
  511. * @code void handler(std::exception_ptr); @endcode
  512. * Otherwise, the function signature of the completion handler must be:
  513. * @code void handler(std::exception_ptr, R); @endcode
  514. *
  515. * @par Completion Signature
  516. * @code void(std::exception_ptr, R) @endcode
  517. * where @c R is the return type of the function object.
  518. *
  519. * @par Per-Operation Cancellation
  520. * The new thread of execution is created with a cancellation state that
  521. * supports @c cancellation_type::terminal values only. To change the
  522. * cancellation state, call the basic_yield_context member function
  523. * @c reset_cancellation_state.
  524. */
  525. template <typename Executor, typename StackAllocator, typename F,
  526. ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
  527. result_of_t<F(basic_yield_context<Executor>)>>::type)
  528. CompletionToken = default_completion_token_t<Executor>>
  529. auto spawn(const Executor& ex, allocator_arg_t,
  530. StackAllocator&& stack_allocator, F&& function,
  531. CompletionToken&& token = default_completion_token_t<Executor>(),
  532. constraint_t<
  533. is_executor<Executor>::value || execution::is_executor<Executor>::value
  534. > = 0)
  535. -> decltype(
  536. async_initiate<CompletionToken,
  537. typename detail::spawn_signature<
  538. result_of_t<F(basic_yield_context<Executor>)>>::type>(
  539. declval<detail::initiate_spawn<Executor>>(),
  540. token, allocator_arg_t(),
  541. static_cast<StackAllocator&&>(stack_allocator),
  542. static_cast<F&&>(function)));
  543. /// Start a new stackful coroutine that executes on a given execution context.
  544. /**
  545. * This function is used to launch a new stackful coroutine.
  546. *
  547. * @param ctx Identifies the execution context that will run the stackful
  548. * coroutine.
  549. *
  550. * @param stack_allocator Denotes the allocator to be used to allocate the
  551. * underlying coroutine's stack. The type must satisfy the stack-allocator
  552. * concept defined by the Boost.Context library.
  553. *
  554. * @param function The coroutine function. The function must be callable the
  555. * signature:
  556. * @code void function(basic_yield_context<Executor> yield); @endcode
  557. *
  558. * @param token The @ref completion_token that will handle the notification
  559. * that the coroutine has completed. If the return type @c R of @c function is
  560. * @c void, the function signature of the completion handler must be:
  561. *
  562. * @code void handler(std::exception_ptr); @endcode
  563. * Otherwise, the function signature of the completion handler must be:
  564. * @code void handler(std::exception_ptr, R); @endcode
  565. *
  566. * @par Completion Signature
  567. * @code void(std::exception_ptr, R) @endcode
  568. * where @c R is the return type of the function object.
  569. *
  570. * @par Per-Operation Cancellation
  571. * The new thread of execution is created with a cancellation state that
  572. * supports @c cancellation_type::terminal values only. To change the
  573. * cancellation state, call the basic_yield_context member function
  574. * @c reset_cancellation_state.
  575. */
  576. template <typename ExecutionContext, typename StackAllocator, typename F,
  577. ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
  578. result_of_t<F(basic_yield_context<
  579. typename ExecutionContext::executor_type>)>>::type)
  580. CompletionToken = default_completion_token_t<
  581. typename ExecutionContext::executor_type>>
  582. auto spawn(ExecutionContext& ctx, allocator_arg_t,
  583. StackAllocator&& stack_allocator, F&& function,
  584. CompletionToken&& token
  585. = default_completion_token_t<typename ExecutionContext::executor_type>(),
  586. constraint_t<
  587. is_convertible<ExecutionContext&, execution_context&>::value
  588. > = 0)
  589. -> decltype(
  590. async_initiate<CompletionToken,
  591. typename detail::spawn_signature<
  592. result_of_t<F(basic_yield_context<
  593. typename ExecutionContext::executor_type>)>>::type>(
  594. declval<detail::initiate_spawn<
  595. typename ExecutionContext::executor_type>>(),
  596. token, allocator_arg_t(),
  597. static_cast<StackAllocator&&>(stack_allocator),
  598. static_cast<F&&>(function)));
  599. /// Start a new stackful coroutine, inheriting the executor of another.
  600. /**
  601. * This function is used to launch a new stackful coroutine using the
  602. * specified stack allocator.
  603. *
  604. * @param ctx Identifies the current coroutine as a parent of the new
  605. * coroutine. This specifies that the new coroutine should inherit the
  606. * executor of the parent. For example, if the parent coroutine is executing
  607. * in a particular strand, then the new coroutine will execute in the same
  608. * strand.
  609. *
  610. * @param stack_allocator Denotes the allocator to be used to allocate the
  611. * underlying coroutine's stack. The type must satisfy the stack-allocator
  612. * concept defined by the Boost.Context library.
  613. *
  614. * @param function The coroutine function. The function must be callable the
  615. * signature:
  616. * @code void function(basic_yield_context<Executor> yield); @endcode
  617. *
  618. * @param token The @ref completion_token that will handle the notification
  619. * that the coroutine has completed. If the return type @c R of @c function is
  620. * @c void, the function signature of the completion handler must be:
  621. *
  622. * @code void handler(std::exception_ptr); @endcode
  623. * Otherwise, the function signature of the completion handler must be:
  624. * @code void handler(std::exception_ptr, R); @endcode
  625. *
  626. * @par Completion Signature
  627. * @code void(std::exception_ptr, R) @endcode
  628. * where @c R is the return type of the function object.
  629. *
  630. * @par Per-Operation Cancellation
  631. * The new thread of execution is created with a cancellation state that
  632. * supports @c cancellation_type::terminal values only. To change the
  633. * cancellation state, call the basic_yield_context member function
  634. * @c reset_cancellation_state.
  635. */
  636. template <typename Executor, typename StackAllocator, typename F,
  637. ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
  638. result_of_t<F(basic_yield_context<Executor>)>>::type)
  639. CompletionToken = default_completion_token_t<Executor>>
  640. auto spawn(const basic_yield_context<Executor>& ctx, allocator_arg_t,
  641. StackAllocator&& stack_allocator, F&& function,
  642. CompletionToken&& token = default_completion_token_t<Executor>(),
  643. constraint_t<
  644. is_executor<Executor>::value || execution::is_executor<Executor>::value
  645. > = 0)
  646. -> decltype(
  647. async_initiate<CompletionToken,
  648. typename detail::spawn_signature<
  649. result_of_t<F(basic_yield_context<Executor>)>>::type>(
  650. declval<detail::initiate_spawn<Executor>>(),
  651. token, allocator_arg_t(),
  652. static_cast<StackAllocator&&>(stack_allocator),
  653. static_cast<F&&>(function)));
  654. #endif // defined(ASIO_HAS_BOOST_CONTEXT_FIBER)
  655. // || defined(GENERATING_DOCUMENTATION)
  656. #if defined(ASIO_HAS_BOOST_COROUTINE) \
  657. || defined(GENERATING_DOCUMENTATION)
  658. /// (Deprecated: Use overloads with a completion token.) Start a new stackful
  659. /// coroutine, calling the specified handler when it completes.
  660. /**
  661. * This function is used to launch a new coroutine.
  662. *
  663. * @param function The coroutine function. The function must have the signature:
  664. * @code void function(basic_yield_context<Executor> yield); @endcode
  665. * where Executor is the associated executor type of @c Function.
  666. *
  667. * @param attributes Boost.Coroutine attributes used to customise the coroutine.
  668. */
  669. template <typename Function>
  670. void spawn(Function&& function,
  671. const boost::coroutines::attributes& attributes
  672. = boost::coroutines::attributes());
  673. /// (Deprecated: Use overloads with a completion token.) Start a new stackful
  674. /// coroutine, calling the specified handler when it completes.
  675. /**
  676. * This function is used to launch a new coroutine.
  677. *
  678. * @param handler A handler to be called when the coroutine exits. More
  679. * importantly, the handler provides an execution context (via the the handler
  680. * invocation hook) for the coroutine. The handler must have the signature:
  681. * @code void handler(); @endcode
  682. *
  683. * @param function The coroutine function. The function must have the signature:
  684. * @code void function(basic_yield_context<Executor> yield); @endcode
  685. * where Executor is the associated executor type of @c Handler.
  686. *
  687. * @param attributes Boost.Coroutine attributes used to customise the coroutine.
  688. */
  689. template <typename Handler, typename Function>
  690. void spawn(Handler&& handler, Function&& function,
  691. const boost::coroutines::attributes& attributes
  692. = boost::coroutines::attributes(),
  693. constraint_t<
  694. !is_executor<decay_t<Handler>>::value &&
  695. !execution::is_executor<decay_t<Handler>>::value &&
  696. !is_convertible<Handler&, execution_context&>::value
  697. > = 0);
  698. /// (Deprecated: Use overloads with a completion token.) Start a new stackful
  699. /// coroutine, inheriting the execution context of another.
  700. /**
  701. * This function is used to launch a new coroutine.
  702. *
  703. * @param ctx Identifies the current coroutine as a parent of the new
  704. * coroutine. This specifies that the new coroutine should inherit the
  705. * execution context of the parent. For example, if the parent coroutine is
  706. * executing in a particular strand, then the new coroutine will execute in the
  707. * same strand.
  708. *
  709. * @param function The coroutine function. The function must have the signature:
  710. * @code void function(basic_yield_context<Executor> yield); @endcode
  711. *
  712. * @param attributes Boost.Coroutine attributes used to customise the coroutine.
  713. */
  714. template <typename Executor, typename Function>
  715. void spawn(basic_yield_context<Executor> ctx, Function&& function,
  716. const boost::coroutines::attributes& attributes
  717. = boost::coroutines::attributes());
  718. /// (Deprecated: Use overloads with a completion token.) Start a new stackful
  719. /// coroutine that executes on a given executor.
  720. /**
  721. * This function is used to launch a new coroutine.
  722. *
  723. * @param ex Identifies the executor that will run the coroutine. The new
  724. * coroutine is automatically given its own explicit strand within this
  725. * executor.
  726. *
  727. * @param function The coroutine function. The function must have the signature:
  728. * @code void function(yield_context yield); @endcode
  729. *
  730. * @param attributes Boost.Coroutine attributes used to customise the coroutine.
  731. */
  732. template <typename Function, typename Executor>
  733. void spawn(const Executor& ex, Function&& function,
  734. const boost::coroutines::attributes& attributes
  735. = boost::coroutines::attributes(),
  736. constraint_t<
  737. is_executor<Executor>::value || execution::is_executor<Executor>::value
  738. > = 0);
  739. /// (Deprecated: Use overloads with a completion token.) Start a new stackful
  740. /// coroutine that executes on a given strand.
  741. /**
  742. * This function is used to launch a new coroutine.
  743. *
  744. * @param ex Identifies the strand that will run the coroutine.
  745. *
  746. * @param function The coroutine function. The function must have the signature:
  747. * @code void function(yield_context yield); @endcode
  748. *
  749. * @param attributes Boost.Coroutine attributes used to customise the coroutine.
  750. */
  751. template <typename Function, typename Executor>
  752. void spawn(const strand<Executor>& ex, Function&& function,
  753. const boost::coroutines::attributes& attributes
  754. = boost::coroutines::attributes());
  755. #if !defined(ASIO_NO_TS_EXECUTORS)
  756. /// (Deprecated: Use overloads with a completion token.) Start a new stackful
  757. /// coroutine that executes in the context of a strand.
  758. /**
  759. * This function is used to launch a new coroutine.
  760. *
  761. * @param s Identifies a strand. By starting multiple coroutines on the same
  762. * strand, the implementation ensures that none of those coroutines can execute
  763. * simultaneously.
  764. *
  765. * @param function The coroutine function. The function must have the signature:
  766. * @code void function(yield_context yield); @endcode
  767. *
  768. * @param attributes Boost.Coroutine attributes used to customise the coroutine.
  769. */
  770. template <typename Function>
  771. void spawn(const asio::io_context::strand& s, Function&& function,
  772. const boost::coroutines::attributes& attributes
  773. = boost::coroutines::attributes());
  774. #endif // !defined(ASIO_NO_TS_EXECUTORS)
  775. /// (Deprecated: Use overloads with a completion token.) Start a new stackful
  776. /// coroutine that executes on a given execution context.
  777. /**
  778. * This function is used to launch a new coroutine.
  779. *
  780. * @param ctx Identifies the execution context that will run the coroutine. The
  781. * new coroutine is implicitly given its own strand within this execution
  782. * context.
  783. *
  784. * @param function The coroutine function. The function must have the signature:
  785. * @code void function(yield_context yield); @endcode
  786. *
  787. * @param attributes Boost.Coroutine attributes used to customise the coroutine.
  788. */
  789. template <typename Function, typename ExecutionContext>
  790. void spawn(ExecutionContext& ctx, Function&& function,
  791. const boost::coroutines::attributes& attributes
  792. = boost::coroutines::attributes(),
  793. constraint_t<
  794. is_convertible<ExecutionContext&, execution_context&>::value
  795. > = 0);
  796. #endif // defined(ASIO_HAS_BOOST_COROUTINE)
  797. // || defined(GENERATING_DOCUMENTATION)
  798. /*@}*/
  799. } // namespace asio
  800. #include "asio/detail/pop_options.hpp"
  801. #include "asio/impl/spawn.hpp"
  802. #endif // ASIO_SPAWN_HPP