Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-05 08:27:43

0001 //
0002 // spawn.hpp
0003 // ~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2024 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 #if defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
0030 # include <boost/coroutine/all.hpp>
0031 #endif // defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
0032 
0033 #include <boost/asio/detail/push_options.hpp>
0034 
0035 namespace boost {
0036 namespace asio {
0037 namespace detail {
0038 
0039 // Base class for all spawn()-ed thread implementations.
0040 class spawned_thread_base
0041 {
0042 public:
0043   spawned_thread_base()
0044     : owner_(0),
0045       has_context_switched_(false),
0046       throw_if_cancelled_(false),
0047       terminal_(false)
0048   {
0049   }
0050 
0051   virtual ~spawned_thread_base() {}
0052   virtual void resume() = 0;
0053   virtual void suspend_with(void (*fn)(void*), void* arg) = 0;
0054   virtual void destroy() = 0;
0055 
0056   void attach(spawned_thread_base** owner)
0057   {
0058     owner_ = owner;
0059     *owner_ = this;
0060   }
0061 
0062   void detach()
0063   {
0064     if (owner_)
0065       *owner_ = 0;
0066     owner_ = 0;
0067   }
0068 
0069   void suspend()
0070   {
0071     suspend_with(0, 0);
0072   }
0073 
0074   template <typename F>
0075   void suspend_with(F f)
0076   {
0077     suspend_with(&spawned_thread_base::call<F>, &f);
0078   }
0079 
0080   cancellation_slot get_cancellation_slot() const noexcept
0081   {
0082     return cancellation_state_.slot();
0083   }
0084 
0085   cancellation_state get_cancellation_state() const noexcept
0086   {
0087     return cancellation_state_;
0088   }
0089 
0090   void reset_cancellation_state()
0091   {
0092     cancellation_state_ = cancellation_state(parent_cancellation_slot_);
0093   }
0094 
0095   template <typename Filter>
0096   void reset_cancellation_state(Filter filter)
0097   {
0098     cancellation_state_ = cancellation_state(
0099         parent_cancellation_slot_, filter, filter);
0100   }
0101 
0102   template <typename InFilter, typename OutFilter>
0103   void reset_cancellation_state(InFilter in_filter, OutFilter out_filter)
0104   {
0105     cancellation_state_ = cancellation_state(
0106         parent_cancellation_slot_, in_filter, out_filter);
0107   }
0108 
0109   cancellation_type_t cancelled() const noexcept
0110   {
0111     return cancellation_state_.cancelled();
0112   }
0113 
0114   bool has_context_switched() const noexcept
0115   {
0116     return has_context_switched_;
0117   }
0118 
0119   bool throw_if_cancelled() const noexcept
0120   {
0121     return throw_if_cancelled_;
0122   }
0123 
0124   void throw_if_cancelled(bool value) noexcept
0125   {
0126     throw_if_cancelled_ = value;
0127   }
0128 
0129 protected:
0130   spawned_thread_base** owner_; // Points to data member in active handler.
0131   boost::asio::cancellation_slot parent_cancellation_slot_;
0132   boost::asio::cancellation_state cancellation_state_;
0133   bool has_context_switched_;
0134   bool throw_if_cancelled_;
0135   bool terminal_;
0136 
0137 private:
0138   // Disallow copying and assignment.
0139   spawned_thread_base(const spawned_thread_base&) = delete;
0140   spawned_thread_base& operator=(const spawned_thread_base&) = delete;
0141 
0142   template <typename F>
0143   static void call(void* f)
0144   {
0145     (*static_cast<F*>(f))();
0146   }
0147 };
0148 
0149 template <typename T>
0150 struct spawn_signature
0151 {
0152   typedef void type(exception_ptr, T);
0153 };
0154 
0155 template <>
0156 struct spawn_signature<void>
0157 {
0158   typedef void type(exception_ptr);
0159 };
0160 
0161 template <typename Executor>
0162 class initiate_spawn;
0163 
0164 } // namespace detail
0165 
0166 /// A @ref completion_token that represents the currently executing coroutine.
0167 /**
0168  * The basic_yield_context class is a completion token type that is used to
0169  * represent the currently executing stackful coroutine. A basic_yield_context
0170  * object may be passed as a completion token to an asynchronous operation. For
0171  * example:
0172  *
0173  * @code template <typename Executor>
0174  * void my_coroutine(basic_yield_context<Executor> yield)
0175  * {
0176  *   ...
0177  *   std::size_t n = my_socket.async_read_some(buffer, yield);
0178  *   ...
0179  * } @endcode
0180  *
0181  * The initiating function (async_read_some in the above example) suspends the
0182  * current coroutine. The coroutine is resumed when the asynchronous operation
0183  * completes, and the result of the operation is returned.
0184  */
0185 template <typename Executor>
0186 class basic_yield_context
0187 {
0188 public:
0189   /// The executor type associated with the yield context.
0190   typedef Executor executor_type;
0191 
0192   /// The cancellation slot type associated with the yield context.
0193   typedef cancellation_slot cancellation_slot_type;
0194 
0195   /// Construct a yield context from another yield context type.
0196   /**
0197    * Requires that OtherExecutor be convertible to Executor.
0198    */
0199   template <typename OtherExecutor>
0200   basic_yield_context(const basic_yield_context<OtherExecutor>& other,
0201       constraint_t<
0202         is_convertible<OtherExecutor, Executor>::value
0203       > = 0)
0204     : spawned_thread_(other.spawned_thread_),
0205       executor_(other.executor_),
0206       ec_(other.ec_)
0207   {
0208   }
0209 
0210   /// Get the executor associated with the yield context.
0211   executor_type get_executor() const noexcept
0212   {
0213     return executor_;
0214   }
0215 
0216   /// Get the cancellation slot associated with the coroutine.
0217   cancellation_slot_type get_cancellation_slot() const noexcept
0218   {
0219     return spawned_thread_->get_cancellation_slot();
0220   }
0221 
0222   /// Get the cancellation state associated with the coroutine.
0223   cancellation_state get_cancellation_state() const noexcept
0224   {
0225     return spawned_thread_->get_cancellation_state();
0226   }
0227 
0228   /// Reset the cancellation state associated with the coroutine.
0229   /**
0230    * Let <tt>P</tt> be the cancellation slot associated with the current
0231    * coroutine's @ref spawn completion handler. Assigns a new
0232    * boost::asio::cancellation_state object <tt>S</tt>, constructed as
0233    * <tt>S(P)</tt>, into the current coroutine's cancellation state object.
0234    */
0235   void reset_cancellation_state() const
0236   {
0237     spawned_thread_->reset_cancellation_state();
0238   }
0239 
0240   /// Reset the cancellation state associated with the coroutine.
0241   /**
0242    * Let <tt>P</tt> be the cancellation slot associated with the current
0243    * coroutine's @ref spawn completion handler. Assigns a new
0244    * boost::asio::cancellation_state object <tt>S</tt>, constructed as <tt>S(P,
0245    * std::forward<Filter>(filter))</tt>, into the current coroutine's
0246    * cancellation state object.
0247    */
0248   template <typename Filter>
0249   void reset_cancellation_state(Filter&& filter) const
0250   {
0251     spawned_thread_->reset_cancellation_state(
0252         static_cast<Filter&&>(filter));
0253   }
0254 
0255   /// Reset the cancellation state associated with the coroutine.
0256   /**
0257    * Let <tt>P</tt> be the cancellation slot associated with the current
0258    * coroutine's @ref spawn completion handler. Assigns a new
0259    * boost::asio::cancellation_state object <tt>S</tt>, constructed as <tt>S(P,
0260    * std::forward<InFilter>(in_filter),
0261    * std::forward<OutFilter>(out_filter))</tt>, into the current coroutine's
0262    * cancellation state object.
0263    */
0264   template <typename InFilter, typename OutFilter>
0265   void reset_cancellation_state(InFilter&& in_filter,
0266       OutFilter&& out_filter) const
0267   {
0268     spawned_thread_->reset_cancellation_state(
0269         static_cast<InFilter&&>(in_filter),
0270         static_cast<OutFilter&&>(out_filter));
0271   }
0272 
0273   /// Determine whether the current coroutine has been cancelled.
0274   cancellation_type_t cancelled() const noexcept
0275   {
0276     return spawned_thread_->cancelled();
0277   }
0278 
0279   /// Determine whether the coroutine throws if trying to suspend when it has
0280   /// been cancelled.
0281   bool throw_if_cancelled() const noexcept
0282   {
0283     return spawned_thread_->throw_if_cancelled();
0284   }
0285 
0286   /// Set whether the coroutine throws if trying to suspend when it has been
0287   /// cancelled.
0288   void throw_if_cancelled(bool value) const noexcept
0289   {
0290     spawned_thread_->throw_if_cancelled(value);
0291   }
0292 
0293   /// Return a yield context that sets the specified error_code.
0294   /**
0295    * By default, when a yield context is used with an asynchronous operation, a
0296    * non-success error_code is converted to system_error and thrown. This
0297    * operator may be used to specify an error_code object that should instead be
0298    * set with the asynchronous operation's result. For example:
0299    *
0300    * @code template <typename Executor>
0301    * void my_coroutine(basic_yield_context<Executor> yield)
0302    * {
0303    *   ...
0304    *   std::size_t n = my_socket.async_read_some(buffer, yield[ec]);
0305    *   if (ec)
0306    *   {
0307    *     // An error occurred.
0308    *   }
0309    *   ...
0310    * } @endcode
0311    */
0312   basic_yield_context operator[](boost::system::error_code& ec) const
0313   {
0314     basic_yield_context tmp(*this);
0315     tmp.ec_ = &ec;
0316     return tmp;
0317   }
0318 
0319 #if !defined(GENERATING_DOCUMENTATION)
0320 //private:
0321   basic_yield_context(detail::spawned_thread_base* spawned_thread,
0322       const Executor& ex)
0323     : spawned_thread_(spawned_thread),
0324       executor_(ex),
0325       ec_(0)
0326   {
0327   }
0328 
0329   detail::spawned_thread_base* spawned_thread_;
0330   Executor executor_;
0331   boost::system::error_code* ec_;
0332 #endif // !defined(GENERATING_DOCUMENTATION)
0333 };
0334 
0335 /// A @ref completion_token object that represents the currently executing
0336 /// coroutine.
0337 typedef basic_yield_context<any_io_executor> yield_context;
0338 
0339 /**
0340  * @defgroup spawn boost::asio::spawn
0341  *
0342  * @brief Start a new stackful coroutine.
0343  *
0344  * The spawn() function is a high-level wrapper over the Boost.Coroutine
0345  * library. This function enables programs to implement asynchronous logic in a
0346  * synchronous manner, as illustrated by the following example:
0347  *
0348  * @code boost::asio::spawn(my_strand, do_echo, boost::asio::detached);
0349  *
0350  * // ...
0351  *
0352  * void do_echo(boost::asio::yield_context yield)
0353  * {
0354  *   try
0355  *   {
0356  *     char data[128];
0357  *     for (;;)
0358  *     {
0359  *       std::size_t length =
0360  *         my_socket.async_read_some(
0361  *           boost::asio::buffer(data), yield);
0362  *
0363  *       boost::asio::async_write(my_socket,
0364  *           boost::asio::buffer(data, length), yield);
0365  *     }
0366  *   }
0367  *   catch (std::exception& e)
0368  *   {
0369  *     // ...
0370  *   }
0371  * } @endcode
0372  */
0373 /*@{*/
0374 
0375 /// Start a new stackful coroutine that executes on a given executor.
0376 /**
0377  * This function is used to launch a new stackful coroutine.
0378  *
0379  * @param ex Identifies the executor that will run the stackful coroutine.
0380  *
0381  * @param function The coroutine function. The function must be callable the
0382  * signature:
0383  * @code void function(basic_yield_context<Executor> yield); @endcode
0384  *
0385  * @param token The @ref completion_token that will handle the notification
0386  * that the coroutine has completed. If the return type @c R of @c function is
0387  * @c void, the function signature of the completion handler must be:
0388  *
0389  * @code void handler(std::exception_ptr); @endcode
0390  * Otherwise, the function signature of the completion handler must be:
0391  * @code void handler(std::exception_ptr, R); @endcode
0392  *
0393  * @par Completion Signature
0394  * @code void(std::exception_ptr, R) @endcode
0395  * where @c R is the return type of the function object.
0396  *
0397  * @par Per-Operation Cancellation
0398  * The new thread of execution is created with a cancellation state that
0399  * supports @c cancellation_type::terminal values only. To change the
0400  * cancellation state, call the basic_yield_context member function
0401  * @c reset_cancellation_state.
0402  */
0403 template <typename Executor, typename F,
0404     BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
0405       result_of_t<F(basic_yield_context<Executor>)>>::type)
0406         CompletionToken = default_completion_token_t<Executor>>
0407 auto spawn(const Executor& ex, F&& function,
0408     CompletionToken&& token = default_completion_token_t<Executor>(),
0409 #if defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
0410     constraint_t<
0411       !is_same<
0412         decay_t<CompletionToken>,
0413         boost::coroutines::attributes
0414       >::value
0415     > = 0,
0416 #endif // defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
0417     constraint_t<
0418       is_executor<Executor>::value || execution::is_executor<Executor>::value
0419     > = 0)
0420   -> decltype(
0421     async_initiate<CompletionToken,
0422       typename detail::spawn_signature<
0423         result_of_t<F(basic_yield_context<Executor>)>>::type>(
0424           declval<detail::initiate_spawn<Executor>>(),
0425           token, static_cast<F&&>(function)));
0426 
0427 /// Start a new stackful coroutine that executes on a given execution context.
0428 /**
0429  * This function is used to launch a new stackful coroutine.
0430  *
0431  * @param ctx Identifies the execution context that will run the stackful
0432  * coroutine.
0433  *
0434  * @param function The coroutine function. The function must be callable the
0435  * signature:
0436  * @code void function(basic_yield_context<Executor> yield); @endcode
0437  *
0438  * @param token The @ref completion_token that will handle the notification
0439  * that the coroutine has completed. If the return type @c R of @c function is
0440  * @c void, the function signature of the completion handler must be:
0441  *
0442  * @code void handler(std::exception_ptr); @endcode
0443  * Otherwise, the function signature of the completion handler must be:
0444  * @code void handler(std::exception_ptr, R); @endcode
0445  *
0446  * @par Completion Signature
0447  * @code void(std::exception_ptr, R) @endcode
0448  * where @c R is the return type of the function object.
0449  *
0450  * @par Per-Operation Cancellation
0451  * The new thread of execution is created with a cancellation state that
0452  * supports @c cancellation_type::terminal values only. To change the
0453  * cancellation state, call the basic_yield_context member function
0454  * @c reset_cancellation_state.
0455  */
0456 template <typename ExecutionContext, typename F,
0457     BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
0458       result_of_t<F(basic_yield_context<
0459         typename ExecutionContext::executor_type>)>>::type)
0460           CompletionToken = default_completion_token_t<
0461             typename ExecutionContext::executor_type>>
0462 auto spawn(ExecutionContext& ctx, F&& function,
0463     CompletionToken&& token
0464       = default_completion_token_t<typename ExecutionContext::executor_type>(),
0465 #if defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
0466     constraint_t<
0467       !is_same<
0468         decay_t<CompletionToken>,
0469         boost::coroutines::attributes
0470       >::value
0471     > = 0,
0472 #endif // defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
0473     constraint_t<
0474       is_convertible<ExecutionContext&, execution_context&>::value
0475     > = 0)
0476   -> decltype(
0477     async_initiate<CompletionToken,
0478       typename detail::spawn_signature<
0479         result_of_t<F(basic_yield_context<
0480           typename ExecutionContext::executor_type>)>>::type>(
0481             declval<detail::initiate_spawn<
0482               typename ExecutionContext::executor_type>>(),
0483             token, static_cast<F&&>(function)));
0484 
0485 /// Start a new stackful coroutine, inheriting the executor of another.
0486 /**
0487  * This function is used to launch a new stackful coroutine.
0488  *
0489  * @param ctx Identifies the current coroutine as a parent of the new
0490  * coroutine. This specifies that the new coroutine should inherit the executor
0491  * of the parent. For example, if the parent coroutine is executing in a
0492  * particular strand, then the new coroutine will execute in the same strand.
0493  *
0494  * @param function The coroutine function. The function must be callable the
0495  * signature:
0496  * @code void function(basic_yield_context<Executor> yield); @endcode
0497  *
0498  * @param token The @ref completion_token that will handle the notification
0499  * that the coroutine has completed. If the return type @c R of @c function is
0500  * @c void, the function signature of the completion handler must be:
0501  *
0502  * @code void handler(std::exception_ptr); @endcode
0503  * Otherwise, the function signature of the completion handler must be:
0504  * @code void handler(std::exception_ptr, R); @endcode
0505  *
0506  * @par Completion Signature
0507  * @code void(std::exception_ptr, R) @endcode
0508  * where @c R is the return type of the function object.
0509  *
0510  * @par Per-Operation Cancellation
0511  * The new thread of execution is created with a cancellation state that
0512  * supports @c cancellation_type::terminal values only. To change the
0513  * cancellation state, call the basic_yield_context member function
0514  * @c reset_cancellation_state.
0515  */
0516 template <typename Executor, typename F,
0517     BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
0518       result_of_t<F(basic_yield_context<Executor>)>>::type)
0519         CompletionToken = default_completion_token_t<Executor>>
0520 auto spawn(const basic_yield_context<Executor>& ctx, F&& function,
0521     CompletionToken&& token = default_completion_token_t<Executor>(),
0522 #if defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
0523     constraint_t<
0524       !is_same<
0525         decay_t<CompletionToken>,
0526         boost::coroutines::attributes
0527       >::value
0528     > = 0,
0529 #endif // defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
0530     constraint_t<
0531       is_executor<Executor>::value || execution::is_executor<Executor>::value
0532     > = 0)
0533   -> decltype(
0534     async_initiate<CompletionToken,
0535       typename detail::spawn_signature<
0536         result_of_t<F(basic_yield_context<Executor>)>>::type>(
0537           declval<detail::initiate_spawn<Executor>>(),
0538           token, static_cast<F&&>(function)));
0539 
0540 #if defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER) \
0541   || defined(GENERATING_DOCUMENTATION)
0542 
0543 /// Start a new stackful coroutine that executes on a given executor.
0544 /**
0545  * This function is used to launch a new stackful coroutine using the
0546  * specified stack allocator.
0547  *
0548  * @param ex Identifies the executor that will run the stackful coroutine.
0549  *
0550  * @param stack_allocator Denotes the allocator to be used to allocate the
0551  * underlying coroutine's stack. The type must satisfy the stack-allocator
0552  * concept defined by the Boost.Context library.
0553  *
0554  * @param function The coroutine function. The function must be callable the
0555  * signature:
0556  * @code void function(basic_yield_context<Executor> yield); @endcode
0557  *
0558  * @param token The @ref completion_token that will handle the notification
0559  * that the coroutine has completed. If the return type @c R of @c function is
0560  * @c void, the function signature of the completion handler must be:
0561  *
0562  * @code void handler(std::exception_ptr); @endcode
0563  * Otherwise, the function signature of the completion handler must be:
0564  * @code void handler(std::exception_ptr, R); @endcode
0565  *
0566  * @par Completion Signature
0567  * @code void(std::exception_ptr, R) @endcode
0568  * where @c R is the return type of the function object.
0569  *
0570  * @par Per-Operation Cancellation
0571  * The new thread of execution is created with a cancellation state that
0572  * supports @c cancellation_type::terminal values only. To change the
0573  * cancellation state, call the basic_yield_context member function
0574  * @c reset_cancellation_state.
0575  */
0576 template <typename Executor, typename StackAllocator, typename F,
0577     BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
0578       result_of_t<F(basic_yield_context<Executor>)>>::type)
0579         CompletionToken = default_completion_token_t<Executor>>
0580 auto spawn(const Executor& ex, allocator_arg_t,
0581     StackAllocator&& stack_allocator, F&& function,
0582     CompletionToken&& token = default_completion_token_t<Executor>(),
0583     constraint_t<
0584       is_executor<Executor>::value || execution::is_executor<Executor>::value
0585     > = 0)
0586   -> decltype(
0587     async_initiate<CompletionToken,
0588       typename detail::spawn_signature<
0589         result_of_t<F(basic_yield_context<Executor>)>>::type>(
0590           declval<detail::initiate_spawn<Executor>>(),
0591           token, allocator_arg_t(),
0592           static_cast<StackAllocator&&>(stack_allocator),
0593           static_cast<F&&>(function)));
0594 
0595 /// Start a new stackful coroutine that executes on a given execution context.
0596 /**
0597  * This function is used to launch a new stackful coroutine.
0598  *
0599  * @param ctx Identifies the execution context that will run the stackful
0600  * coroutine.
0601  *
0602  * @param stack_allocator Denotes the allocator to be used to allocate the
0603  * underlying coroutine's stack. The type must satisfy the stack-allocator
0604  * concept defined by the Boost.Context library.
0605  *
0606  * @param function The coroutine function. The function must be callable the
0607  * signature:
0608  * @code void function(basic_yield_context<Executor> yield); @endcode
0609  *
0610  * @param token The @ref completion_token that will handle the notification
0611  * that the coroutine has completed. If the return type @c R of @c function is
0612  * @c void, the function signature of the completion handler must be:
0613  *
0614  * @code void handler(std::exception_ptr); @endcode
0615  * Otherwise, the function signature of the completion handler must be:
0616  * @code void handler(std::exception_ptr, R); @endcode
0617  *
0618  * @par Completion Signature
0619  * @code void(std::exception_ptr, R) @endcode
0620  * where @c R is the return type of the function object.
0621  *
0622  * @par Per-Operation Cancellation
0623  * The new thread of execution is created with a cancellation state that
0624  * supports @c cancellation_type::terminal values only. To change the
0625  * cancellation state, call the basic_yield_context member function
0626  * @c reset_cancellation_state.
0627  */
0628 template <typename ExecutionContext, typename StackAllocator, typename F,
0629     BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
0630       result_of_t<F(basic_yield_context<
0631         typename ExecutionContext::executor_type>)>>::type)
0632           CompletionToken = default_completion_token_t<
0633             typename ExecutionContext::executor_type>>
0634 auto spawn(ExecutionContext& ctx, allocator_arg_t,
0635     StackAllocator&& stack_allocator, F&& function,
0636     CompletionToken&& token
0637       = default_completion_token_t<typename ExecutionContext::executor_type>(),
0638     constraint_t<
0639       is_convertible<ExecutionContext&, execution_context&>::value
0640     > = 0)
0641   -> decltype(
0642     async_initiate<CompletionToken,
0643       typename detail::spawn_signature<
0644         result_of_t<F(basic_yield_context<
0645           typename ExecutionContext::executor_type>)>>::type>(
0646             declval<detail::initiate_spawn<
0647               typename ExecutionContext::executor_type>>(),
0648             token, allocator_arg_t(),
0649             static_cast<StackAllocator&&>(stack_allocator),
0650             static_cast<F&&>(function)));
0651 
0652 /// Start a new stackful coroutine, inheriting the executor of another.
0653 /**
0654  * This function is used to launch a new stackful coroutine using the
0655  * specified stack allocator.
0656  *
0657  * @param ctx Identifies the current coroutine as a parent of the new
0658  * coroutine. This specifies that the new coroutine should inherit the
0659  * executor of the parent. For example, if the parent coroutine is executing
0660  * in a particular strand, then the new coroutine will execute in the same
0661  * strand.
0662  *
0663  * @param stack_allocator Denotes the allocator to be used to allocate the
0664  * underlying coroutine's stack. The type must satisfy the stack-allocator
0665  * concept defined by the Boost.Context library.
0666  *
0667  * @param function The coroutine function. The function must be callable the
0668  * signature:
0669  * @code void function(basic_yield_context<Executor> yield); @endcode
0670  *
0671  * @param token The @ref completion_token that will handle the notification
0672  * that the coroutine has completed. If the return type @c R of @c function is
0673  * @c void, the function signature of the completion handler must be:
0674  *
0675  * @code void handler(std::exception_ptr); @endcode
0676  * Otherwise, the function signature of the completion handler must be:
0677  * @code void handler(std::exception_ptr, R); @endcode
0678  *
0679  * @par Completion Signature
0680  * @code void(std::exception_ptr, R) @endcode
0681  * where @c R is the return type of the function object.
0682  *
0683  * @par Per-Operation Cancellation
0684  * The new thread of execution is created with a cancellation state that
0685  * supports @c cancellation_type::terminal values only. To change the
0686  * cancellation state, call the basic_yield_context member function
0687  * @c reset_cancellation_state.
0688  */
0689 template <typename Executor, typename StackAllocator, typename F,
0690     BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
0691       result_of_t<F(basic_yield_context<Executor>)>>::type)
0692         CompletionToken = default_completion_token_t<Executor>>
0693 auto spawn(const basic_yield_context<Executor>& ctx, allocator_arg_t,
0694     StackAllocator&& stack_allocator, F&& function,
0695     CompletionToken&& token = default_completion_token_t<Executor>(),
0696     constraint_t<
0697       is_executor<Executor>::value || execution::is_executor<Executor>::value
0698     > = 0)
0699   -> decltype(
0700     async_initiate<CompletionToken,
0701       typename detail::spawn_signature<
0702         result_of_t<F(basic_yield_context<Executor>)>>::type>(
0703           declval<detail::initiate_spawn<Executor>>(),
0704           token, allocator_arg_t(),
0705           static_cast<StackAllocator&&>(stack_allocator),
0706           static_cast<F&&>(function)));
0707 
0708 #endif // defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
0709        //   || defined(GENERATING_DOCUMENTATION)
0710 
0711 #if defined(BOOST_ASIO_HAS_BOOST_COROUTINE) \
0712   || defined(GENERATING_DOCUMENTATION)
0713 
0714 /// (Deprecated: Use overloads with a completion token.) Start a new stackful
0715 /// coroutine, calling the specified handler when it completes.
0716 /**
0717  * This function is used to launch a new coroutine.
0718  *
0719  * @param function The coroutine function. The function must have the signature:
0720  * @code void function(basic_yield_context<Executor> yield); @endcode
0721  * where Executor is the associated executor type of @c Function.
0722  *
0723  * @param attributes Boost.Coroutine attributes used to customise the coroutine.
0724  */
0725 template <typename Function>
0726 void spawn(Function&& function,
0727     const boost::coroutines::attributes& attributes
0728       = boost::coroutines::attributes());
0729 
0730 /// (Deprecated: Use overloads with a completion token.) Start a new stackful
0731 /// coroutine, calling the specified handler when it completes.
0732 /**
0733  * This function is used to launch a new coroutine.
0734  *
0735  * @param handler A handler to be called when the coroutine exits. More
0736  * importantly, the handler provides an execution context (via the the handler
0737  * invocation hook) for the coroutine. The handler must have the signature:
0738  * @code void handler(); @endcode
0739  *
0740  * @param function The coroutine function. The function must have the signature:
0741  * @code void function(basic_yield_context<Executor> yield); @endcode
0742  * where Executor is the associated executor type of @c Handler.
0743  *
0744  * @param attributes Boost.Coroutine attributes used to customise the coroutine.
0745  */
0746 template <typename Handler, typename Function>
0747 void spawn(Handler&& handler, Function&& function,
0748     const boost::coroutines::attributes& attributes
0749       = boost::coroutines::attributes(),
0750     constraint_t<
0751       !is_executor<decay_t<Handler>>::value &&
0752       !execution::is_executor<decay_t<Handler>>::value &&
0753       !is_convertible<Handler&, execution_context&>::value
0754     > = 0);
0755 
0756 /// (Deprecated: Use overloads with a completion token.) Start a new stackful
0757 /// coroutine, inheriting the execution context of another.
0758 /**
0759  * This function is used to launch a new coroutine.
0760  *
0761  * @param ctx Identifies the current coroutine as a parent of the new
0762  * coroutine. This specifies that the new coroutine should inherit the
0763  * execution context of the parent. For example, if the parent coroutine is
0764  * executing in a particular strand, then the new coroutine will execute in the
0765  * same strand.
0766  *
0767  * @param function The coroutine function. The function must have the signature:
0768  * @code void function(basic_yield_context<Executor> yield); @endcode
0769  *
0770  * @param attributes Boost.Coroutine attributes used to customise the coroutine.
0771  */
0772 template <typename Executor, typename Function>
0773 void spawn(basic_yield_context<Executor> ctx, Function&& function,
0774     const boost::coroutines::attributes& attributes
0775       = boost::coroutines::attributes());
0776 
0777 /// (Deprecated: Use overloads with a completion token.) Start a new stackful
0778 /// coroutine that executes on a given executor.
0779 /**
0780  * This function is used to launch a new coroutine.
0781  *
0782  * @param ex Identifies the executor that will run the coroutine. The new
0783  * coroutine is automatically given its own explicit strand within this
0784  * executor.
0785  *
0786  * @param function The coroutine function. The function must have the signature:
0787  * @code void function(yield_context yield); @endcode
0788  *
0789  * @param attributes Boost.Coroutine attributes used to customise the coroutine.
0790  */
0791 template <typename Function, typename Executor>
0792 void spawn(const Executor& ex, Function&& function,
0793     const boost::coroutines::attributes& attributes
0794       = boost::coroutines::attributes(),
0795     constraint_t<
0796       is_executor<Executor>::value || execution::is_executor<Executor>::value
0797     > = 0);
0798 
0799 /// (Deprecated: Use overloads with a completion token.) Start a new stackful
0800 /// coroutine that executes on a given strand.
0801 /**
0802  * This function is used to launch a new coroutine.
0803  *
0804  * @param ex Identifies the strand that will run the coroutine.
0805  *
0806  * @param function The coroutine function. The function must have the signature:
0807  * @code void function(yield_context yield); @endcode
0808  *
0809  * @param attributes Boost.Coroutine attributes used to customise the coroutine.
0810  */
0811 template <typename Function, typename Executor>
0812 void spawn(const strand<Executor>& ex, Function&& function,
0813     const boost::coroutines::attributes& attributes
0814       = boost::coroutines::attributes());
0815 
0816 #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0817 
0818 /// (Deprecated: Use overloads with a completion token.) Start a new stackful
0819 /// coroutine that executes in the context of a strand.
0820 /**
0821  * This function is used to launch a new coroutine.
0822  *
0823  * @param s Identifies a strand. By starting multiple coroutines on the same
0824  * strand, the implementation ensures that none of those coroutines can execute
0825  * simultaneously.
0826  *
0827  * @param function The coroutine function. The function must have the signature:
0828  * @code void function(yield_context yield); @endcode
0829  *
0830  * @param attributes Boost.Coroutine attributes used to customise the coroutine.
0831  */
0832 template <typename Function>
0833 void spawn(const boost::asio::io_context::strand& s, Function&& function,
0834     const boost::coroutines::attributes& attributes
0835       = boost::coroutines::attributes());
0836 
0837 #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0838 
0839 /// (Deprecated: Use overloads with a completion token.) Start a new stackful
0840 /// coroutine that executes on a given execution context.
0841 /**
0842  * This function is used to launch a new coroutine.
0843  *
0844  * @param ctx Identifies the execution context that will run the coroutine. The
0845  * new coroutine is implicitly given its own strand within this execution
0846  * context.
0847  *
0848  * @param function The coroutine function. The function must have the signature:
0849  * @code void function(yield_context yield); @endcode
0850  *
0851  * @param attributes Boost.Coroutine attributes used to customise the coroutine.
0852  */
0853 template <typename Function, typename ExecutionContext>
0854 void spawn(ExecutionContext& ctx, Function&& function,
0855     const boost::coroutines::attributes& attributes
0856       = boost::coroutines::attributes(),
0857     constraint_t<
0858       is_convertible<ExecutionContext&, execution_context&>::value
0859     > = 0);
0860 
0861 #endif // defined(BOOST_ASIO_HAS_BOOST_COROUTINE)
0862        //   || defined(GENERATING_DOCUMENTATION)
0863 
0864 /*@}*/
0865 
0866 } // namespace asio
0867 } // namespace boost
0868 
0869 #include <boost/asio/detail/pop_options.hpp>
0870 
0871 #include <boost/asio/impl/spawn.hpp>
0872 
0873 #endif // BOOST_ASIO_SPAWN_HPP