Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-14 08:27:40

0001 //
0002 // spawn.hpp
0003 // ~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 //
0010 
0011 #ifndef BOOST_ASIO_SPAWN_HPP
0012 #define BOOST_ASIO_SPAWN_HPP
0013 
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0017 
0018 #include <boost/asio/detail/config.hpp>
0019 #include <boost/asio/any_io_executor.hpp>
0020 #include <boost/asio/cancellation_signal.hpp>
0021 #include <boost/asio/cancellation_state.hpp>
0022 #include <boost/asio/detail/exception.hpp>
0023 #include <boost/asio/detail/memory.hpp>
0024 #include <boost/asio/detail/type_traits.hpp>
0025 #include <boost/asio/io_context.hpp>
0026 #include <boost/asio/is_executor.hpp>
0027 #include <boost/asio/strand.hpp>
0028 
0029 #include <boost/asio/detail/push_options.hpp>
0030 
0031 namespace boost {
0032 namespace asio {
0033 namespace detail {
0034 
0035 // Base class for all spawn()-ed thread implementations.
0036 class spawned_thread_base
0037 {
0038 public:
0039   spawned_thread_base()
0040     : owner_(0),
0041       has_context_switched_(false),
0042       throw_if_cancelled_(false),
0043       terminal_(false)
0044   {
0045   }
0046 
0047   virtual ~spawned_thread_base() {}
0048   virtual void resume() = 0;
0049   virtual void suspend_with(void (*fn)(void*), void* arg) = 0;
0050   virtual void destroy() = 0;
0051 
0052   void attach(spawned_thread_base** owner)
0053   {
0054     owner_ = owner;
0055     *owner_ = this;
0056   }
0057 
0058   void detach()
0059   {
0060     if (owner_)
0061       *owner_ = 0;
0062     owner_ = 0;
0063   }
0064 
0065   void suspend()
0066   {
0067     suspend_with(0, 0);
0068   }
0069 
0070   template <typename F>
0071   void suspend_with(F f)
0072   {
0073     suspend_with(&spawned_thread_base::call<F>, &f);
0074   }
0075 
0076   cancellation_slot get_cancellation_slot() const noexcept
0077   {
0078     return cancellation_state_.slot();
0079   }
0080 
0081   cancellation_state get_cancellation_state() const noexcept
0082   {
0083     return cancellation_state_;
0084   }
0085 
0086   void reset_cancellation_state()
0087   {
0088     cancellation_state_ = cancellation_state(parent_cancellation_slot_);
0089   }
0090 
0091   template <typename Filter>
0092   void reset_cancellation_state(Filter filter)
0093   {
0094     cancellation_state_ = cancellation_state(
0095         parent_cancellation_slot_, filter, filter);
0096   }
0097 
0098   template <typename InFilter, typename OutFilter>
0099   void reset_cancellation_state(InFilter in_filter, OutFilter out_filter)
0100   {
0101     cancellation_state_ = cancellation_state(
0102         parent_cancellation_slot_, in_filter, out_filter);
0103   }
0104 
0105   cancellation_type_t cancelled() const noexcept
0106   {
0107     return cancellation_state_.cancelled();
0108   }
0109 
0110   bool has_context_switched() const noexcept
0111   {
0112     return has_context_switched_;
0113   }
0114 
0115   bool throw_if_cancelled() const noexcept
0116   {
0117     return throw_if_cancelled_;
0118   }
0119 
0120   void throw_if_cancelled(bool value) noexcept
0121   {
0122     throw_if_cancelled_ = value;
0123   }
0124 
0125 protected:
0126   spawned_thread_base** owner_; // Points to data member in active handler.
0127   boost::asio::cancellation_slot parent_cancellation_slot_;
0128   boost::asio::cancellation_state cancellation_state_;
0129   bool has_context_switched_;
0130   bool throw_if_cancelled_;
0131   bool terminal_;
0132 
0133 private:
0134   // Disallow copying and assignment.
0135   spawned_thread_base(const spawned_thread_base&) = delete;
0136   spawned_thread_base& operator=(const spawned_thread_base&) = delete;
0137 
0138   template <typename F>
0139   static void call(void* f)
0140   {
0141     (*static_cast<F*>(f))();
0142   }
0143 };
0144 
0145 template <typename T>
0146 struct spawn_signature
0147 {
0148   typedef void type(exception_ptr, T);
0149 };
0150 
0151 template <>
0152 struct spawn_signature<void>
0153 {
0154   typedef void type(exception_ptr);
0155 };
0156 
0157 template <typename Executor>
0158 class initiate_spawn;
0159 
0160 } // namespace detail
0161 
0162 /// A @ref completion_token that represents the currently executing coroutine.
0163 /**
0164  * The basic_yield_context class is a completion token type that is used to
0165  * represent the currently executing stackful coroutine. A basic_yield_context
0166  * object may be passed as a completion token to an asynchronous operation. For
0167  * example:
0168  *
0169  * @code template <typename Executor>
0170  * void my_coroutine(basic_yield_context<Executor> yield)
0171  * {
0172  *   ...
0173  *   std::size_t n = my_socket.async_read_some(buffer, yield);
0174  *   ...
0175  * } @endcode
0176  *
0177  * The initiating function (async_read_some in the above example) suspends the
0178  * current coroutine. The coroutine is resumed when the asynchronous operation
0179  * completes, and the result of the operation is returned.
0180  */
0181 template <typename Executor>
0182 class basic_yield_context
0183 {
0184 public:
0185   /// The executor type associated with the yield context.
0186   typedef Executor executor_type;
0187 
0188   /// The cancellation slot type associated with the yield context.
0189   typedef cancellation_slot cancellation_slot_type;
0190 
0191   /// Construct a yield context from another yield context type.
0192   /**
0193    * Requires that OtherExecutor be convertible to Executor.
0194    */
0195   template <typename OtherExecutor>
0196   basic_yield_context(const basic_yield_context<OtherExecutor>& other,
0197       constraint_t<
0198         is_convertible<OtherExecutor, Executor>::value
0199       > = 0)
0200     : spawned_thread_(other.spawned_thread_),
0201       executor_(other.executor_),
0202       ec_(other.ec_)
0203   {
0204   }
0205 
0206   /// Get the executor associated with the yield context.
0207   executor_type get_executor() const noexcept
0208   {
0209     return executor_;
0210   }
0211 
0212   /// Get the cancellation slot associated with the coroutine.
0213   cancellation_slot_type get_cancellation_slot() const noexcept
0214   {
0215     return spawned_thread_->get_cancellation_slot();
0216   }
0217 
0218   /// Get the cancellation state associated with the coroutine.
0219   cancellation_state get_cancellation_state() const noexcept
0220   {
0221     return spawned_thread_->get_cancellation_state();
0222   }
0223 
0224   /// Reset the cancellation state associated with the coroutine.
0225   /**
0226    * Let <tt>P</tt> be the cancellation slot associated with the current
0227    * coroutine's @ref spawn completion handler. Assigns a new
0228    * boost::asio::cancellation_state object <tt>S</tt>, constructed as
0229    * <tt>S(P)</tt>, into the current coroutine's cancellation state object.
0230    */
0231   void reset_cancellation_state() const
0232   {
0233     spawned_thread_->reset_cancellation_state();
0234   }
0235 
0236   /// Reset the cancellation state associated with the coroutine.
0237   /**
0238    * Let <tt>P</tt> be the cancellation slot associated with the current
0239    * coroutine's @ref spawn completion handler. Assigns a new
0240    * boost::asio::cancellation_state object <tt>S</tt>, constructed as <tt>S(P,
0241    * std::forward<Filter>(filter))</tt>, into the current coroutine's
0242    * cancellation state object.
0243    */
0244   template <typename Filter>
0245   void reset_cancellation_state(Filter&& filter) const
0246   {
0247     spawned_thread_->reset_cancellation_state(
0248         static_cast<Filter&&>(filter));
0249   }
0250 
0251   /// Reset the cancellation state associated with the coroutine.
0252   /**
0253    * Let <tt>P</tt> be the cancellation slot associated with the current
0254    * coroutine's @ref spawn completion handler. Assigns a new
0255    * boost::asio::cancellation_state object <tt>S</tt>, constructed as <tt>S(P,
0256    * std::forward<InFilter>(in_filter),
0257    * std::forward<OutFilter>(out_filter))</tt>, into the current coroutine's
0258    * cancellation state object.
0259    */
0260   template <typename InFilter, typename OutFilter>
0261   void reset_cancellation_state(InFilter&& in_filter,
0262       OutFilter&& out_filter) const
0263   {
0264     spawned_thread_->reset_cancellation_state(
0265         static_cast<InFilter&&>(in_filter),
0266         static_cast<OutFilter&&>(out_filter));
0267   }
0268 
0269   /// Determine whether the current coroutine has been cancelled.
0270   cancellation_type_t cancelled() const noexcept
0271   {
0272     return spawned_thread_->cancelled();
0273   }
0274 
0275   /// Determine whether the coroutine throws if trying to suspend when it has
0276   /// been cancelled.
0277   bool throw_if_cancelled() const noexcept
0278   {
0279     return spawned_thread_->throw_if_cancelled();
0280   }
0281 
0282   /// Set whether the coroutine throws if trying to suspend when it has been
0283   /// cancelled.
0284   void throw_if_cancelled(bool value) const noexcept
0285   {
0286     spawned_thread_->throw_if_cancelled(value);
0287   }
0288 
0289   /// Return a yield context that sets the specified error_code.
0290   /**
0291    * By default, when a yield context is used with an asynchronous operation, a
0292    * non-success error_code is converted to system_error and thrown. This
0293    * operator may be used to specify an error_code object that should instead be
0294    * set with the asynchronous operation's result. For example:
0295    *
0296    * @code template <typename Executor>
0297    * void my_coroutine(basic_yield_context<Executor> yield)
0298    * {
0299    *   ...
0300    *   std::size_t n = my_socket.async_read_some(buffer, yield[ec]);
0301    *   if (ec)
0302    *   {
0303    *     // An error occurred.
0304    *   }
0305    *   ...
0306    * } @endcode
0307    */
0308   basic_yield_context operator[](boost::system::error_code& ec) const
0309   {
0310     basic_yield_context tmp(*this);
0311     tmp.ec_ = &ec;
0312     return tmp;
0313   }
0314 
0315 #if !defined(GENERATING_DOCUMENTATION)
0316 //private:
0317   basic_yield_context(detail::spawned_thread_base* spawned_thread,
0318       const Executor& ex)
0319     : spawned_thread_(spawned_thread),
0320       executor_(ex),
0321       ec_(0)
0322   {
0323   }
0324 
0325   detail::spawned_thread_base* spawned_thread_;
0326   Executor executor_;
0327   boost::system::error_code* ec_;
0328 #endif // !defined(GENERATING_DOCUMENTATION)
0329 };
0330 
0331 /// A @ref completion_token object that represents the currently executing
0332 /// coroutine.
0333 typedef basic_yield_context<any_io_executor> yield_context;
0334 
0335 /**
0336  * @defgroup spawn boost::asio::spawn
0337  *
0338  * @brief Start a new stackful coroutine.
0339  *
0340  * The spawn() function is a high-level wrapper over the Boost.Coroutine
0341  * library. This function enables programs to implement asynchronous logic in a
0342  * synchronous manner, as illustrated by the following example:
0343  *
0344  * @code boost::asio::spawn(my_strand, do_echo, boost::asio::detached);
0345  *
0346  * // ...
0347  *
0348  * void do_echo(boost::asio::yield_context yield)
0349  * {
0350  *   try
0351  *   {
0352  *     char data[128];
0353  *     for (;;)
0354  *     {
0355  *       std::size_t length =
0356  *         my_socket.async_read_some(
0357  *           boost::asio::buffer(data), yield);
0358  *
0359  *       boost::asio::async_write(my_socket,
0360  *           boost::asio::buffer(data, length), yield);
0361  *     }
0362  *   }
0363  *   catch (std::exception& e)
0364  *   {
0365  *     // ...
0366  *   }
0367  * } @endcode
0368  */
0369 /*@{*/
0370 
0371 /// Start a new stackful coroutine that executes on a given executor.
0372 /**
0373  * This function is used to launch a new stackful coroutine.
0374  *
0375  * @param ex Identifies the executor that will run the stackful coroutine.
0376  *
0377  * @param function The coroutine function. The function must be callable the
0378  * signature:
0379  * @code void function(basic_yield_context<Executor> yield); @endcode
0380  *
0381  * @param token The @ref completion_token that will handle the notification
0382  * that the coroutine has completed. If the return type @c R of @c function is
0383  * @c void, the function signature of the completion handler must be:
0384  *
0385  * @code void handler(std::exception_ptr); @endcode
0386  * Otherwise, the function signature of the completion handler must be:
0387  * @code void handler(std::exception_ptr, R); @endcode
0388  *
0389  * @par Completion Signature
0390  * @code void(std::exception_ptr, R) @endcode
0391  * where @c R is the return type of the function object.
0392  *
0393  * @par Per-Operation Cancellation
0394  * The new thread of execution is created with a cancellation state that
0395  * supports @c cancellation_type::terminal values only. To change the
0396  * cancellation state, call the basic_yield_context member function
0397  * @c reset_cancellation_state.
0398  */
0399 template <typename Executor, typename F,
0400     BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
0401       result_of_t<F(basic_yield_context<Executor>)>>::type)
0402         CompletionToken = default_completion_token_t<Executor>>
0403 auto spawn(const Executor& ex, F&& function,
0404     CompletionToken&& token = default_completion_token_t<Executor>(),
0405     constraint_t<
0406       is_executor<Executor>::value || execution::is_executor<Executor>::value
0407     > = 0)
0408   -> decltype(
0409     async_initiate<CompletionToken,
0410       typename detail::spawn_signature<
0411         result_of_t<F(basic_yield_context<Executor>)>>::type>(
0412           declval<detail::initiate_spawn<Executor>>(),
0413           token, static_cast<F&&>(function)));
0414 
0415 /// Start a new stackful coroutine that executes on a given execution context.
0416 /**
0417  * This function is used to launch a new stackful coroutine.
0418  *
0419  * @param ctx Identifies the execution context that will run the stackful
0420  * coroutine.
0421  *
0422  * @param function The coroutine function. The function must be callable the
0423  * signature:
0424  * @code void function(basic_yield_context<Executor> yield); @endcode
0425  *
0426  * @param token The @ref completion_token that will handle the notification
0427  * that the coroutine has completed. If the return type @c R of @c function is
0428  * @c void, the function signature of the completion handler must be:
0429  *
0430  * @code void handler(std::exception_ptr); @endcode
0431  * Otherwise, the function signature of the completion handler must be:
0432  * @code void handler(std::exception_ptr, R); @endcode
0433  *
0434  * @par Completion Signature
0435  * @code void(std::exception_ptr, R) @endcode
0436  * where @c R is the return type of the function object.
0437  *
0438  * @par Per-Operation Cancellation
0439  * The new thread of execution is created with a cancellation state that
0440  * supports @c cancellation_type::terminal values only. To change the
0441  * cancellation state, call the basic_yield_context member function
0442  * @c reset_cancellation_state.
0443  */
0444 template <typename ExecutionContext, typename F,
0445     BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
0446       result_of_t<F(basic_yield_context<
0447         typename ExecutionContext::executor_type>)>>::type)
0448           CompletionToken = default_completion_token_t<
0449             typename ExecutionContext::executor_type>>
0450 auto spawn(ExecutionContext& ctx, F&& function,
0451     CompletionToken&& token
0452       = default_completion_token_t<typename ExecutionContext::executor_type>(),
0453     constraint_t<
0454       is_convertible<ExecutionContext&, execution_context&>::value
0455     > = 0)
0456   -> decltype(
0457     async_initiate<CompletionToken,
0458       typename detail::spawn_signature<
0459         result_of_t<F(basic_yield_context<
0460           typename ExecutionContext::executor_type>)>>::type>(
0461             declval<detail::initiate_spawn<
0462               typename ExecutionContext::executor_type>>(),
0463             token, static_cast<F&&>(function)));
0464 
0465 /// Start a new stackful coroutine, inheriting the executor of another.
0466 /**
0467  * This function is used to launch a new stackful coroutine.
0468  *
0469  * @param ctx Identifies the current coroutine as a parent of the new
0470  * coroutine. This specifies that the new coroutine should inherit the executor
0471  * of the parent. For example, if the parent coroutine is executing in a
0472  * particular strand, then the new coroutine will execute in the same strand.
0473  *
0474  * @param function The coroutine function. The function must be callable the
0475  * signature:
0476  * @code void function(basic_yield_context<Executor> yield); @endcode
0477  *
0478  * @param token The @ref completion_token that will handle the notification
0479  * that the coroutine has completed. If the return type @c R of @c function is
0480  * @c void, the function signature of the completion handler must be:
0481  *
0482  * @code void handler(std::exception_ptr); @endcode
0483  * Otherwise, the function signature of the completion handler must be:
0484  * @code void handler(std::exception_ptr, R); @endcode
0485  *
0486  * @par Completion Signature
0487  * @code void(std::exception_ptr, R) @endcode
0488  * where @c R is the return type of the function object.
0489  *
0490  * @par Per-Operation Cancellation
0491  * The new thread of execution is created with a cancellation state that
0492  * supports @c cancellation_type::terminal values only. To change the
0493  * cancellation state, call the basic_yield_context member function
0494  * @c reset_cancellation_state.
0495  */
0496 template <typename Executor, typename F,
0497     BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
0498       result_of_t<F(basic_yield_context<Executor>)>>::type)
0499         CompletionToken = default_completion_token_t<Executor>>
0500 auto spawn(const basic_yield_context<Executor>& ctx, F&& function,
0501     CompletionToken&& token = default_completion_token_t<Executor>(),
0502     constraint_t<
0503       is_executor<Executor>::value || execution::is_executor<Executor>::value
0504     > = 0)
0505   -> decltype(
0506     async_initiate<CompletionToken,
0507       typename detail::spawn_signature<
0508         result_of_t<F(basic_yield_context<Executor>)>>::type>(
0509           declval<detail::initiate_spawn<Executor>>(),
0510           token, static_cast<F&&>(function)));
0511 
0512 #if defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER) \
0513   || defined(GENERATING_DOCUMENTATION)
0514 
0515 /// Start a new stackful coroutine that executes on a given executor.
0516 /**
0517  * This function is used to launch a new stackful coroutine using the
0518  * specified stack allocator.
0519  *
0520  * @param ex Identifies the executor that will run the stackful coroutine.
0521  *
0522  * @param stack_allocator Denotes the allocator to be used to allocate the
0523  * underlying coroutine's stack. The type must satisfy the stack-allocator
0524  * concept defined by the Boost.Context library.
0525  *
0526  * @param function The coroutine function. The function must be callable the
0527  * signature:
0528  * @code void function(basic_yield_context<Executor> yield); @endcode
0529  *
0530  * @param token The @ref completion_token that will handle the notification
0531  * that the coroutine has completed. If the return type @c R of @c function is
0532  * @c void, the function signature of the completion handler must be:
0533  *
0534  * @code void handler(std::exception_ptr); @endcode
0535  * Otherwise, the function signature of the completion handler must be:
0536  * @code void handler(std::exception_ptr, R); @endcode
0537  *
0538  * @par Completion Signature
0539  * @code void(std::exception_ptr, R) @endcode
0540  * where @c R is the return type of the function object.
0541  *
0542  * @par Per-Operation Cancellation
0543  * The new thread of execution is created with a cancellation state that
0544  * supports @c cancellation_type::terminal values only. To change the
0545  * cancellation state, call the basic_yield_context member function
0546  * @c reset_cancellation_state.
0547  */
0548 template <typename Executor, typename StackAllocator, typename F,
0549     BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
0550       result_of_t<F(basic_yield_context<Executor>)>>::type)
0551         CompletionToken = default_completion_token_t<Executor>>
0552 auto spawn(const Executor& ex, allocator_arg_t,
0553     StackAllocator&& stack_allocator, F&& function,
0554     CompletionToken&& token = default_completion_token_t<Executor>(),
0555     constraint_t<
0556       is_executor<Executor>::value || execution::is_executor<Executor>::value
0557     > = 0)
0558   -> decltype(
0559     async_initiate<CompletionToken,
0560       typename detail::spawn_signature<
0561         result_of_t<F(basic_yield_context<Executor>)>>::type>(
0562           declval<detail::initiate_spawn<Executor>>(),
0563           token, allocator_arg_t(),
0564           static_cast<StackAllocator&&>(stack_allocator),
0565           static_cast<F&&>(function)));
0566 
0567 /// Start a new stackful coroutine that executes on a given execution context.
0568 /**
0569  * This function is used to launch a new stackful coroutine.
0570  *
0571  * @param ctx Identifies the execution context that will run the stackful
0572  * coroutine.
0573  *
0574  * @param stack_allocator Denotes the allocator to be used to allocate the
0575  * underlying coroutine's stack. The type must satisfy the stack-allocator
0576  * concept defined by the Boost.Context library.
0577  *
0578  * @param function The coroutine function. The function must be callable the
0579  * signature:
0580  * @code void function(basic_yield_context<Executor> yield); @endcode
0581  *
0582  * @param token The @ref completion_token that will handle the notification
0583  * that the coroutine has completed. If the return type @c R of @c function is
0584  * @c void, the function signature of the completion handler must be:
0585  *
0586  * @code void handler(std::exception_ptr); @endcode
0587  * Otherwise, the function signature of the completion handler must be:
0588  * @code void handler(std::exception_ptr, R); @endcode
0589  *
0590  * @par Completion Signature
0591  * @code void(std::exception_ptr, R) @endcode
0592  * where @c R is the return type of the function object.
0593  *
0594  * @par Per-Operation Cancellation
0595  * The new thread of execution is created with a cancellation state that
0596  * supports @c cancellation_type::terminal values only. To change the
0597  * cancellation state, call the basic_yield_context member function
0598  * @c reset_cancellation_state.
0599  */
0600 template <typename ExecutionContext, typename StackAllocator, typename F,
0601     BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
0602       result_of_t<F(basic_yield_context<
0603         typename ExecutionContext::executor_type>)>>::type)
0604           CompletionToken = default_completion_token_t<
0605             typename ExecutionContext::executor_type>>
0606 auto spawn(ExecutionContext& ctx, allocator_arg_t,
0607     StackAllocator&& stack_allocator, F&& function,
0608     CompletionToken&& token
0609       = default_completion_token_t<typename ExecutionContext::executor_type>(),
0610     constraint_t<
0611       is_convertible<ExecutionContext&, execution_context&>::value
0612     > = 0)
0613   -> decltype(
0614     async_initiate<CompletionToken,
0615       typename detail::spawn_signature<
0616         result_of_t<F(basic_yield_context<
0617           typename ExecutionContext::executor_type>)>>::type>(
0618             declval<detail::initiate_spawn<
0619               typename ExecutionContext::executor_type>>(),
0620             token, allocator_arg_t(),
0621             static_cast<StackAllocator&&>(stack_allocator),
0622             static_cast<F&&>(function)));
0623 
0624 /// Start a new stackful coroutine, inheriting the executor of another.
0625 /**
0626  * This function is used to launch a new stackful coroutine using the
0627  * specified stack allocator.
0628  *
0629  * @param ctx Identifies the current coroutine as a parent of the new
0630  * coroutine. This specifies that the new coroutine should inherit the
0631  * executor of the parent. For example, if the parent coroutine is executing
0632  * in a particular strand, then the new coroutine will execute in the same
0633  * strand.
0634  *
0635  * @param stack_allocator Denotes the allocator to be used to allocate the
0636  * underlying coroutine's stack. The type must satisfy the stack-allocator
0637  * concept defined by the Boost.Context library.
0638  *
0639  * @param function The coroutine function. The function must be callable the
0640  * signature:
0641  * @code void function(basic_yield_context<Executor> yield); @endcode
0642  *
0643  * @param token The @ref completion_token that will handle the notification
0644  * that the coroutine has completed. If the return type @c R of @c function is
0645  * @c void, the function signature of the completion handler must be:
0646  *
0647  * @code void handler(std::exception_ptr); @endcode
0648  * Otherwise, the function signature of the completion handler must be:
0649  * @code void handler(std::exception_ptr, R); @endcode
0650  *
0651  * @par Completion Signature
0652  * @code void(std::exception_ptr, R) @endcode
0653  * where @c R is the return type of the function object.
0654  *
0655  * @par Per-Operation Cancellation
0656  * The new thread of execution is created with a cancellation state that
0657  * supports @c cancellation_type::terminal values only. To change the
0658  * cancellation state, call the basic_yield_context member function
0659  * @c reset_cancellation_state.
0660  */
0661 template <typename Executor, typename StackAllocator, typename F,
0662     BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
0663       result_of_t<F(basic_yield_context<Executor>)>>::type)
0664         CompletionToken = default_completion_token_t<Executor>>
0665 auto spawn(const basic_yield_context<Executor>& ctx, allocator_arg_t,
0666     StackAllocator&& stack_allocator, F&& function,
0667     CompletionToken&& token = default_completion_token_t<Executor>(),
0668     constraint_t<
0669       is_executor<Executor>::value || execution::is_executor<Executor>::value
0670     > = 0)
0671   -> decltype(
0672     async_initiate<CompletionToken,
0673       typename detail::spawn_signature<
0674         result_of_t<F(basic_yield_context<Executor>)>>::type>(
0675           declval<detail::initiate_spawn<Executor>>(),
0676           token, allocator_arg_t(),
0677           static_cast<StackAllocator&&>(stack_allocator),
0678           static_cast<F&&>(function)));
0679 
0680 #endif // defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
0681        //   || defined(GENERATING_DOCUMENTATION)
0682 
0683 /*@}*/
0684 
0685 } // namespace asio
0686 } // namespace boost
0687 
0688 #include <boost/asio/detail/pop_options.hpp>
0689 
0690 #include <boost/asio/impl/spawn.hpp>
0691 
0692 #endif // BOOST_ASIO_SPAWN_HPP