Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-15 08:29:48

0001 //
0002 // impl/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_IMPL_SPAWN_HPP
0012 #define BOOST_ASIO_IMPL_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 <tuple>
0020 #include <boost/asio/associated_allocator.hpp>
0021 #include <boost/asio/associated_cancellation_slot.hpp>
0022 #include <boost/asio/associated_executor.hpp>
0023 #include <boost/asio/async_result.hpp>
0024 #include <boost/asio/bind_executor.hpp>
0025 #include <boost/asio/detail/atomic_count.hpp>
0026 #include <boost/asio/detail/bind_handler.hpp>
0027 #include <boost/asio/detail/handler_cont_helpers.hpp>
0028 #include <boost/asio/detail/memory.hpp>
0029 #include <boost/asio/detail/noncopyable.hpp>
0030 #include <boost/asio/detail/type_traits.hpp>
0031 #include <boost/asio/detail/utility.hpp>
0032 #include <boost/asio/disposition.hpp>
0033 #include <boost/asio/error.hpp>
0034 #include <boost/system/system_error.hpp>
0035 
0036 #if defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
0037 # include <boost/context/fiber.hpp>
0038 #endif // defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
0039 
0040 #include <boost/asio/detail/push_options.hpp>
0041 
0042 namespace boost {
0043 namespace asio {
0044 namespace detail {
0045 
0046 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0047 inline void spawned_thread_rethrow(void* ex)
0048 {
0049   if (*static_cast<exception_ptr*>(ex))
0050     rethrow_exception(*static_cast<exception_ptr*>(ex));
0051 }
0052 #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
0053 
0054 #if defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
0055 
0056 // Spawned thread implementation using Boost.Context's fiber.
0057 class spawned_fiber_thread : public spawned_thread_base
0058 {
0059 public:
0060   typedef boost::context::fiber fiber_type;
0061 
0062   spawned_fiber_thread(fiber_type&& caller)
0063     : caller_(static_cast<fiber_type&&>(caller)),
0064       on_suspend_fn_(0),
0065       on_suspend_arg_(0)
0066   {
0067   }
0068 
0069   template <typename StackAllocator, typename F>
0070   static spawned_thread_base* spawn(allocator_arg_t,
0071       StackAllocator&& stack_allocator,
0072       F&& f,
0073       cancellation_slot parent_cancel_slot = cancellation_slot(),
0074       cancellation_state cancel_state = cancellation_state())
0075   {
0076     spawned_fiber_thread* spawned_thread = 0;
0077     fiber_type callee(allocator_arg_t(),
0078         static_cast<StackAllocator&&>(stack_allocator),
0079         entry_point<decay_t<F>>(
0080           static_cast<F&&>(f), &spawned_thread));
0081     callee = fiber_type(static_cast<fiber_type&&>(callee)).resume();
0082     spawned_thread->callee_ = static_cast<fiber_type&&>(callee);
0083     spawned_thread->parent_cancellation_slot_ = parent_cancel_slot;
0084     spawned_thread->cancellation_state_ = cancel_state;
0085     return spawned_thread;
0086   }
0087 
0088   template <typename F>
0089   static spawned_thread_base* spawn(F&& f,
0090       cancellation_slot parent_cancel_slot = cancellation_slot(),
0091       cancellation_state cancel_state = cancellation_state())
0092   {
0093     return spawn(allocator_arg_t(), boost::context::fixedsize_stack(),
0094         static_cast<F&&>(f), parent_cancel_slot, cancel_state);
0095   }
0096 
0097   void resume()
0098   {
0099     callee_ = fiber_type(static_cast<fiber_type&&>(callee_)).resume();
0100     if (on_suspend_fn_)
0101     {
0102       void (*fn)(void*) = on_suspend_fn_;
0103       void* arg = on_suspend_arg_;
0104       on_suspend_fn_ = 0;
0105       fn(arg);
0106     }
0107   }
0108 
0109   void suspend_with(void (*fn)(void*), void* arg)
0110   {
0111     if (throw_if_cancelled_)
0112       if (!!cancellation_state_.cancelled())
0113         throw_error(boost::asio::error::operation_aborted, "yield");
0114     has_context_switched_ = true;
0115     on_suspend_fn_ = fn;
0116     on_suspend_arg_ = arg;
0117     caller_ = fiber_type(static_cast<fiber_type&&>(caller_)).resume();
0118   }
0119 
0120   void destroy()
0121   {
0122     fiber_type callee = static_cast<fiber_type&&>(callee_);
0123     if (terminal_)
0124       fiber_type(static_cast<fiber_type&&>(callee)).resume();
0125   }
0126 
0127 private:
0128   template <typename Function>
0129   class entry_point
0130   {
0131   public:
0132     template <typename F>
0133     entry_point(F&& f,
0134         spawned_fiber_thread** spawned_thread_out)
0135       : function_(static_cast<F&&>(f)),
0136         spawned_thread_out_(spawned_thread_out)
0137     {
0138     }
0139 
0140     fiber_type operator()(fiber_type&& caller)
0141     {
0142       Function function(static_cast<Function&&>(function_));
0143       spawned_fiber_thread spawned_thread(
0144           static_cast<fiber_type&&>(caller));
0145       *spawned_thread_out_ = &spawned_thread;
0146       spawned_thread_out_ = 0;
0147       spawned_thread.suspend();
0148 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0149       try
0150 #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
0151       {
0152         function(&spawned_thread);
0153         spawned_thread.terminal_ = true;
0154         spawned_thread.suspend();
0155       }
0156 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0157       catch (const boost::context::detail::forced_unwind&)
0158       {
0159         throw;
0160       }
0161       catch (...)
0162       {
0163         exception_ptr ex = current_exception();
0164         spawned_thread.terminal_ = true;
0165         spawned_thread.suspend_with(spawned_thread_rethrow, &ex);
0166       }
0167 #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
0168       return static_cast<fiber_type&&>(spawned_thread.caller_);
0169     }
0170 
0171   private:
0172     Function function_;
0173     spawned_fiber_thread** spawned_thread_out_;
0174   };
0175 
0176   fiber_type caller_;
0177   fiber_type callee_;
0178   void (*on_suspend_fn_)(void*);
0179   void* on_suspend_arg_;
0180 };
0181 
0182 #endif // defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
0183 
0184 #if defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
0185 typedef spawned_fiber_thread default_spawned_thread_type;
0186 #else
0187 # error No spawn() implementation available
0188 #endif
0189 
0190 // Helper class to perform the initial resume on the correct executor.
0191 class spawned_thread_resumer
0192 {
0193 public:
0194   explicit spawned_thread_resumer(spawned_thread_base* spawned_thread)
0195     : spawned_thread_(spawned_thread)
0196   {
0197   }
0198 
0199   spawned_thread_resumer(spawned_thread_resumer&& other) noexcept
0200     : spawned_thread_(other.spawned_thread_)
0201   {
0202     other.spawned_thread_ = 0;
0203   }
0204 
0205   ~spawned_thread_resumer()
0206   {
0207     if (spawned_thread_)
0208       spawned_thread_->destroy();
0209   }
0210 
0211   void operator()()
0212   {
0213     spawned_thread_->attach(&spawned_thread_);
0214     spawned_thread_->resume();
0215   }
0216 
0217 private:
0218   spawned_thread_base* spawned_thread_;
0219 };
0220 
0221 // Helper class to ensure spawned threads are destroyed on the correct executor.
0222 class spawned_thread_destroyer
0223 {
0224 public:
0225   explicit spawned_thread_destroyer(spawned_thread_base* spawned_thread)
0226     : spawned_thread_(spawned_thread)
0227   {
0228     spawned_thread->detach();
0229   }
0230 
0231   spawned_thread_destroyer(spawned_thread_destroyer&& other) noexcept
0232     : spawned_thread_(other.spawned_thread_)
0233   {
0234     other.spawned_thread_ = 0;
0235   }
0236 
0237   ~spawned_thread_destroyer()
0238   {
0239     if (spawned_thread_)
0240       spawned_thread_->destroy();
0241   }
0242 
0243   void operator()()
0244   {
0245     if (spawned_thread_)
0246     {
0247       spawned_thread_->destroy();
0248       spawned_thread_ = 0;
0249     }
0250   }
0251 
0252 private:
0253   spawned_thread_base* spawned_thread_;
0254 };
0255 
0256 // Base class for all completion handlers associated with a spawned thread.
0257 template <typename Executor>
0258 class spawn_handler_base
0259 {
0260 public:
0261   typedef Executor executor_type;
0262   typedef cancellation_slot cancellation_slot_type;
0263 
0264   spawn_handler_base(const basic_yield_context<Executor>& yield)
0265     : yield_(yield),
0266       spawned_thread_(yield.spawned_thread_)
0267   {
0268     spawned_thread_->detach();
0269   }
0270 
0271   spawn_handler_base(spawn_handler_base&& other) noexcept
0272     : yield_(other.yield_),
0273       spawned_thread_(other.spawned_thread_)
0274 
0275   {
0276     other.spawned_thread_ = 0;
0277   }
0278 
0279   ~spawn_handler_base()
0280   {
0281     if (spawned_thread_)
0282       (post)(yield_.executor_, spawned_thread_destroyer(spawned_thread_));
0283   }
0284 
0285   executor_type get_executor() const noexcept
0286   {
0287     return yield_.executor_;
0288   }
0289 
0290   cancellation_slot_type get_cancellation_slot() const noexcept
0291   {
0292     return spawned_thread_->get_cancellation_slot();
0293   }
0294 
0295   void resume()
0296   {
0297     spawned_thread_resumer resumer(spawned_thread_);
0298     spawned_thread_ = 0;
0299     resumer();
0300   }
0301 
0302 protected:
0303   const basic_yield_context<Executor>& yield_;
0304   spawned_thread_base* spawned_thread_;
0305 };
0306 
0307 // Completion handlers for when basic_yield_context is used as a token.
0308 template <typename Executor, typename Signature, typename = void>
0309 class spawn_handler;
0310 
0311 template <typename Executor, typename R>
0312 class spawn_handler<Executor, R()>
0313   : public spawn_handler_base<Executor>
0314 {
0315 public:
0316   typedef void return_type;
0317 
0318   struct result_type {};
0319 
0320   spawn_handler(const basic_yield_context<Executor>& yield, result_type&)
0321     : spawn_handler_base<Executor>(yield)
0322   {
0323   }
0324 
0325   void operator()()
0326   {
0327     this->resume();
0328   }
0329 
0330   static return_type on_resume(result_type&)
0331   {
0332   }
0333 };
0334 
0335 template <typename Executor, typename R>
0336 class spawn_handler<Executor, R(boost::system::error_code)>
0337   : public spawn_handler_base<Executor>
0338 {
0339 public:
0340   typedef void return_type;
0341   typedef boost::system::error_code* result_type;
0342 
0343   spawn_handler(const basic_yield_context<Executor>& yield, result_type& result)
0344     : spawn_handler_base<Executor>(yield),
0345       result_(result)
0346   {
0347   }
0348 
0349   void operator()(boost::system::error_code ec)
0350   {
0351     if (this->yield_.ec_)
0352     {
0353       *this->yield_.ec_ = ec;
0354       result_ = 0;
0355     }
0356     else
0357       result_ = &ec;
0358     this->resume();
0359   }
0360 
0361   static return_type on_resume(result_type& result)
0362   {
0363     if (result)
0364       throw_error(*result);
0365   }
0366 
0367 private:
0368   result_type& result_;
0369 };
0370 
0371 template <typename Executor, typename R, typename Disposition>
0372 class spawn_handler<Executor, R(Disposition),
0373     enable_if_t<is_disposition<Disposition>::value>
0374   > : public spawn_handler_base<Executor>
0375 {
0376 public:
0377   typedef void return_type;
0378   typedef Disposition* result_type;
0379 
0380   spawn_handler(const basic_yield_context<Executor>& yield, result_type& result)
0381     : spawn_handler_base<Executor>(yield),
0382       result_(result)
0383   {
0384   }
0385 
0386   void operator()(Disposition d)
0387   {
0388     result_ = detail::addressof(d);
0389     this->resume();
0390   }
0391 
0392   static return_type on_resume(result_type& result)
0393   {
0394     if (*result != no_error)
0395       boost::asio::throw_exception(static_cast<Disposition&&>(*result));
0396   }
0397 
0398 private:
0399   result_type& result_;
0400 };
0401 
0402 template <typename Executor, typename R, typename T>
0403 class spawn_handler<Executor, R(T),
0404     enable_if_t<!is_disposition<T>::value>
0405   > : public spawn_handler_base<Executor>
0406 {
0407 public:
0408   typedef T return_type;
0409   typedef return_type* result_type;
0410 
0411   spawn_handler(const basic_yield_context<Executor>& yield, result_type& result)
0412     : spawn_handler_base<Executor>(yield),
0413       result_(result)
0414   {
0415   }
0416 
0417   void operator()(T value)
0418   {
0419     result_ = detail::addressof(value);
0420     this->resume();
0421   }
0422 
0423   static return_type on_resume(result_type& result)
0424   {
0425     return static_cast<return_type&&>(*result);
0426   }
0427 
0428 private:
0429   result_type& result_;
0430 };
0431 
0432 template <typename Executor, typename R, typename T>
0433 class spawn_handler<Executor, R(boost::system::error_code, T)>
0434   : public spawn_handler_base<Executor>
0435 {
0436 public:
0437   typedef T return_type;
0438 
0439   struct result_type
0440   {
0441     boost::system::error_code* ec_;
0442     return_type* value_;
0443   };
0444 
0445   spawn_handler(const basic_yield_context<Executor>& yield, result_type& result)
0446     : spawn_handler_base<Executor>(yield),
0447       result_(result)
0448   {
0449   }
0450 
0451   void operator()(boost::system::error_code ec, T value)
0452   {
0453     if (this->yield_.ec_)
0454     {
0455       *this->yield_.ec_ = ec;
0456       result_.ec_ = 0;
0457     }
0458     else
0459       result_.ec_ = &ec;
0460     result_.value_ = detail::addressof(value);
0461     this->resume();
0462   }
0463 
0464   static return_type on_resume(result_type& result)
0465   {
0466     if (result.ec_)
0467       throw_error(*result.ec_);
0468     return static_cast<return_type&&>(*result.value_);
0469   }
0470 
0471 private:
0472   result_type& result_;
0473 };
0474 
0475 template <typename Executor, typename R, typename Disposition, typename T>
0476 class spawn_handler<Executor, R(Disposition, T),
0477     enable_if_t<is_disposition<Disposition>::value>
0478   > : public spawn_handler_base<Executor>
0479 {
0480 public:
0481   typedef T return_type;
0482 
0483   struct result_type
0484   {
0485     Disposition* disposition_;
0486     return_type* value_;
0487   };
0488 
0489   spawn_handler(const basic_yield_context<Executor>& yield, result_type& result)
0490     : spawn_handler_base<Executor>(yield),
0491       result_(result)
0492   {
0493   }
0494 
0495   void operator()(Disposition d, T value)
0496   {
0497     result_.disposition_ = detail::addressof(d);
0498     result_.value_ = detail::addressof(value);
0499     this->resume();
0500   }
0501 
0502   static return_type on_resume(result_type& result)
0503   {
0504     if (*result.disposition_ != no_error)
0505     {
0506       boost::asio::throw_exception(
0507           static_cast<Disposition&&>(*result.disposition_));
0508     }
0509     return static_cast<return_type&&>(*result.value_);
0510   }
0511 
0512 private:
0513   result_type& result_;
0514 };
0515 
0516 template <typename Executor, typename R, typename T, typename... Ts>
0517 class spawn_handler<Executor, R(T, Ts...),
0518     enable_if_t<!is_disposition<T>::value>
0519   > : public spawn_handler_base<Executor>
0520 {
0521 public:
0522   typedef std::tuple<T, Ts...> return_type;
0523 
0524   typedef return_type* result_type;
0525 
0526   spawn_handler(const basic_yield_context<Executor>& yield, result_type& result)
0527     : spawn_handler_base<Executor>(yield),
0528       result_(result)
0529   {
0530   }
0531 
0532   template <typename... Args>
0533   void operator()(Args&&... args)
0534   {
0535     return_type value(static_cast<Args&&>(args)...);
0536     result_ = detail::addressof(value);
0537     this->resume();
0538   }
0539 
0540   static return_type on_resume(result_type& result)
0541   {
0542     return static_cast<return_type&&>(*result);
0543   }
0544 
0545 private:
0546   result_type& result_;
0547 };
0548 
0549 template <typename Executor, typename R, typename... Ts>
0550 class spawn_handler<Executor, R(boost::system::error_code, Ts...)>
0551   : public spawn_handler_base<Executor>
0552 {
0553 public:
0554   typedef std::tuple<Ts...> return_type;
0555 
0556   struct result_type
0557   {
0558     boost::system::error_code* ec_;
0559     return_type* value_;
0560   };
0561 
0562   spawn_handler(const basic_yield_context<Executor>& yield, result_type& result)
0563     : spawn_handler_base<Executor>(yield),
0564       result_(result)
0565   {
0566   }
0567 
0568   template <typename... Args>
0569   void operator()(boost::system::error_code ec,
0570       Args&&... args)
0571   {
0572     return_type value(static_cast<Args&&>(args)...);
0573     if (this->yield_.ec_)
0574     {
0575       *this->yield_.ec_ = ec;
0576       result_.ec_ = 0;
0577     }
0578     else
0579       result_.ec_ = &ec;
0580     result_.value_ = detail::addressof(value);
0581     this->resume();
0582   }
0583 
0584   static return_type on_resume(result_type& result)
0585   {
0586     if (result.ec_)
0587       throw_error(*result.ec_);
0588     return static_cast<return_type&&>(*result.value_);
0589   }
0590 
0591 private:
0592   result_type& result_;
0593 };
0594 
0595 template <typename Executor, typename R, typename Disposition, typename... Ts>
0596 class spawn_handler<Executor, R(Disposition, Ts...),
0597     enable_if_t<is_disposition<Disposition>::value>
0598   > : public spawn_handler_base<Executor>
0599 {
0600 public:
0601   typedef std::tuple<Ts...> return_type;
0602 
0603   struct result_type
0604   {
0605     Disposition* disposition_;
0606     return_type* value_;
0607   };
0608 
0609   spawn_handler(const basic_yield_context<Executor>& yield, result_type& result)
0610     : spawn_handler_base<Executor>(yield),
0611       result_(result)
0612   {
0613   }
0614 
0615   template <typename... Args>
0616   void operator()(Disposition d, Args&&... args)
0617   {
0618     return_type value(static_cast<Args&&>(args)...);
0619     result_.disposition_ = detail::addressof(d);
0620     result_.value_ = detail::addressof(value);
0621     this->resume();
0622   }
0623 
0624   static return_type on_resume(result_type& result)
0625   {
0626     if (*result.disposition_ != no_error)
0627     {
0628       boost::asio::throw_exception(
0629           static_cast<Disposition&&>(*result.disposition_));
0630     }
0631     return static_cast<return_type&&>(*result.value_);
0632   }
0633 
0634 private:
0635   result_type& result_;
0636 };
0637 
0638 template <typename Executor, typename Signature>
0639 inline bool asio_handler_is_continuation(spawn_handler<Executor, Signature>*)
0640 {
0641   return true;
0642 }
0643 
0644 } // namespace detail
0645 
0646 #if !defined(GENERATING_DOCUMENTATION)
0647 
0648 template <typename Executor, typename Signature>
0649 class async_result<basic_yield_context<Executor>, Signature>
0650 {
0651 public:
0652   typedef typename detail::spawn_handler<Executor, Signature> handler_type;
0653   typedef typename handler_type::return_type return_type;
0654 
0655 #if defined(BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES)
0656 
0657   template <typename Initiation, typename... InitArgs>
0658   static return_type initiate(Initiation&& init,
0659       const basic_yield_context<Executor>& yield,
0660       InitArgs&&... init_args)
0661   {
0662     typename handler_type::result_type result
0663       = typename handler_type::result_type();
0664 
0665     yield.spawned_thread_->suspend_with(
0666         [&]()
0667         {
0668           static_cast<Initiation&&>(init)(
0669               handler_type(yield, result),
0670               static_cast<InitArgs&&>(init_args)...);
0671         });
0672 
0673     return handler_type::on_resume(result);
0674   }
0675 
0676 #else // defined(BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES)
0677 
0678   template <typename Initiation, typename... InitArgs>
0679   struct suspend_with_helper
0680   {
0681     typename handler_type::result_type& result_;
0682     Initiation&& init_;
0683     const basic_yield_context<Executor>& yield_;
0684     std::tuple<InitArgs&&...> init_args_;
0685 
0686     template <std::size_t... I>
0687     void do_invoke(detail::index_sequence<I...>)
0688     {
0689       static_cast<Initiation&&>(init_)(
0690           handler_type(yield_, result_),
0691           static_cast<InitArgs&&>(std::get<I>(init_args_))...);
0692     }
0693 
0694     void operator()()
0695     {
0696       this->do_invoke(detail::make_index_sequence<sizeof...(InitArgs)>());
0697     }
0698   };
0699 
0700   template <typename Initiation, typename... InitArgs>
0701   static return_type initiate(Initiation&& init,
0702       const basic_yield_context<Executor>& yield,
0703       InitArgs&&... init_args)
0704   {
0705     typename handler_type::result_type result
0706       = typename handler_type::result_type();
0707 
0708     yield.spawned_thread_->suspend_with(
0709       suspend_with_helper<Initiation, InitArgs...>{
0710           result, static_cast<Initiation&&>(init), yield,
0711           std::tuple<InitArgs&&...>(
0712             static_cast<InitArgs&&>(init_args)...)});
0713 
0714     return handler_type::on_resume(result);
0715   }
0716 
0717 #endif // defined(BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES)
0718 };
0719 
0720 #endif // !defined(GENERATING_DOCUMENTATION)
0721 
0722 namespace detail {
0723 
0724 template <typename Executor, typename Function, typename Handler>
0725 class spawn_entry_point
0726 {
0727 public:
0728   template <typename F, typename H>
0729   spawn_entry_point(const Executor& ex,
0730       F&& f, H&& h)
0731     : executor_(ex),
0732       function_(static_cast<F&&>(f)),
0733       handler_(static_cast<H&&>(h)),
0734       work_(handler_, executor_)
0735   {
0736   }
0737 
0738   void operator()(spawned_thread_base* spawned_thread)
0739   {
0740     const basic_yield_context<Executor> yield(spawned_thread, executor_);
0741     this->call(yield,
0742         void_type<result_of_t<Function(basic_yield_context<Executor>)>>());
0743   }
0744 
0745 private:
0746   void call(const basic_yield_context<Executor>& yield, void_type<void>)
0747   {
0748 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0749     try
0750 #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
0751     {
0752       function_(yield);
0753       if (!yield.spawned_thread_->has_context_switched())
0754         (post)(yield);
0755       detail::binder1<Handler, exception_ptr>
0756         handler(handler_, exception_ptr());
0757       work_.complete(handler, handler.handler_);
0758     }
0759 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0760 # if defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
0761     catch (const boost::context::detail::forced_unwind&)
0762     {
0763       throw;
0764     }
0765 # endif // defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
0766     catch (...)
0767     {
0768       exception_ptr ex = current_exception();
0769       if (!yield.spawned_thread_->has_context_switched())
0770         (post)(yield);
0771       detail::binder1<Handler, exception_ptr> handler(handler_, ex);
0772       work_.complete(handler, handler.handler_);
0773     }
0774 #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
0775   }
0776 
0777   template <typename T>
0778   void call(const basic_yield_context<Executor>& yield, void_type<T>)
0779   {
0780 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0781     try
0782 #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
0783     {
0784       T result(function_(yield));
0785       if (!yield.spawned_thread_->has_context_switched())
0786         (post)(yield);
0787       detail::move_binder2<Handler, exception_ptr, T>
0788         handler(0, static_cast<Handler&&>(handler_),
0789           exception_ptr(), static_cast<T&&>(result));
0790       work_.complete(handler, handler.handler_);
0791     }
0792 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0793 # if defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
0794     catch (const boost::context::detail::forced_unwind&)
0795     {
0796       throw;
0797     }
0798 # endif // defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
0799     catch (...)
0800     {
0801       exception_ptr ex = current_exception();
0802       if (!yield.spawned_thread_->has_context_switched())
0803         (post)(yield);
0804       detail::move_binder2<Handler, exception_ptr, T>
0805         handler(0, static_cast<Handler&&>(handler_), ex, T());
0806       work_.complete(handler, handler.handler_);
0807     }
0808 #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
0809   }
0810 
0811   Executor executor_;
0812   Function function_;
0813   Handler handler_;
0814   handler_work<Handler, Executor> work_;
0815 };
0816 
0817 struct spawn_cancellation_signal_emitter
0818 {
0819   cancellation_signal* signal_;
0820   cancellation_type_t type_;
0821 
0822   void operator()()
0823   {
0824     signal_->emit(type_);
0825   }
0826 };
0827 
0828 template <typename Handler, typename Executor, typename = void>
0829 class spawn_cancellation_handler
0830 {
0831 public:
0832   spawn_cancellation_handler(const Handler&, const Executor& ex)
0833     : ex_(ex)
0834   {
0835   }
0836 
0837   cancellation_slot slot()
0838   {
0839     return signal_.slot();
0840   }
0841 
0842   void operator()(cancellation_type_t type)
0843   {
0844     spawn_cancellation_signal_emitter emitter = { &signal_, type };
0845     (dispatch)(ex_, emitter);
0846   }
0847 
0848 private:
0849   cancellation_signal signal_;
0850   Executor ex_;
0851 };
0852 
0853 template <typename Handler, typename Executor>
0854 class spawn_cancellation_handler<Handler, Executor,
0855     enable_if_t<
0856       is_same<
0857         typename associated_executor<Handler,
0858           Executor>::asio_associated_executor_is_unspecialised,
0859         void
0860       >::value
0861     >>
0862 {
0863 public:
0864   spawn_cancellation_handler(const Handler&, const Executor&)
0865   {
0866   }
0867 
0868   cancellation_slot slot()
0869   {
0870     return signal_.slot();
0871   }
0872 
0873   void operator()(cancellation_type_t type)
0874   {
0875     signal_.emit(type);
0876   }
0877 
0878 private:
0879   cancellation_signal signal_;
0880 };
0881 
0882 template <typename Executor>
0883 class initiate_spawn
0884 {
0885 public:
0886   typedef Executor executor_type;
0887 
0888   explicit initiate_spawn(const executor_type& ex)
0889     : executor_(ex)
0890   {
0891   }
0892 
0893   executor_type get_executor() const noexcept
0894   {
0895     return executor_;
0896   }
0897 
0898   template <typename Handler, typename F>
0899   void operator()(Handler&& handler,
0900       F&& f) const
0901   {
0902     typedef decay_t<Handler> handler_type;
0903     typedef decay_t<F> function_type;
0904     typedef spawn_cancellation_handler<
0905       handler_type, Executor> cancel_handler_type;
0906 
0907     associated_cancellation_slot_t<handler_type> slot
0908       = boost::asio::get_associated_cancellation_slot(handler);
0909 
0910     cancel_handler_type* cancel_handler = slot.is_connected()
0911       ? &slot.template emplace<cancel_handler_type>(handler, executor_)
0912       : 0;
0913 
0914     cancellation_slot proxy_slot(
0915         cancel_handler
0916           ? cancel_handler->slot()
0917           : cancellation_slot());
0918 
0919     cancellation_state cancel_state(proxy_slot);
0920 
0921     (dispatch)(executor_,
0922         spawned_thread_resumer(
0923           default_spawned_thread_type::spawn(
0924             spawn_entry_point<Executor, function_type, handler_type>(
0925               executor_, static_cast<F&&>(f),
0926               static_cast<Handler&&>(handler)),
0927             proxy_slot, cancel_state)));
0928   }
0929 
0930 #if defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
0931 
0932   template <typename Handler, typename StackAllocator, typename F>
0933   void operator()(Handler&& handler, allocator_arg_t,
0934       StackAllocator&& stack_allocator,
0935       F&& f) const
0936   {
0937     typedef decay_t<Handler> handler_type;
0938     typedef decay_t<F> function_type;
0939     typedef spawn_cancellation_handler<
0940       handler_type, Executor> cancel_handler_type;
0941 
0942     associated_cancellation_slot_t<handler_type> slot
0943       = boost::asio::get_associated_cancellation_slot(handler);
0944 
0945     cancel_handler_type* cancel_handler = slot.is_connected()
0946       ? &slot.template emplace<cancel_handler_type>(handler, executor_)
0947       : 0;
0948 
0949     cancellation_slot proxy_slot(
0950         cancel_handler
0951           ? cancel_handler->slot()
0952           : cancellation_slot());
0953 
0954     cancellation_state cancel_state(proxy_slot);
0955 
0956     (dispatch)(executor_,
0957         spawned_thread_resumer(
0958           spawned_fiber_thread::spawn(allocator_arg_t(),
0959             static_cast<StackAllocator&&>(stack_allocator),
0960             spawn_entry_point<Executor, function_type, handler_type>(
0961               executor_, static_cast<F&&>(f),
0962               static_cast<Handler&&>(handler)),
0963             proxy_slot, cancel_state)));
0964   }
0965 
0966 #endif // defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
0967 
0968 private:
0969   executor_type executor_;
0970 };
0971 
0972 } // namespace detail
0973 
0974 template <typename Executor, typename F,
0975     BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
0976       result_of_t<F(basic_yield_context<Executor>)>>::type) CompletionToken>
0977 inline auto spawn(const Executor& ex, F&& function, CompletionToken&& token,
0978     constraint_t<
0979       is_executor<Executor>::value || execution::is_executor<Executor>::value
0980     >)
0981   -> decltype(
0982     async_initiate<CompletionToken,
0983       typename detail::spawn_signature<
0984         result_of_t<F(basic_yield_context<Executor>)>>::type>(
0985           declval<detail::initiate_spawn<Executor>>(),
0986           token, static_cast<F&&>(function)))
0987 {
0988   return async_initiate<CompletionToken,
0989     typename detail::spawn_signature<
0990       result_of_t<F(basic_yield_context<Executor>)>>::type>(
0991         detail::initiate_spawn<Executor>(ex),
0992         token, static_cast<F&&>(function));
0993 }
0994 
0995 template <typename ExecutionContext, typename F,
0996     BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
0997       result_of_t<F(basic_yield_context<
0998         typename ExecutionContext::executor_type>)>>::type) CompletionToken>
0999 inline auto spawn(ExecutionContext& ctx, F&& function, CompletionToken&& token,
1000     constraint_t<
1001       is_convertible<ExecutionContext&, execution_context&>::value
1002     >)
1003   -> decltype(
1004     async_initiate<CompletionToken,
1005       typename detail::spawn_signature<
1006         result_of_t<F(basic_yield_context<
1007           typename ExecutionContext::executor_type>)>>::type>(
1008             declval<detail::initiate_spawn<
1009               typename ExecutionContext::executor_type>>(),
1010             token, static_cast<F&&>(function)))
1011 {
1012   return (spawn)(ctx.get_executor(), static_cast<F&&>(function),
1013       static_cast<CompletionToken&&>(token));
1014 }
1015 
1016 template <typename Executor, typename F,
1017     BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
1018       result_of_t<F(basic_yield_context<Executor>)>>::type)
1019         CompletionToken>
1020 inline auto spawn(const basic_yield_context<Executor>& ctx,
1021     F&& function, CompletionToken&& token,
1022     constraint_t<
1023       is_executor<Executor>::value || execution::is_executor<Executor>::value
1024     >)
1025   -> decltype(
1026     async_initiate<CompletionToken,
1027       typename detail::spawn_signature<
1028         result_of_t<F(basic_yield_context<Executor>)>>::type>(
1029           declval<detail::initiate_spawn<Executor>>(),
1030           token, static_cast<F&&>(function)))
1031 {
1032   return (spawn)(ctx.get_executor(), static_cast<F&&>(function),
1033       static_cast<CompletionToken&&>(token));
1034 }
1035 
1036 #if defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
1037 
1038 template <typename Executor, typename StackAllocator, typename F,
1039     BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
1040       result_of_t<F(basic_yield_context<Executor>)>>::type)
1041         CompletionToken>
1042 inline auto spawn(const Executor& ex, allocator_arg_t,
1043     StackAllocator&& stack_allocator, F&& function, CompletionToken&& token,
1044     constraint_t<
1045       is_executor<Executor>::value || execution::is_executor<Executor>::value
1046     >)
1047   -> decltype(
1048     async_initiate<CompletionToken,
1049       typename detail::spawn_signature<
1050         result_of_t<F(basic_yield_context<Executor>)>>::type>(
1051           declval<detail::initiate_spawn<Executor>>(),
1052           token, allocator_arg_t(),
1053           static_cast<StackAllocator&&>(stack_allocator),
1054           static_cast<F&&>(function)))
1055 {
1056   return async_initiate<CompletionToken,
1057     typename detail::spawn_signature<
1058       result_of_t<F(basic_yield_context<Executor>)>>::type>(
1059         detail::initiate_spawn<Executor>(ex), token, allocator_arg_t(),
1060         static_cast<StackAllocator&&>(stack_allocator),
1061         static_cast<F&&>(function));
1062 }
1063 
1064 template <typename ExecutionContext, typename StackAllocator, typename F,
1065     BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
1066       result_of_t<F(basic_yield_context<
1067         typename ExecutionContext::executor_type>)>>::type) CompletionToken>
1068 inline auto spawn(ExecutionContext& ctx, allocator_arg_t,
1069     StackAllocator&& stack_allocator, F&& function, CompletionToken&& token,
1070     constraint_t<
1071       is_convertible<ExecutionContext&, execution_context&>::value
1072     >)
1073   -> decltype(
1074     async_initiate<CompletionToken,
1075       typename detail::spawn_signature<
1076         result_of_t<F(basic_yield_context<
1077           typename ExecutionContext::executor_type>)>>::type>(
1078             declval<detail::initiate_spawn<
1079               typename ExecutionContext::executor_type>>(),
1080             token, allocator_arg_t(),
1081             static_cast<StackAllocator&&>(stack_allocator),
1082             static_cast<F&&>(function)))
1083 {
1084   return (spawn)(ctx.get_executor(), allocator_arg_t(),
1085       static_cast<StackAllocator&&>(stack_allocator),
1086       static_cast<F&&>(function), static_cast<CompletionToken&&>(token));
1087 }
1088 
1089 template <typename Executor, typename StackAllocator, typename F,
1090     BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
1091       result_of_t<F(basic_yield_context<Executor>)>>::type) CompletionToken>
1092 inline auto spawn(const basic_yield_context<Executor>& ctx, allocator_arg_t,
1093     StackAllocator&& stack_allocator, F&& function, CompletionToken&& token,
1094     constraint_t<
1095       is_executor<Executor>::value || execution::is_executor<Executor>::value
1096     >)
1097   -> decltype(
1098     async_initiate<CompletionToken,
1099       typename detail::spawn_signature<
1100         result_of_t<F(basic_yield_context<Executor>)>>::type>(
1101           declval<detail::initiate_spawn<Executor>>(), token,
1102           allocator_arg_t(), static_cast<StackAllocator&&>(stack_allocator),
1103           static_cast<F&&>(function)))
1104 {
1105   return (spawn)(ctx.get_executor(), allocator_arg_t(),
1106       static_cast<StackAllocator&&>(stack_allocator),
1107       static_cast<F&&>(function), static_cast<CompletionToken&&>(token));
1108 }
1109 
1110 #endif // defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER)
1111 
1112 } // namespace asio
1113 } // namespace boost
1114 
1115 #include <boost/asio/detail/pop_options.hpp>
1116 
1117 #endif // BOOST_ASIO_IMPL_SPAWN_HPP