Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:29:11

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