spawn.hpp 31 KB

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