spawn.hpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908
  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 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 BOOST_ASIO_NOEXCEPT
  68. {
  69. return cancellation_state_.slot();
  70. }
  71. cancellation_state get_cancellation_state() const BOOST_ASIO_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 BOOST_ASIO_NOEXCEPT
  92. {
  93. return cancellation_state_.cancelled();
  94. }
  95. bool has_context_switched() const BOOST_ASIO_NOEXCEPT
  96. {
  97. return has_context_switched_;
  98. }
  99. bool throw_if_cancelled() const BOOST_ASIO_NOEXCEPT
  100. {
  101. return throw_if_cancelled_;
  102. }
  103. void throw_if_cancelled(bool value) BOOST_ASIO_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&) BOOST_ASIO_DELETED;
  117. spawned_thread_base& operator=(const spawned_thread_base&) BOOST_ASIO_DELETED;
  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. typename constraint<
  171. is_convertible<OtherExecutor, Executor>::value
  172. >::type = 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 BOOST_ASIO_NOEXCEPT
  180. {
  181. return executor_;
  182. }
  183. /// Get the cancellation slot associated with the coroutine.
  184. cancellation_slot_type get_cancellation_slot() const BOOST_ASIO_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 BOOST_ASIO_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(BOOST_ASIO_MOVE_ARG(Filter) filter) const
  214. {
  215. spawned_thread_->reset_cancellation_state(
  216. BOOST_ASIO_MOVE_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(BOOST_ASIO_MOVE_ARG(InFilter) in_filter,
  229. BOOST_ASIO_MOVE_ARG(OutFilter) out_filter) const
  230. {
  231. spawned_thread_->reset_cancellation_state(
  232. BOOST_ASIO_MOVE_CAST(InFilter)(in_filter),
  233. BOOST_ASIO_MOVE_CAST(OutFilter)(out_filter));
  234. }
  235. /// Determine whether the current coroutine has been cancelled.
  236. cancellation_type_t cancelled() const BOOST_ASIO_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 BOOST_ASIO_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 BOOST_ASIO_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. typename result_of<F(basic_yield_context<Executor>)>::type>::type)
  360. CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
  361. BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX(CompletionToken,
  362. typename detail::spawn_signature<
  363. typename result_of<F(basic_yield_context<Executor>)>::type>::type)
  364. spawn(const Executor& ex, BOOST_ASIO_MOVE_ARG(F) function,
  365. BOOST_ASIO_MOVE_ARG(CompletionToken) token
  366. BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
  367. #if defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
  368. typename constraint<
  369. !is_same<
  370. typename decay<CompletionToken>::type,
  371. boost::coroutines::attributes
  372. >::value
  373. >::type = 0,
  374. #endif // defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
  375. typename constraint<
  376. is_executor<Executor>::value || execution::is_executor<Executor>::value
  377. >::type = 0)
  378. BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_SUFFIX((
  379. async_initiate<CompletionToken,
  380. typename detail::spawn_signature<
  381. typename result_of<F(basic_yield_context<Executor>)>::type>::type>(
  382. declval<detail::initiate_spawn<Executor> >(),
  383. token, BOOST_ASIO_MOVE_CAST(F)(function))));
  384. /// Start a new stackful coroutine that executes on a given execution context.
  385. /**
  386. * This function is used to launch a new stackful coroutine.
  387. *
  388. * @param ctx Identifies the execution context that will run the stackful
  389. * coroutine.
  390. *
  391. * @param function The coroutine function. The function must be callable the
  392. * signature:
  393. * @code void function(basic_yield_context<Executor> yield); @endcode
  394. *
  395. * @param token The @ref completion_token that will handle the notification
  396. * that the coroutine has completed. If the return type @c R of @c function is
  397. * @c void, the function signature of the completion handler must be:
  398. *
  399. * @code void handler(std::exception_ptr); @endcode
  400. * Otherwise, the function signature of the completion handler must be:
  401. * @code void handler(std::exception_ptr, R); @endcode
  402. *
  403. * @par Completion Signature
  404. * @code void(std::exception_ptr, R) @endcode
  405. * where @c R is the return type of the function object.
  406. *
  407. * @par Per-Operation Cancellation
  408. * The new thread of execution is created with a cancellation state that
  409. * supports @c cancellation_type::terminal values only. To change the
  410. * cancellation state, call the basic_yield_context member function
  411. * @c reset_cancellation_state.
  412. */
  413. template <typename ExecutionContext, typename F,
  414. BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
  415. typename result_of<F(basic_yield_context<
  416. typename ExecutionContext::executor_type>)>::type>::type)
  417. CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
  418. typename ExecutionContext::executor_type)>
  419. BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX(CompletionToken,
  420. typename detail::spawn_signature<
  421. typename result_of<F(basic_yield_context<
  422. typename ExecutionContext::executor_type>)>::type>::type)
  423. spawn(ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(F) function,
  424. BOOST_ASIO_MOVE_ARG(CompletionToken) token
  425. BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(
  426. typename ExecutionContext::executor_type),
  427. #if defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
  428. typename constraint<
  429. !is_same<
  430. typename decay<CompletionToken>::type,
  431. boost::coroutines::attributes
  432. >::value
  433. >::type = 0,
  434. #endif // defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
  435. typename constraint<
  436. is_convertible<ExecutionContext&, execution_context&>::value
  437. >::type = 0)
  438. BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_SUFFIX((
  439. async_initiate<CompletionToken,
  440. typename detail::spawn_signature<
  441. typename result_of<F(basic_yield_context<
  442. typename ExecutionContext::executor_type>)>::type>::type>(
  443. declval<detail::initiate_spawn<
  444. typename ExecutionContext::executor_type> >(),
  445. token, BOOST_ASIO_MOVE_CAST(F)(function))));
  446. /// Start a new stackful coroutine, inheriting the executor of another.
  447. /**
  448. * This function is used to launch a new stackful coroutine.
  449. *
  450. * @param ctx Identifies the current coroutine as a parent of the new
  451. * coroutine. This specifies that the new coroutine should inherit the executor
  452. * of the parent. For example, if the parent coroutine is executing in a
  453. * particular strand, then the new coroutine will execute in the same strand.
  454. *
  455. * @param function The coroutine function. The function must be callable the
  456. * signature:
  457. * @code void function(basic_yield_context<Executor> yield); @endcode
  458. *
  459. * @param token The @ref completion_token that will handle the notification
  460. * that the coroutine has completed. If the return type @c R of @c function is
  461. * @c void, the function signature of the completion handler must be:
  462. *
  463. * @code void handler(std::exception_ptr); @endcode
  464. * Otherwise, the function signature of the completion handler must be:
  465. * @code void handler(std::exception_ptr, R); @endcode
  466. *
  467. * @par Completion Signature
  468. * @code void(std::exception_ptr, R) @endcode
  469. * where @c R is the return type of the function object.
  470. *
  471. * @par Per-Operation Cancellation
  472. * The new thread of execution is created with a cancellation state that
  473. * supports @c cancellation_type::terminal values only. To change the
  474. * cancellation state, call the basic_yield_context member function
  475. * @c reset_cancellation_state.
  476. */
  477. template <typename Executor, typename F,
  478. BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
  479. typename result_of<F(basic_yield_context<Executor>)>::type>::type)
  480. CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
  481. BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX(CompletionToken,
  482. typename detail::spawn_signature<
  483. typename result_of<F(basic_yield_context<Executor>)>::type>::type)
  484. spawn(const basic_yield_context<Executor>& ctx,
  485. BOOST_ASIO_MOVE_ARG(F) function,
  486. BOOST_ASIO_MOVE_ARG(CompletionToken) token
  487. BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
  488. #if defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
  489. typename constraint<
  490. !is_same<
  491. typename decay<CompletionToken>::type,
  492. boost::coroutines::attributes
  493. >::value
  494. >::type = 0,
  495. #endif // defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
  496. typename constraint<
  497. is_executor<Executor>::value || execution::is_executor<Executor>::value
  498. >::type = 0)
  499. BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_SUFFIX((
  500. async_initiate<CompletionToken,
  501. typename detail::spawn_signature<
  502. typename result_of<F(basic_yield_context<Executor>)>::type>::type>(
  503. declval<detail::initiate_spawn<Executor> >(),
  504. token, BOOST_ASIO_MOVE_CAST(F)(function))));
  505. #if defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER) \
  506. || defined(GENERATING_DOCUMENTATION)
  507. /// Start a new stackful coroutine that executes on a given executor.
  508. /**
  509. * This function is used to launch a new stackful coroutine using the
  510. * specified stack allocator.
  511. *
  512. * @param ex Identifies the executor that will run the stackful coroutine.
  513. *
  514. * @param stack_allocator Denotes the allocator to be used to allocate the
  515. * underlying coroutine's stack. The type must satisfy the stack-allocator
  516. * concept defined by the Boost.Context library.
  517. *
  518. * @param function The coroutine function. The function must be callable the
  519. * signature:
  520. * @code void function(basic_yield_context<Executor> yield); @endcode
  521. *
  522. * @param token The @ref completion_token that will handle the notification
  523. * that the coroutine has completed. If the return type @c R of @c function is
  524. * @c void, the function signature of the completion handler must be:
  525. *
  526. * @code void handler(std::exception_ptr); @endcode
  527. * Otherwise, the function signature of the completion handler must be:
  528. * @code void handler(std::exception_ptr, R); @endcode
  529. *
  530. * @par Completion Signature
  531. * @code void(std::exception_ptr, R) @endcode
  532. * where @c R is the return type of the function object.
  533. *
  534. * @par Per-Operation Cancellation
  535. * The new thread of execution is created with a cancellation state that
  536. * supports @c cancellation_type::terminal values only. To change the
  537. * cancellation state, call the basic_yield_context member function
  538. * @c reset_cancellation_state.
  539. */
  540. template <typename Executor, typename StackAllocator, typename F,
  541. BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
  542. typename result_of<F(basic_yield_context<Executor>)>::type>::type)
  543. CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
  544. BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX(CompletionToken,
  545. typename detail::spawn_signature<
  546. typename result_of<F(basic_yield_context<Executor>)>::type>::type)
  547. spawn(const Executor& ex, allocator_arg_t,
  548. BOOST_ASIO_MOVE_ARG(StackAllocator) stack_allocator,
  549. BOOST_ASIO_MOVE_ARG(F) function,
  550. BOOST_ASIO_MOVE_ARG(CompletionToken) token
  551. BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
  552. typename constraint<
  553. is_executor<Executor>::value || execution::is_executor<Executor>::value
  554. >::type = 0)
  555. BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_SUFFIX((
  556. async_initiate<CompletionToken,
  557. typename detail::spawn_signature<
  558. typename result_of<F(basic_yield_context<Executor>)>::type>::type>(
  559. declval<detail::initiate_spawn<Executor> >(),
  560. token, allocator_arg_t(),
  561. BOOST_ASIO_MOVE_CAST(StackAllocator)(stack_allocator),
  562. BOOST_ASIO_MOVE_CAST(F)(function))));
  563. /// Start a new stackful coroutine that executes on a given execution context.
  564. /**
  565. * This function is used to launch a new stackful coroutine.
  566. *
  567. * @param ctx Identifies the execution context that will run the stackful
  568. * coroutine.
  569. *
  570. * @param stack_allocator Denotes the allocator to be used to allocate the
  571. * underlying coroutine's stack. The type must satisfy the stack-allocator
  572. * concept defined by the Boost.Context library.
  573. *
  574. * @param function The coroutine function. The function must be callable the
  575. * signature:
  576. * @code void function(basic_yield_context<Executor> yield); @endcode
  577. *
  578. * @param token The @ref completion_token that will handle the notification
  579. * that the coroutine has completed. If the return type @c R of @c function is
  580. * @c void, the function signature of the completion handler must be:
  581. *
  582. * @code void handler(std::exception_ptr); @endcode
  583. * Otherwise, the function signature of the completion handler must be:
  584. * @code void handler(std::exception_ptr, R); @endcode
  585. *
  586. * @par Completion Signature
  587. * @code void(std::exception_ptr, R) @endcode
  588. * where @c R is the return type of the function object.
  589. *
  590. * @par Per-Operation Cancellation
  591. * The new thread of execution is created with a cancellation state that
  592. * supports @c cancellation_type::terminal values only. To change the
  593. * cancellation state, call the basic_yield_context member function
  594. * @c reset_cancellation_state.
  595. */
  596. template <typename ExecutionContext, typename StackAllocator, typename F,
  597. BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
  598. typename result_of<F(basic_yield_context<
  599. typename ExecutionContext::executor_type>)>::type>::type)
  600. CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
  601. typename ExecutionContext::executor_type)>
  602. BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX(CompletionToken,
  603. typename detail::spawn_signature<
  604. typename result_of<F(basic_yield_context<
  605. typename ExecutionContext::executor_type>)>::type>::type)
  606. spawn(ExecutionContext& ctx, allocator_arg_t,
  607. BOOST_ASIO_MOVE_ARG(StackAllocator) stack_allocator,
  608. BOOST_ASIO_MOVE_ARG(F) function,
  609. BOOST_ASIO_MOVE_ARG(CompletionToken) token
  610. BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(
  611. typename ExecutionContext::executor_type),
  612. typename constraint<
  613. is_convertible<ExecutionContext&, execution_context&>::value
  614. >::type = 0)
  615. BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_SUFFIX((
  616. async_initiate<CompletionToken,
  617. typename detail::spawn_signature<
  618. typename result_of<F(basic_yield_context<
  619. typename ExecutionContext::executor_type>)>::type>::type>(
  620. declval<detail::initiate_spawn<
  621. typename ExecutionContext::executor_type> >(),
  622. token, allocator_arg_t(),
  623. BOOST_ASIO_MOVE_CAST(StackAllocator)(stack_allocator),
  624. BOOST_ASIO_MOVE_CAST(F)(function))));
  625. /// Start a new stackful coroutine, inheriting the executor of another.
  626. /**
  627. * This function is used to launch a new stackful coroutine using the
  628. * specified stack allocator.
  629. *
  630. * @param ctx Identifies the current coroutine as a parent of the new
  631. * coroutine. This specifies that the new coroutine should inherit the
  632. * executor of the parent. For example, if the parent coroutine is executing
  633. * in a particular strand, then the new coroutine will execute in the same
  634. * strand.
  635. *
  636. * @param stack_allocator Denotes the allocator to be used to allocate the
  637. * underlying coroutine's stack. The type must satisfy the stack-allocator
  638. * concept defined by the Boost.Context library.
  639. *
  640. * @param function The coroutine function. The function must be callable the
  641. * signature:
  642. * @code void function(basic_yield_context<Executor> yield); @endcode
  643. *
  644. * @param token The @ref completion_token that will handle the notification
  645. * that the coroutine has completed. If the return type @c R of @c function is
  646. * @c void, the function signature of the completion handler must be:
  647. *
  648. * @code void handler(std::exception_ptr); @endcode
  649. * Otherwise, the function signature of the completion handler must be:
  650. * @code void handler(std::exception_ptr, R); @endcode
  651. *
  652. * @par Completion Signature
  653. * @code void(std::exception_ptr, R) @endcode
  654. * where @c R is the return type of the function object.
  655. *
  656. * @par Per-Operation Cancellation
  657. * The new thread of execution is created with a cancellation state that
  658. * supports @c cancellation_type::terminal values only. To change the
  659. * cancellation state, call the basic_yield_context member function
  660. * @c reset_cancellation_state.
  661. */
  662. template <typename Executor, typename StackAllocator, typename F,
  663. BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
  664. typename result_of<F(basic_yield_context<Executor>)>::type>::type)
  665. CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
  666. BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX(CompletionToken,
  667. typename detail::spawn_signature<
  668. typename result_of<F(basic_yield_context<Executor>)>::type>::type)
  669. spawn(const basic_yield_context<Executor>& ctx, allocator_arg_t,
  670. BOOST_ASIO_MOVE_ARG(StackAllocator) stack_allocator,
  671. BOOST_ASIO_MOVE_ARG(F) function,
  672. BOOST_ASIO_MOVE_ARG(CompletionToken) token
  673. BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
  674. typename constraint<
  675. is_executor<Executor>::value || execution::is_executor<Executor>::value
  676. >::type = 0)
  677. BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_SUFFIX((
  678. async_initiate<CompletionToken,
  679. typename detail::spawn_signature<
  680. typename result_of<F(basic_yield_context<Executor>)>::type>::type>(
  681. declval<detail::initiate_spawn<Executor> >(),
  682. token, allocator_arg_t(),
  683. BOOST_ASIO_MOVE_CAST(StackAllocator)(stack_allocator),
  684. BOOST_ASIO_MOVE_CAST(F)(function))));
  685. #endif // defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
  686. // || defined(GENERATING_DOCUMENTATION)
  687. #if defined(BOOST_ASIO_HAS_BOOST_COROUTINE) \
  688. || defined(GENERATING_DOCUMENTATION)
  689. /// (Deprecated: Use overloads with a completion token.) Start a new stackful
  690. /// coroutine, calling the specified handler when it completes.
  691. /**
  692. * This function is used to launch a new coroutine.
  693. *
  694. * @param function The coroutine function. The function must have the signature:
  695. * @code void function(basic_yield_context<Executor> yield); @endcode
  696. * where Executor is the associated executor type of @c Function.
  697. *
  698. * @param attributes Boost.Coroutine attributes used to customise the coroutine.
  699. */
  700. template <typename Function>
  701. void spawn(BOOST_ASIO_MOVE_ARG(Function) function,
  702. const boost::coroutines::attributes& attributes
  703. = boost::coroutines::attributes());
  704. /// (Deprecated: Use overloads with a completion token.) Start a new stackful
  705. /// coroutine, calling the specified handler when it completes.
  706. /**
  707. * This function is used to launch a new coroutine.
  708. *
  709. * @param handler A handler to be called when the coroutine exits. More
  710. * importantly, the handler provides an execution context (via the the handler
  711. * invocation hook) for the coroutine. The handler must have the signature:
  712. * @code void handler(); @endcode
  713. *
  714. * @param function The coroutine function. The function must have the signature:
  715. * @code void function(basic_yield_context<Executor> yield); @endcode
  716. * where Executor is the associated executor type of @c Handler.
  717. *
  718. * @param attributes Boost.Coroutine attributes used to customise the coroutine.
  719. */
  720. template <typename Handler, typename Function>
  721. void spawn(BOOST_ASIO_MOVE_ARG(Handler) handler,
  722. BOOST_ASIO_MOVE_ARG(Function) function,
  723. const boost::coroutines::attributes& attributes
  724. = boost::coroutines::attributes(),
  725. typename constraint<
  726. !is_executor<typename decay<Handler>::type>::value &&
  727. !execution::is_executor<typename decay<Handler>::type>::value &&
  728. !is_convertible<Handler&, execution_context&>::value>::type = 0);
  729. /// (Deprecated: Use overloads with a completion token.) Start a new stackful
  730. /// coroutine, inheriting the execution context of another.
  731. /**
  732. * This function is used to launch a new coroutine.
  733. *
  734. * @param ctx Identifies the current coroutine as a parent of the new
  735. * coroutine. This specifies that the new coroutine should inherit the
  736. * execution context of the parent. For example, if the parent coroutine is
  737. * executing in a particular strand, then the new coroutine will execute in the
  738. * same strand.
  739. *
  740. * @param function The coroutine function. The function must have the signature:
  741. * @code void function(basic_yield_context<Executor> yield); @endcode
  742. *
  743. * @param attributes Boost.Coroutine attributes used to customise the coroutine.
  744. */
  745. template <typename Executor, typename Function>
  746. void spawn(basic_yield_context<Executor> ctx,
  747. BOOST_ASIO_MOVE_ARG(Function) function,
  748. const boost::coroutines::attributes& attributes
  749. = boost::coroutines::attributes());
  750. /// (Deprecated: Use overloads with a completion token.) Start a new stackful
  751. /// coroutine that executes on a given executor.
  752. /**
  753. * This function is used to launch a new coroutine.
  754. *
  755. * @param ex Identifies the executor that will run the coroutine. The new
  756. * coroutine is automatically given its own explicit strand within this
  757. * executor.
  758. *
  759. * @param function The coroutine function. The function must have the signature:
  760. * @code void function(yield_context yield); @endcode
  761. *
  762. * @param attributes Boost.Coroutine attributes used to customise the coroutine.
  763. */
  764. template <typename Function, typename Executor>
  765. void spawn(const Executor& ex,
  766. BOOST_ASIO_MOVE_ARG(Function) function,
  767. const boost::coroutines::attributes& attributes
  768. = boost::coroutines::attributes(),
  769. typename constraint<
  770. is_executor<Executor>::value || execution::is_executor<Executor>::value
  771. >::type = 0);
  772. /// (Deprecated: Use overloads with a completion token.) Start a new stackful
  773. /// coroutine that executes on a given strand.
  774. /**
  775. * This function is used to launch a new coroutine.
  776. *
  777. * @param ex Identifies the strand that will run the coroutine.
  778. *
  779. * @param function The coroutine function. The function must have the signature:
  780. * @code void function(yield_context yield); @endcode
  781. *
  782. * @param attributes Boost.Coroutine attributes used to customise the coroutine.
  783. */
  784. template <typename Function, typename Executor>
  785. void spawn(const strand<Executor>& ex,
  786. BOOST_ASIO_MOVE_ARG(Function) function,
  787. const boost::coroutines::attributes& attributes
  788. = boost::coroutines::attributes());
  789. #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
  790. /// (Deprecated: Use overloads with a completion token.) Start a new stackful
  791. /// coroutine that executes in the context of a strand.
  792. /**
  793. * This function is used to launch a new coroutine.
  794. *
  795. * @param s Identifies a strand. By starting multiple coroutines on the same
  796. * strand, the implementation ensures that none of those coroutines can execute
  797. * simultaneously.
  798. *
  799. * @param function The coroutine function. The function must have the signature:
  800. * @code void function(yield_context yield); @endcode
  801. *
  802. * @param attributes Boost.Coroutine attributes used to customise the coroutine.
  803. */
  804. template <typename Function>
  805. void spawn(const boost::asio::io_context::strand& s,
  806. BOOST_ASIO_MOVE_ARG(Function) function,
  807. const boost::coroutines::attributes& attributes
  808. = boost::coroutines::attributes());
  809. #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
  810. /// (Deprecated: Use overloads with a completion token.) Start a new stackful
  811. /// coroutine that executes on a given execution context.
  812. /**
  813. * This function is used to launch a new coroutine.
  814. *
  815. * @param ctx Identifies the execution context that will run the coroutine. The
  816. * new coroutine is implicitly given its own strand within this execution
  817. * context.
  818. *
  819. * @param function The coroutine function. The function must have the signature:
  820. * @code void function(yield_context yield); @endcode
  821. *
  822. * @param attributes Boost.Coroutine attributes used to customise the coroutine.
  823. */
  824. template <typename Function, typename ExecutionContext>
  825. void spawn(ExecutionContext& ctx,
  826. BOOST_ASIO_MOVE_ARG(Function) function,
  827. const boost::coroutines::attributes& attributes
  828. = boost::coroutines::attributes(),
  829. typename constraint<is_convertible<
  830. ExecutionContext&, execution_context&>::value>::type = 0);
  831. #endif // defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
  832. // || defined(GENERATING_DOCUMENTATION)
  833. /*@}*/
  834. } // namespace asio
  835. } // namespace boost
  836. #include <boost/asio/detail/pop_options.hpp>
  837. #include <boost/asio/impl/spawn.hpp>
  838. #endif // BOOST_ASIO_SPAWN_HPP