1617 lines
		
	
	
		
			44 KiB
		
	
	
	
		
			C++
		
	
	
	
		
		
			
		
	
	
			1617 lines
		
	
	
		
			44 KiB
		
	
	
	
		
			C++
		
	
	
	
|  | //
 | ||
|  | // impl/spawn.hpp
 | ||
|  | // ~~~~~~~~~~~~~~
 | ||
|  | //
 | ||
|  | // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 | ||
|  | //
 | ||
|  | // Distributed under the Boost Software License, Version 1.0. (See accompanying
 | ||
|  | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 | ||
|  | //
 | ||
|  | 
 | ||
|  | #ifndef ASIO_IMPL_SPAWN_HPP
 | ||
|  | #define ASIO_IMPL_SPAWN_HPP
 | ||
|  | 
 | ||
|  | #if defined(_MSC_VER) && (_MSC_VER >= 1200)
 | ||
|  | # pragma once
 | ||
|  | #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 | ||
|  | 
 | ||
|  | #include "asio/detail/config.hpp"
 | ||
|  | #include "asio/associated_allocator.hpp"
 | ||
|  | #include "asio/associated_cancellation_slot.hpp"
 | ||
|  | #include "asio/associated_executor.hpp"
 | ||
|  | #include "asio/async_result.hpp"
 | ||
|  | #include "asio/bind_executor.hpp"
 | ||
|  | #include "asio/detail/atomic_count.hpp"
 | ||
|  | #include "asio/detail/bind_handler.hpp"
 | ||
|  | #include "asio/detail/handler_alloc_helpers.hpp"
 | ||
|  | #include "asio/detail/handler_cont_helpers.hpp"
 | ||
|  | #include "asio/detail/handler_invoke_helpers.hpp"
 | ||
|  | #include "asio/detail/memory.hpp"
 | ||
|  | #include "asio/detail/noncopyable.hpp"
 | ||
|  | #include "asio/detail/type_traits.hpp"
 | ||
|  | #include "asio/detail/utility.hpp"
 | ||
|  | #include "asio/detail/variadic_templates.hpp"
 | ||
|  | #include "asio/system_error.hpp"
 | ||
|  | 
 | ||
|  | #if defined(ASIO_HAS_STD_TUPLE)
 | ||
|  | # include <tuple>
 | ||
|  | #endif // defined(ASIO_HAS_STD_TUPLE)
 | ||
|  | 
 | ||
|  | #if defined(ASIO_HAS_BOOST_CONTEXT_FIBER)
 | ||
|  | # include <boost/context/fiber.hpp>
 | ||
|  | #endif // defined(ASIO_HAS_BOOST_CONTEXT_FIBER)
 | ||
|  | 
 | ||
|  | #include "asio/detail/push_options.hpp"
 | ||
|  | 
 | ||
|  | namespace asio { | ||
|  | namespace detail { | ||
|  | 
 | ||
|  | #if !defined(ASIO_NO_EXCEPTIONS)
 | ||
|  | inline void spawned_thread_rethrow(void* ex) | ||
|  | { | ||
|  |   if (*static_cast<exception_ptr*>(ex)) | ||
|  |     rethrow_exception(*static_cast<exception_ptr*>(ex)); | ||
|  | } | ||
|  | #endif // !defined(ASIO_NO_EXCEPTIONS)
 | ||
|  | 
 | ||
|  | #if defined(ASIO_HAS_BOOST_COROUTINE)
 | ||
|  | 
 | ||
|  | // Spawned thread implementation using Boost.Coroutine.
 | ||
|  | class spawned_coroutine_thread : public spawned_thread_base | ||
|  | { | ||
|  | public: | ||
|  | #if defined(BOOST_COROUTINES_UNIDIRECT) || defined(BOOST_COROUTINES_V2)
 | ||
|  |   typedef boost::coroutines::pull_coroutine<void> callee_type; | ||
|  |   typedef boost::coroutines::push_coroutine<void> caller_type; | ||
|  | #else
 | ||
|  |   typedef boost::coroutines::coroutine<void()> callee_type; | ||
|  |   typedef boost::coroutines::coroutine<void()> caller_type; | ||
|  | #endif
 | ||
|  | 
 | ||
|  |   spawned_coroutine_thread(caller_type& caller) | ||
|  |     : caller_(caller), | ||
|  |       on_suspend_fn_(0), | ||
|  |       on_suspend_arg_(0) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   template <typename F> | ||
|  |   static spawned_thread_base* spawn(ASIO_MOVE_ARG(F) f, | ||
|  |       const boost::coroutines::attributes& attributes, | ||
|  |       cancellation_slot parent_cancel_slot = cancellation_slot(), | ||
|  |       cancellation_state cancel_state = cancellation_state()) | ||
|  |   { | ||
|  |     spawned_coroutine_thread* spawned_thread = 0; | ||
|  |     callee_type callee(entry_point<typename decay<F>::type>( | ||
|  |           ASIO_MOVE_CAST(F)(f), &spawned_thread), attributes); | ||
|  |     spawned_thread->callee_.swap(callee); | ||
|  |     spawned_thread->parent_cancellation_slot_ = parent_cancel_slot; | ||
|  |     spawned_thread->cancellation_state_ = cancel_state; | ||
|  |     return spawned_thread; | ||
|  |   } | ||
|  | 
 | ||
|  |   template <typename F> | ||
|  |   static spawned_thread_base* spawn(ASIO_MOVE_ARG(F) f, | ||
|  |       cancellation_slot parent_cancel_slot = cancellation_slot(), | ||
|  |       cancellation_state cancel_state = cancellation_state()) | ||
|  |   { | ||
|  |     return spawn(ASIO_MOVE_CAST(F)(f), boost::coroutines::attributes(), | ||
|  |         parent_cancel_slot, cancel_state); | ||
|  |   } | ||
|  | 
 | ||
|  |   void resume() | ||
|  |   { | ||
|  |     callee_(); | ||
|  |     if (on_suspend_fn_) | ||
|  |     { | ||
|  |       void (*fn)(void*) = on_suspend_fn_; | ||
|  |       void* arg = on_suspend_arg_; | ||
|  |       on_suspend_fn_ = 0; | ||
|  |       fn(arg); | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   void suspend_with(void (*fn)(void*), void* arg) | ||
|  |   { | ||
|  |     if (throw_if_cancelled_) | ||
|  |       if (!!cancellation_state_.cancelled()) | ||
|  |         throw_error(asio::error::operation_aborted, "yield"); | ||
|  |     has_context_switched_ = true; | ||
|  |     on_suspend_fn_ = fn; | ||
|  |     on_suspend_arg_ = arg; | ||
|  |     caller_(); | ||
|  |   } | ||
|  | 
 | ||
|  |   void destroy() | ||
|  |   { | ||
|  |     callee_type callee; | ||
|  |     callee.swap(callee_); | ||
|  |     if (terminal_) | ||
|  |       callee(); | ||
|  |   } | ||
|  | 
 | ||
|  | private: | ||
|  |   template <typename Function> | ||
|  |   class entry_point | ||
|  |   { | ||
|  |   public: | ||
|  |     template <typename F> | ||
|  |     entry_point(ASIO_MOVE_ARG(F) f, | ||
|  |         spawned_coroutine_thread** spawned_thread_out) | ||
|  |       : function_(ASIO_MOVE_CAST(F)(f)), | ||
|  |         spawned_thread_out_(spawned_thread_out) | ||
|  |     { | ||
|  |     } | ||
|  | 
 | ||
|  |     void operator()(caller_type& caller) | ||
|  |     { | ||
|  |       Function function(ASIO_MOVE_CAST(Function)(function_)); | ||
|  |       spawned_coroutine_thread spawned_thread(caller); | ||
|  |       *spawned_thread_out_ = &spawned_thread; | ||
|  |       spawned_thread_out_ = 0; | ||
|  |       spawned_thread.suspend(); | ||
|  | #if !defined(ASIO_NO_EXCEPTIONS)
 | ||
|  |       try | ||
|  | #endif // !defined(ASIO_NO_EXCEPTIONS)
 | ||
|  |       { | ||
|  |         function(&spawned_thread); | ||
|  |         spawned_thread.terminal_ = true; | ||
|  |         spawned_thread.suspend(); | ||
|  |       } | ||
|  | #if !defined(ASIO_NO_EXCEPTIONS)
 | ||
|  |       catch (const boost::coroutines::detail::forced_unwind&) | ||
|  |       { | ||
|  |         throw; | ||
|  |       } | ||
|  |       catch (...) | ||
|  |       { | ||
|  |         exception_ptr ex = current_exception(); | ||
|  |         spawned_thread.terminal_ = true; | ||
|  |         spawned_thread.suspend_with(spawned_thread_rethrow, &ex); | ||
|  |       } | ||
|  | #endif // !defined(ASIO_NO_EXCEPTIONS)
 | ||
|  |     } | ||
|  | 
 | ||
|  |   private: | ||
|  |     Function function_; | ||
|  |     spawned_coroutine_thread** spawned_thread_out_; | ||
|  |   }; | ||
|  | 
 | ||
|  |   caller_type& caller_; | ||
|  |   callee_type callee_; | ||
|  |   void (*on_suspend_fn_)(void*); | ||
|  |   void* on_suspend_arg_; | ||
|  | }; | ||
|  | 
 | ||
|  | #endif // defined(ASIO_HAS_BOOST_COROUTINE)
 | ||
|  | 
 | ||
|  | #if defined(ASIO_HAS_BOOST_CONTEXT_FIBER)
 | ||
|  | 
 | ||
|  | // Spawned thread implementation using Boost.Context's fiber.
 | ||
|  | class spawned_fiber_thread : public spawned_thread_base | ||
|  | { | ||
|  | public: | ||
|  |   typedef boost::context::fiber fiber_type; | ||
|  | 
 | ||
|  |   spawned_fiber_thread(ASIO_MOVE_ARG(fiber_type) caller) | ||
|  |     : caller_(ASIO_MOVE_CAST(fiber_type)(caller)), | ||
|  |       on_suspend_fn_(0), | ||
|  |       on_suspend_arg_(0) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   template <typename StackAllocator, typename F> | ||
|  |   static spawned_thread_base* spawn(allocator_arg_t, | ||
|  |       ASIO_MOVE_ARG(StackAllocator) stack_allocator, | ||
|  |       ASIO_MOVE_ARG(F) f, | ||
|  |       cancellation_slot parent_cancel_slot = cancellation_slot(), | ||
|  |       cancellation_state cancel_state = cancellation_state()) | ||
|  |   { | ||
|  |     spawned_fiber_thread* spawned_thread = 0; | ||
|  |     fiber_type callee(allocator_arg_t(), | ||
|  |         ASIO_MOVE_CAST(StackAllocator)(stack_allocator), | ||
|  |         entry_point<typename decay<F>::type>( | ||
|  |           ASIO_MOVE_CAST(F)(f), &spawned_thread)); | ||
|  |     callee = fiber_type(ASIO_MOVE_CAST(fiber_type)(callee)).resume(); | ||
|  |     spawned_thread->callee_ = ASIO_MOVE_CAST(fiber_type)(callee); | ||
|  |     spawned_thread->parent_cancellation_slot_ = parent_cancel_slot; | ||
|  |     spawned_thread->cancellation_state_ = cancel_state; | ||
|  |     return spawned_thread; | ||
|  |   } | ||
|  | 
 | ||
|  |   template <typename F> | ||
|  |   static spawned_thread_base* spawn(ASIO_MOVE_ARG(F) f, | ||
|  |       cancellation_slot parent_cancel_slot = cancellation_slot(), | ||
|  |       cancellation_state cancel_state = cancellation_state()) | ||
|  |   { | ||
|  |     return spawn(allocator_arg_t(), boost::context::fixedsize_stack(), | ||
|  |         ASIO_MOVE_CAST(F)(f), parent_cancel_slot, cancel_state); | ||
|  |   } | ||
|  | 
 | ||
|  |   void resume() | ||
|  |   { | ||
|  |     callee_ = fiber_type(ASIO_MOVE_CAST(fiber_type)(callee_)).resume(); | ||
|  |     if (on_suspend_fn_) | ||
|  |     { | ||
|  |       void (*fn)(void*) = on_suspend_fn_; | ||
|  |       void* arg = on_suspend_arg_; | ||
|  |       on_suspend_fn_ = 0; | ||
|  |       fn(arg); | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   void suspend_with(void (*fn)(void*), void* arg) | ||
|  |   { | ||
|  |     if (throw_if_cancelled_) | ||
|  |       if (!!cancellation_state_.cancelled()) | ||
|  |         throw_error(asio::error::operation_aborted, "yield"); | ||
|  |     has_context_switched_ = true; | ||
|  |     on_suspend_fn_ = fn; | ||
|  |     on_suspend_arg_ = arg; | ||
|  |     caller_ = fiber_type(ASIO_MOVE_CAST(fiber_type)(caller_)).resume(); | ||
|  |   } | ||
|  | 
 | ||
|  |   void destroy() | ||
|  |   { | ||
|  |     fiber_type callee = ASIO_MOVE_CAST(fiber_type)(callee_); | ||
|  |     if (terminal_) | ||
|  |       fiber_type(ASIO_MOVE_CAST(fiber_type)(callee)).resume(); | ||
|  |   } | ||
|  | 
 | ||
|  | private: | ||
|  |   template <typename Function> | ||
|  |   class entry_point | ||
|  |   { | ||
|  |   public: | ||
|  |     template <typename F> | ||
|  |     entry_point(ASIO_MOVE_ARG(F) f, | ||
|  |         spawned_fiber_thread** spawned_thread_out) | ||
|  |       : function_(ASIO_MOVE_CAST(F)(f)), | ||
|  |         spawned_thread_out_(spawned_thread_out) | ||
|  |     { | ||
|  |     } | ||
|  | 
 | ||
|  |     fiber_type operator()(ASIO_MOVE_ARG(fiber_type) caller) | ||
|  |     { | ||
|  |       Function function(ASIO_MOVE_CAST(Function)(function_)); | ||
|  |       spawned_fiber_thread spawned_thread( | ||
|  |           ASIO_MOVE_CAST(fiber_type)(caller)); | ||
|  |       *spawned_thread_out_ = &spawned_thread; | ||
|  |       spawned_thread_out_ = 0; | ||
|  |       spawned_thread.suspend(); | ||
|  | #if !defined(ASIO_NO_EXCEPTIONS)
 | ||
|  |       try | ||
|  | #endif // !defined(ASIO_NO_EXCEPTIONS)
 | ||
|  |       { | ||
|  |         function(&spawned_thread); | ||
|  |         spawned_thread.terminal_ = true; | ||
|  |         spawned_thread.suspend(); | ||
|  |       } | ||
|  | #if !defined(ASIO_NO_EXCEPTIONS)
 | ||
|  |       catch (const boost::context::detail::forced_unwind&) | ||
|  |       { | ||
|  |         throw; | ||
|  |       } | ||
|  |       catch (...) | ||
|  |       { | ||
|  |         exception_ptr ex = current_exception(); | ||
|  |         spawned_thread.terminal_ = true; | ||
|  |         spawned_thread.suspend_with(spawned_thread_rethrow, &ex); | ||
|  |       } | ||
|  | #endif // !defined(ASIO_NO_EXCEPTIONS)
 | ||
|  |       return ASIO_MOVE_CAST(fiber_type)(spawned_thread.caller_); | ||
|  |     } | ||
|  | 
 | ||
|  |   private: | ||
|  |     Function function_; | ||
|  |     spawned_fiber_thread** spawned_thread_out_; | ||
|  |   }; | ||
|  | 
 | ||
|  |   fiber_type caller_; | ||
|  |   fiber_type callee_; | ||
|  |   void (*on_suspend_fn_)(void*); | ||
|  |   void* on_suspend_arg_; | ||
|  | }; | ||
|  | 
 | ||
|  | #endif // defined(ASIO_HAS_BOOST_CONTEXT_FIBER)
 | ||
|  | 
 | ||
|  | #if defined(ASIO_HAS_BOOST_CONTEXT_FIBER)
 | ||
|  | typedef spawned_fiber_thread default_spawned_thread_type; | ||
|  | #elif defined(ASIO_HAS_BOOST_COROUTINE)
 | ||
|  | typedef spawned_coroutine_thread default_spawned_thread_type; | ||
|  | #else
 | ||
|  | # error No spawn() implementation available
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | // Helper class to perform the initial resume on the correct executor.
 | ||
|  | class spawned_thread_resumer | ||
|  | { | ||
|  | public: | ||
|  |   explicit spawned_thread_resumer(spawned_thread_base* spawned_thread) | ||
|  |     : spawned_thread_(spawned_thread) | ||
|  |   { | ||
|  | #if !defined(ASIO_HAS_MOVE)
 | ||
|  |     spawned_thread->detach(); | ||
|  |     spawned_thread->attach(&spawned_thread_); | ||
|  | #endif // !defined(ASIO_HAS_MOVE)
 | ||
|  |   } | ||
|  | 
 | ||
|  | #if defined(ASIO_HAS_MOVE)
 | ||
|  | 
 | ||
|  |   spawned_thread_resumer(spawned_thread_resumer&& other) ASIO_NOEXCEPT | ||
|  |     : spawned_thread_(other.spawned_thread_) | ||
|  |   { | ||
|  |     other.spawned_thread_ = 0; | ||
|  |   } | ||
|  | 
 | ||
|  | #else // defined(ASIO_HAS_MOVE)
 | ||
|  | 
 | ||
|  |   spawned_thread_resumer( | ||
|  |       const spawned_thread_resumer& other) ASIO_NOEXCEPT | ||
|  |     : spawned_thread_(other.spawned_thread_) | ||
|  |   { | ||
|  |     spawned_thread_->detach(); | ||
|  |     spawned_thread_->attach(&spawned_thread_); | ||
|  |   } | ||
|  | 
 | ||
|  | #endif // defined(ASIO_HAS_MOVE)
 | ||
|  | 
 | ||
|  |   ~spawned_thread_resumer() | ||
|  |   { | ||
|  |     if (spawned_thread_) | ||
|  |       spawned_thread_->destroy(); | ||
|  |   } | ||
|  | 
 | ||
|  |   void operator()() | ||
|  |   { | ||
|  | #if defined(ASIO_HAS_MOVE)
 | ||
|  |     spawned_thread_->attach(&spawned_thread_); | ||
|  | #endif // defined(ASIO_HAS_MOVE)
 | ||
|  |     spawned_thread_->resume(); | ||
|  |   } | ||
|  | 
 | ||
|  | private: | ||
|  |   spawned_thread_base* spawned_thread_; | ||
|  | }; | ||
|  | 
 | ||
|  | // Helper class to ensure spawned threads are destroyed on the correct executor.
 | ||
|  | class spawned_thread_destroyer | ||
|  | { | ||
|  | public: | ||
|  |   explicit spawned_thread_destroyer(spawned_thread_base* spawned_thread) | ||
|  |     : spawned_thread_(spawned_thread) | ||
|  |   { | ||
|  |     spawned_thread->detach(); | ||
|  | #if !defined(ASIO_HAS_MOVE)
 | ||
|  |     spawned_thread->attach(&spawned_thread_); | ||
|  | #endif // !defined(ASIO_HAS_MOVE)
 | ||
|  |   } | ||
|  | 
 | ||
|  | #if defined(ASIO_HAS_MOVE)
 | ||
|  | 
 | ||
|  |   spawned_thread_destroyer(spawned_thread_destroyer&& other) ASIO_NOEXCEPT | ||
|  |     : spawned_thread_(other.spawned_thread_) | ||
|  |   { | ||
|  |     other.spawned_thread_ = 0; | ||
|  |   } | ||
|  | 
 | ||
|  | #else // defined(ASIO_HAS_MOVE)
 | ||
|  | 
 | ||
|  |   spawned_thread_destroyer( | ||
|  |       const spawned_thread_destroyer& other) ASIO_NOEXCEPT | ||
|  |     : spawned_thread_(other.spawned_thread_) | ||
|  |   { | ||
|  |     spawned_thread_->detach(); | ||
|  |     spawned_thread_->attach(&spawned_thread_); | ||
|  |   } | ||
|  | 
 | ||
|  | #endif // defined(ASIO_HAS_MOVE)
 | ||
|  | 
 | ||
|  |   ~spawned_thread_destroyer() | ||
|  |   { | ||
|  |     if (spawned_thread_) | ||
|  |       spawned_thread_->destroy(); | ||
|  |   } | ||
|  | 
 | ||
|  |   void operator()() | ||
|  |   { | ||
|  |     if (spawned_thread_) | ||
|  |     { | ||
|  |       spawned_thread_->destroy(); | ||
|  |       spawned_thread_ = 0; | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  | private: | ||
|  |   spawned_thread_base* spawned_thread_; | ||
|  | }; | ||
|  | 
 | ||
|  | // Base class for all completion handlers associated with a spawned thread.
 | ||
|  | template <typename Executor> | ||
|  | class spawn_handler_base | ||
|  | { | ||
|  | public: | ||
|  |   typedef Executor executor_type; | ||
|  |   typedef cancellation_slot cancellation_slot_type; | ||
|  | 
 | ||
|  |   spawn_handler_base(const basic_yield_context<Executor>& yield) | ||
|  |     : yield_(yield), | ||
|  |       spawned_thread_(yield.spawned_thread_) | ||
|  |   { | ||
|  |     spawned_thread_->detach(); | ||
|  | #if !defined(ASIO_HAS_MOVE)
 | ||
|  |     spawned_thread_->attach(&spawned_thread_); | ||
|  | #endif // !defined(ASIO_HAS_MOVE)
 | ||
|  |   } | ||
|  | 
 | ||
|  | #if defined(ASIO_HAS_MOVE)
 | ||
|  | 
 | ||
|  |   spawn_handler_base(spawn_handler_base&& other) ASIO_NOEXCEPT | ||
|  |     : yield_(other.yield_), | ||
|  |       spawned_thread_(other.spawned_thread_) | ||
|  | 
 | ||
|  |   { | ||
|  |     other.spawned_thread_ = 0; | ||
|  |   } | ||
|  | 
 | ||
|  | #else // defined(ASIO_HAS_MOVE)
 | ||
|  | 
 | ||
|  |   spawn_handler_base(const spawn_handler_base& other) ASIO_NOEXCEPT | ||
|  |     : yield_(other.yield_), | ||
|  |       spawned_thread_(other.spawned_thread_) | ||
|  |   { | ||
|  |     spawned_thread_->detach(); | ||
|  |     spawned_thread_->attach(&spawned_thread_); | ||
|  |   } | ||
|  | 
 | ||
|  | #endif // defined(ASIO_HAS_MOVE)
 | ||
|  | 
 | ||
|  |   ~spawn_handler_base() | ||
|  |   { | ||
|  |     if (spawned_thread_) | ||
|  |       (post)(yield_.executor_, spawned_thread_destroyer(spawned_thread_)); | ||
|  |   } | ||
|  | 
 | ||
|  |   executor_type get_executor() const ASIO_NOEXCEPT | ||
|  |   { | ||
|  |     return yield_.executor_; | ||
|  |   } | ||
|  | 
 | ||
|  |   cancellation_slot_type get_cancellation_slot() const ASIO_NOEXCEPT | ||
|  |   { | ||
|  |     return spawned_thread_->get_cancellation_slot(); | ||
|  |   } | ||
|  | 
 | ||
|  |   void resume() | ||
|  |   { | ||
|  |     spawned_thread_resumer resumer(spawned_thread_); | ||
|  |     spawned_thread_ = 0; | ||
|  |     resumer(); | ||
|  |   } | ||
|  | 
 | ||
|  | protected: | ||
|  |   const basic_yield_context<Executor>& yield_; | ||
|  |   spawned_thread_base* spawned_thread_; | ||
|  | }; | ||
|  | 
 | ||
|  | // Completion handlers for when basic_yield_context is used as a token.
 | ||
|  | template <typename Executor, typename Signature> | ||
|  | class spawn_handler; | ||
|  | 
 | ||
|  | template <typename Executor, typename R> | ||
|  | class spawn_handler<Executor, R()> | ||
|  |   : public spawn_handler_base<Executor> | ||
|  | { | ||
|  | public: | ||
|  |   typedef void return_type; | ||
|  | 
 | ||
|  |   struct result_type {}; | ||
|  | 
 | ||
|  |   spawn_handler(const basic_yield_context<Executor>& yield, result_type&) | ||
|  |     : spawn_handler_base<Executor>(yield) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   void operator()() | ||
|  |   { | ||
|  |     this->resume(); | ||
|  |   } | ||
|  | 
 | ||
|  |   static return_type on_resume(result_type&) | ||
|  |   { | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename Executor, typename R> | ||
|  | class spawn_handler<Executor, R(asio::error_code)> | ||
|  |   : public spawn_handler_base<Executor> | ||
|  | { | ||
|  | public: | ||
|  |   typedef void return_type; | ||
|  |   typedef asio::error_code* result_type; | ||
|  | 
 | ||
|  |   spawn_handler(const basic_yield_context<Executor>& yield, result_type& result) | ||
|  |     : spawn_handler_base<Executor>(yield), | ||
|  |       result_(result) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   void operator()(asio::error_code ec) | ||
|  |   { | ||
|  |     if (this->yield_.ec_) | ||
|  |     { | ||
|  |       *this->yield_.ec_ = ec; | ||
|  |       result_ = 0; | ||
|  |     } | ||
|  |     else | ||
|  |       result_ = &ec; | ||
|  |     this->resume(); | ||
|  |   } | ||
|  | 
 | ||
|  |   static return_type on_resume(result_type& result) | ||
|  |   { | ||
|  |     if (result) | ||
|  |       throw_error(*result); | ||
|  |   } | ||
|  | 
 | ||
|  | private: | ||
|  |   result_type& result_; | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename Executor, typename R> | ||
|  | class spawn_handler<Executor, R(exception_ptr)> | ||
|  |   : public spawn_handler_base<Executor> | ||
|  | { | ||
|  | public: | ||
|  |   typedef void return_type; | ||
|  |   typedef exception_ptr* result_type; | ||
|  | 
 | ||
|  |   spawn_handler(const basic_yield_context<Executor>& yield, result_type& result) | ||
|  |     : spawn_handler_base<Executor>(yield), | ||
|  |       result_(result) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   void operator()(exception_ptr ex) | ||
|  |   { | ||
|  |     result_ = &ex; | ||
|  |     this->resume(); | ||
|  |   } | ||
|  | 
 | ||
|  |   static return_type on_resume(result_type& result) | ||
|  |   { | ||
|  |     if (result) | ||
|  |       rethrow_exception(*result); | ||
|  |   } | ||
|  | 
 | ||
|  | private: | ||
|  |   result_type& result_; | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename Executor, typename R, typename T> | ||
|  | class spawn_handler<Executor, R(T)> | ||
|  |   : public spawn_handler_base<Executor> | ||
|  | { | ||
|  | public: | ||
|  |   typedef T return_type; | ||
|  |   typedef return_type* result_type; | ||
|  | 
 | ||
|  |   spawn_handler(const basic_yield_context<Executor>& yield, result_type& result) | ||
|  |     : spawn_handler_base<Executor>(yield), | ||
|  |       result_(result) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   void operator()(T value) | ||
|  |   { | ||
|  |     result_ = &value; | ||
|  |     this->resume(); | ||
|  |   } | ||
|  | 
 | ||
|  |   static return_type on_resume(result_type& result) | ||
|  |   { | ||
|  |     return ASIO_MOVE_CAST(return_type)(*result); | ||
|  |   } | ||
|  | 
 | ||
|  | private: | ||
|  |   result_type& result_; | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename Executor, typename R, typename T> | ||
|  | class spawn_handler<Executor, R(asio::error_code, T)> | ||
|  |   : public spawn_handler_base<Executor> | ||
|  | { | ||
|  | public: | ||
|  |   typedef T return_type; | ||
|  | 
 | ||
|  |   struct result_type | ||
|  |   { | ||
|  |     asio::error_code* ec_; | ||
|  |     return_type* value_; | ||
|  |   }; | ||
|  | 
 | ||
|  |   spawn_handler(const basic_yield_context<Executor>& yield, result_type& result) | ||
|  |     : spawn_handler_base<Executor>(yield), | ||
|  |       result_(result) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   void operator()(asio::error_code ec, T value) | ||
|  |   { | ||
|  |     if (this->yield_.ec_) | ||
|  |     { | ||
|  |       *this->yield_.ec_ = ec; | ||
|  |       result_.ec_ = 0; | ||
|  |     } | ||
|  |     else | ||
|  |       result_.ec_ = &ec; | ||
|  |     result_.value_ = &value; | ||
|  |     this->resume(); | ||
|  |   } | ||
|  | 
 | ||
|  |   static return_type on_resume(result_type& result) | ||
|  |   { | ||
|  |     if (result.ec_) | ||
|  |       throw_error(*result.ec_); | ||
|  |     return ASIO_MOVE_CAST(return_type)(*result.value_); | ||
|  |   } | ||
|  | 
 | ||
|  | private: | ||
|  |   result_type& result_; | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename Executor, typename R, typename T> | ||
|  | class spawn_handler<Executor, R(exception_ptr, T)> | ||
|  |   : public spawn_handler_base<Executor> | ||
|  | { | ||
|  | public: | ||
|  |   typedef T return_type; | ||
|  | 
 | ||
|  |   struct result_type | ||
|  |   { | ||
|  |     exception_ptr ex_; | ||
|  |     return_type* value_; | ||
|  |   }; | ||
|  | 
 | ||
|  |   spawn_handler(const basic_yield_context<Executor>& yield, result_type& result) | ||
|  |     : spawn_handler_base<Executor>(yield), | ||
|  |       result_(result) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   void operator()(exception_ptr ex, T value) | ||
|  |   { | ||
|  |     result_.ex_ = &ex; | ||
|  |     result_.value_ = &value; | ||
|  |     this->resume(); | ||
|  |   } | ||
|  | 
 | ||
|  |   static return_type on_resume(result_type& result) | ||
|  |   { | ||
|  |     if (result.ex_) | ||
|  |       rethrow_exception(*result.ex_); | ||
|  |     return ASIO_MOVE_CAST(return_type)(*result.value_); | ||
|  |   } | ||
|  | 
 | ||
|  | private: | ||
|  |   result_type& result_; | ||
|  | }; | ||
|  | 
 | ||
|  | #if defined(ASIO_HAS_VARIADIC_TEMPLATES) \
 | ||
|  |   && defined(ASIO_HAS_STD_TUPLE) | ||
|  | 
 | ||
|  | template <typename Executor, typename R, typename... Ts> | ||
|  | class spawn_handler<Executor, R(Ts...)> | ||
|  |   : public spawn_handler_base<Executor> | ||
|  | { | ||
|  | public: | ||
|  |   typedef std::tuple<Ts...> return_type; | ||
|  | 
 | ||
|  |   typedef return_type* result_type; | ||
|  | 
 | ||
|  |   spawn_handler(const basic_yield_context<Executor>& yield, result_type& result) | ||
|  |     : spawn_handler_base<Executor>(yield), | ||
|  |       result_(result) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   template <typename... Args> | ||
|  |   void operator()(ASIO_MOVE_ARG(Args)... args) | ||
|  |   { | ||
|  |     return_type value(ASIO_MOVE_CAST(Args)(args)...); | ||
|  |     result_ = &value; | ||
|  |     this->resume(); | ||
|  |   } | ||
|  | 
 | ||
|  |   static return_type on_resume(result_type& result) | ||
|  |   { | ||
|  |     return ASIO_MOVE_CAST(return_type)(*result); | ||
|  |   } | ||
|  | 
 | ||
|  | private: | ||
|  |   result_type& result_; | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename Executor, typename R, typename... Ts> | ||
|  | class spawn_handler<Executor, R(asio::error_code, Ts...)> | ||
|  |   : public spawn_handler_base<Executor> | ||
|  | { | ||
|  | public: | ||
|  |   typedef std::tuple<Ts...> return_type; | ||
|  | 
 | ||
|  |   struct result_type | ||
|  |   { | ||
|  |     asio::error_code* ec_; | ||
|  |     return_type* value_; | ||
|  |   }; | ||
|  | 
 | ||
|  |   spawn_handler(const basic_yield_context<Executor>& yield, result_type& result) | ||
|  |     : spawn_handler_base<Executor>(yield), | ||
|  |       result_(result) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   template <typename... Args> | ||
|  |   void operator()(asio::error_code ec, | ||
|  |       ASIO_MOVE_ARG(Args)... args) | ||
|  |   { | ||
|  |     return_type value(ASIO_MOVE_CAST(Args)(args)...); | ||
|  |     if (this->yield_.ec_) | ||
|  |     { | ||
|  |       *this->yield_.ec_ = ec; | ||
|  |       result_.ec_ = 0; | ||
|  |     } | ||
|  |     else | ||
|  |       result_.ec_ = &ec; | ||
|  |     result_.value_ = &value; | ||
|  |     this->resume(); | ||
|  |   } | ||
|  | 
 | ||
|  |   static return_type on_resume(result_type& result) | ||
|  |   { | ||
|  |     if (result.ec_) | ||
|  |       throw_error(*result.ec_); | ||
|  |     return ASIO_MOVE_CAST(return_type)(*result.value_); | ||
|  |   } | ||
|  | 
 | ||
|  | private: | ||
|  |   result_type& result_; | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename Executor, typename R, typename... Ts> | ||
|  | class spawn_handler<Executor, R(exception_ptr, Ts...)> | ||
|  |   : public spawn_handler_base<Executor> | ||
|  | { | ||
|  | public: | ||
|  |   typedef std::tuple<Ts...> return_type; | ||
|  | 
 | ||
|  |   struct result_type | ||
|  |   { | ||
|  |     exception_ptr ex_; | ||
|  |     return_type* value_; | ||
|  |   }; | ||
|  | 
 | ||
|  |   spawn_handler(const basic_yield_context<Executor>& yield, result_type& result) | ||
|  |     : spawn_handler_base<Executor>(yield), | ||
|  |       result_(result) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   template <typename... Args> | ||
|  |   void operator()(exception_ptr ex, ASIO_MOVE_ARG(Args)... args) | ||
|  |   { | ||
|  |     return_type value(ASIO_MOVE_CAST(Args)(args)...); | ||
|  |     result_.ex_ = &ex; | ||
|  |     result_.value_ = &value; | ||
|  |     this->resume(); | ||
|  |   } | ||
|  | 
 | ||
|  |   static return_type on_resume(result_type& result) | ||
|  |   { | ||
|  |     if (result.ex_) | ||
|  |       rethrow_exception(*result.ex_); | ||
|  |     return ASIO_MOVE_CAST(return_type)(*result.value_); | ||
|  |   } | ||
|  | 
 | ||
|  | private: | ||
|  |   result_type& result_; | ||
|  | }; | ||
|  | 
 | ||
|  | #endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
 | ||
|  |        //   && defined(ASIO_HAS_STD_TUPLE)
 | ||
|  | 
 | ||
|  | template <typename Executor, typename Signature> | ||
|  | inline bool asio_handler_is_continuation(spawn_handler<Executor, Signature>*) | ||
|  | { | ||
|  |   return true; | ||
|  | } | ||
|  | 
 | ||
|  | } // namespace detail
 | ||
|  | 
 | ||
|  | template <typename Executor, typename Signature> | ||
|  | class async_result<basic_yield_context<Executor>, Signature> | ||
|  | { | ||
|  | public: | ||
|  |   typedef typename detail::spawn_handler<Executor, Signature> handler_type; | ||
|  |   typedef typename handler_type::return_type return_type; | ||
|  | 
 | ||
|  | #if defined(ASIO_HAS_VARIADIC_TEMPLATES)
 | ||
|  | # if defined(ASIO_HAS_VARIADIC_LAMBDA_CAPTURES)
 | ||
|  | 
 | ||
|  |   template <typename Initiation, typename... InitArgs> | ||
|  |   static return_type initiate(ASIO_MOVE_ARG(Initiation) init, | ||
|  |       const basic_yield_context<Executor>& yield, | ||
|  |       ASIO_MOVE_ARG(InitArgs)... init_args) | ||
|  |   { | ||
|  |     typename handler_type::result_type result | ||
|  |       = typename handler_type::result_type(); | ||
|  | 
 | ||
|  |     yield.spawned_thread_->suspend_with( | ||
|  |         [&]() | ||
|  |         { | ||
|  |           ASIO_MOVE_CAST(Initiation)(init)( | ||
|  |               handler_type(yield, result), | ||
|  |               ASIO_MOVE_CAST(InitArgs)(init_args)...); | ||
|  |         }); | ||
|  | 
 | ||
|  |     return handler_type::on_resume(result); | ||
|  |   } | ||
|  | 
 | ||
|  | # else // defined(ASIO_HAS_VARIADIC_LAMBDA_CAPTURES)
 | ||
|  | 
 | ||
|  |   template <typename Initiation, typename... InitArgs> | ||
|  |   struct suspend_with_helper | ||
|  |   { | ||
|  |     typename handler_type::result_type& result_; | ||
|  |     ASIO_MOVE_ARG(Initiation) init_; | ||
|  |     const basic_yield_context<Executor>& yield_; | ||
|  |     std::tuple<ASIO_MOVE_ARG(InitArgs)...> init_args_; | ||
|  | 
 | ||
|  |     template <std::size_t... I> | ||
|  |     void do_invoke(detail::index_sequence<I...>) | ||
|  |     { | ||
|  |       ASIO_MOVE_CAST(Initiation)(init_)( | ||
|  |           handler_type(yield_, result_), | ||
|  |           ASIO_MOVE_CAST(InitArgs)(std::get<I>(init_args_))...); | ||
|  |     } | ||
|  | 
 | ||
|  |     void operator()() | ||
|  |     { | ||
|  |       this->do_invoke(detail::make_index_sequence<sizeof...(InitArgs)>()); | ||
|  |     } | ||
|  |   }; | ||
|  | 
 | ||
|  |   template <typename Initiation, typename... InitArgs> | ||
|  |   static return_type initiate(ASIO_MOVE_ARG(Initiation) init, | ||
|  |       const basic_yield_context<Executor>& yield, | ||
|  |       ASIO_MOVE_ARG(InitArgs)... init_args) | ||
|  |   { | ||
|  |     typename handler_type::result_type result | ||
|  |       = typename handler_type::result_type(); | ||
|  | 
 | ||
|  |     yield.spawned_thread_->suspend_with( | ||
|  |       suspend_with_helper<Initiation, InitArgs...>{ | ||
|  |           result, ASIO_MOVE_CAST(Initiation)(init), yield, | ||
|  |           std::tuple<ASIO_MOVE_ARG(InitArgs)...>( | ||
|  |             ASIO_MOVE_CAST(InitArgs)(init_args)...)}); | ||
|  | 
 | ||
|  |     return handler_type::on_resume(result); | ||
|  |   } | ||
|  | 
 | ||
|  | # endif // defined(ASIO_HAS_VARIADIC_LAMBDA_CAPTURES)
 | ||
|  | #else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
 | ||
|  | 
 | ||
|  |   template <typename Initiation> | ||
|  |   static return_type initiate(Initiation init, | ||
|  |       const basic_yield_context<Executor>& yield) | ||
|  |   { | ||
|  |     typename handler_type::result_type result | ||
|  |       = typename handler_type::result_type(); | ||
|  | 
 | ||
|  |     struct on_suspend | ||
|  |     { | ||
|  |       Initiation& init_; | ||
|  |       const basic_yield_context<Executor>& yield_; | ||
|  |       typename handler_type::result_type& result_; | ||
|  | 
 | ||
|  |       void do_call() | ||
|  |       { | ||
|  |         ASIO_MOVE_CAST(Initiation)(init_)( | ||
|  |             handler_type(yield_, result_)); | ||
|  |       } | ||
|  | 
 | ||
|  |       static void call(void* arg) | ||
|  |       { | ||
|  |         static_cast<on_suspend*>(arg)->do_call(); | ||
|  |       } | ||
|  |     } o = { init, yield, result }; | ||
|  | 
 | ||
|  |     yield.spawned_thread_->suspend_with(&on_suspend::call, &o); | ||
|  | 
 | ||
|  |     return handler_type::on_resume(result); | ||
|  |   } | ||
|  | 
 | ||
|  | #define ASIO_PRIVATE_ON_SUSPEND_MEMBERS(n) \
 | ||
|  |   ASIO_PRIVATE_ON_SUSPEND_MEMBERS_##n | ||
|  | #define ASIO_PRIVATE_ON_SUSPEND_MEMBERS_1 \
 | ||
|  |   T1& x1; | ||
|  | #define ASIO_PRIVATE_ON_SUSPEND_MEMBERS_2 \
 | ||
|  |   T1& x1; T2& x2; | ||
|  | #define ASIO_PRIVATE_ON_SUSPEND_MEMBERS_3 \
 | ||
|  |   T1& x1; T2& x2; T3& x3; | ||
|  | #define ASIO_PRIVATE_ON_SUSPEND_MEMBERS_4 \
 | ||
|  |   T1& x1; T2& x2; T3& x3; T4& x4; | ||
|  | #define ASIO_PRIVATE_ON_SUSPEND_MEMBERS_5 \
 | ||
|  |   T1& x1; T2& x2; T3& x3; T4& x4; T5& x5; | ||
|  | #define ASIO_PRIVATE_ON_SUSPEND_MEMBERS_6 \
 | ||
|  |   T1& x1; T2& x2; T3& x3; T4& x4; T5& x5; T6& x6; | ||
|  | #define ASIO_PRIVATE_ON_SUSPEND_MEMBERS_7 \
 | ||
|  |   T1& x1; T2& x2; T3& x3; T4& x4; T5& x5; T6& x6; T7& x7; | ||
|  | #define ASIO_PRIVATE_ON_SUSPEND_MEMBERS_8 \
 | ||
|  |   T1& x1; T2& x2; T3& x3; T4& x4; T5& x5; T6& x6; T7& x7; T8& x8; | ||
|  | 
 | ||
|  | #define ASIO_PRIVATE_INITIATE_DEF(n) \
 | ||
|  |   template <typename Initiation, ASIO_VARIADIC_TPARAMS(n)> \ | ||
|  |   static return_type initiate(Initiation init, \ | ||
|  |       const basic_yield_context<Executor>& yield, \ | ||
|  |       ASIO_VARIADIC_BYVAL_PARAMS(n)) \ | ||
|  |   { \ | ||
|  |     typename handler_type::result_type result \ | ||
|  |       = typename handler_type::result_type(); \ | ||
|  |   \ | ||
|  |     struct on_suspend \ | ||
|  |     { \ | ||
|  |       Initiation& init; \ | ||
|  |       const basic_yield_context<Executor>& yield; \ | ||
|  |       typename handler_type::result_type& result; \ | ||
|  |       ASIO_PRIVATE_ON_SUSPEND_MEMBERS(n) \ | ||
|  |   \ | ||
|  |       void do_call() \ | ||
|  |       { \ | ||
|  |         ASIO_MOVE_CAST(Initiation)(init)( \ | ||
|  |             handler_type(yield, result), \ | ||
|  |             ASIO_VARIADIC_MOVE_ARGS(n)); \ | ||
|  |       } \ | ||
|  |   \ | ||
|  |       static void call(void* arg) \ | ||
|  |       { \ | ||
|  |         static_cast<on_suspend*>(arg)->do_call(); \ | ||
|  |       } \ | ||
|  |     } o = { init, yield, result, ASIO_VARIADIC_BYVAL_ARGS(n) }; \ | ||
|  |   \ | ||
|  |     yield.spawned_thread_->suspend_with(&on_suspend::call, &o); \ | ||
|  |   \ | ||
|  |     return handler_type::on_resume(result); \ | ||
|  |   } \ | ||
|  |   /**/ | ||
|  |   ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_INITIATE_DEF) | ||
|  | #undef ASIO_PRIVATE_INITIATE_DEF
 | ||
|  | #undef ASIO_PRIVATE_ON_SUSPEND_MEMBERS
 | ||
|  | #undef ASIO_PRIVATE_ON_SUSPEND_MEMBERS_1
 | ||
|  | #undef ASIO_PRIVATE_ON_SUSPEND_MEMBERS_2
 | ||
|  | #undef ASIO_PRIVATE_ON_SUSPEND_MEMBERS_3
 | ||
|  | #undef ASIO_PRIVATE_ON_SUSPEND_MEMBERS_4
 | ||
|  | #undef ASIO_PRIVATE_ON_SUSPEND_MEMBERS_5
 | ||
|  | #undef ASIO_PRIVATE_ON_SUSPEND_MEMBERS_6
 | ||
|  | #undef ASIO_PRIVATE_ON_SUSPEND_MEMBERS_7
 | ||
|  | #undef ASIO_PRIVATE_ON_SUSPEND_MEMBERS_8
 | ||
|  | 
 | ||
|  | #endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
 | ||
|  | }; | ||
|  | 
 | ||
|  | namespace detail { | ||
|  | 
 | ||
|  | template <typename Executor, typename Function, typename Handler> | ||
|  | class spawn_entry_point | ||
|  | { | ||
|  | public: | ||
|  |   template <typename F, typename H> | ||
|  |   spawn_entry_point(const Executor& ex, | ||
|  |       ASIO_MOVE_ARG(F) f, ASIO_MOVE_ARG(H) h) | ||
|  |     : executor_(ex), | ||
|  |       function_(ASIO_MOVE_CAST(F)(f)), | ||
|  |       handler_(ASIO_MOVE_CAST(H)(h)), | ||
|  |       work_(handler_, executor_) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   void operator()(spawned_thread_base* spawned_thread) | ||
|  |   { | ||
|  |     const basic_yield_context<Executor> yield(spawned_thread, executor_); | ||
|  |     this->call(yield, | ||
|  |         void_type<typename result_of<Function( | ||
|  |           basic_yield_context<Executor>)>::type>()); | ||
|  |   } | ||
|  | 
 | ||
|  | private: | ||
|  |   void call(const basic_yield_context<Executor>& yield, void_type<void>) | ||
|  |   { | ||
|  | #if !defined(ASIO_NO_EXCEPTIONS)
 | ||
|  |     try | ||
|  | #endif // !defined(ASIO_NO_EXCEPTIONS)
 | ||
|  |     { | ||
|  |       function_(yield); | ||
|  |       if (!yield.spawned_thread_->has_context_switched()) | ||
|  |         (post)(yield); | ||
|  |       detail::binder1<Handler, exception_ptr> | ||
|  |         handler(handler_, exception_ptr()); | ||
|  |       work_.complete(handler, handler.handler_); | ||
|  |     } | ||
|  | #if !defined(ASIO_NO_EXCEPTIONS)
 | ||
|  | # if defined(ASIO_HAS_BOOST_CONTEXT_FIBER)
 | ||
|  |     catch (const boost::context::detail::forced_unwind&) | ||
|  |     { | ||
|  |       throw; | ||
|  |     } | ||
|  | # endif // defined(ASIO_HAS_BOOST_CONTEXT_FIBER)
 | ||
|  | # if defined(ASIO_HAS_BOOST_COROUTINE)
 | ||
|  |     catch (const boost::coroutines::detail::forced_unwind&) | ||
|  |     { | ||
|  |       throw; | ||
|  |     } | ||
|  | # endif // defined(ASIO_HAS_BOOST_COROUTINE)
 | ||
|  |     catch (...) | ||
|  |     { | ||
|  |       exception_ptr ex = current_exception(); | ||
|  |       if (!yield.spawned_thread_->has_context_switched()) | ||
|  |         (post)(yield); | ||
|  |       detail::binder1<Handler, exception_ptr> handler(handler_, ex); | ||
|  |       work_.complete(handler, handler.handler_); | ||
|  |     } | ||
|  | #endif // !defined(ASIO_NO_EXCEPTIONS)
 | ||
|  |   } | ||
|  | 
 | ||
|  |   template <typename T> | ||
|  |   void call(const basic_yield_context<Executor>& yield, void_type<T>) | ||
|  |   { | ||
|  | #if !defined(ASIO_NO_EXCEPTIONS)
 | ||
|  |     try | ||
|  | #endif // !defined(ASIO_NO_EXCEPTIONS)
 | ||
|  |     { | ||
|  |       T result(function_(yield)); | ||
|  |       if (!yield.spawned_thread_->has_context_switched()) | ||
|  |         (post)(yield); | ||
|  |       detail::binder2<Handler, exception_ptr, T> | ||
|  |         handler(handler_, exception_ptr(), ASIO_MOVE_CAST(T)(result)); | ||
|  |       work_.complete(handler, handler.handler_); | ||
|  |     } | ||
|  | #if !defined(ASIO_NO_EXCEPTIONS)
 | ||
|  | # if defined(ASIO_HAS_BOOST_CONTEXT_FIBER)
 | ||
|  |     catch (const boost::context::detail::forced_unwind&) | ||
|  |     { | ||
|  |       throw; | ||
|  |     } | ||
|  | # endif // defined(ASIO_HAS_BOOST_CONTEXT_FIBER)
 | ||
|  | # if defined(ASIO_HAS_BOOST_COROUTINE)
 | ||
|  |     catch (const boost::coroutines::detail::forced_unwind&) | ||
|  |     { | ||
|  |       throw; | ||
|  |     } | ||
|  | # endif // defined(ASIO_HAS_BOOST_COROUTINE)
 | ||
|  |     catch (...) | ||
|  |     { | ||
|  |       exception_ptr ex = current_exception(); | ||
|  |       if (!yield.spawned_thread_->has_context_switched()) | ||
|  |         (post)(yield); | ||
|  |       detail::binder2<Handler, exception_ptr, T> handler(handler_, ex, T()); | ||
|  |       work_.complete(handler, handler.handler_); | ||
|  |     } | ||
|  | #endif // !defined(ASIO_NO_EXCEPTIONS)
 | ||
|  |   } | ||
|  | 
 | ||
|  |   Executor executor_; | ||
|  |   Function function_; | ||
|  |   Handler handler_; | ||
|  |   handler_work<Handler, Executor> work_; | ||
|  | }; | ||
|  | 
 | ||
|  | struct spawn_cancellation_signal_emitter | ||
|  | { | ||
|  |   cancellation_signal* signal_; | ||
|  |   cancellation_type_t type_; | ||
|  | 
 | ||
|  |   void operator()() | ||
|  |   { | ||
|  |     signal_->emit(type_); | ||
|  |   } | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename Handler, typename Executor, typename = void> | ||
|  | class spawn_cancellation_handler | ||
|  | { | ||
|  | public: | ||
|  |   spawn_cancellation_handler(const Handler&, const Executor& ex) | ||
|  |     : ex_(ex) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   cancellation_slot slot() | ||
|  |   { | ||
|  |     return signal_.slot(); | ||
|  |   } | ||
|  | 
 | ||
|  |   void operator()(cancellation_type_t type) | ||
|  |   { | ||
|  |     spawn_cancellation_signal_emitter emitter = { &signal_, type }; | ||
|  |     (dispatch)(ex_, emitter); | ||
|  |   } | ||
|  | 
 | ||
|  | private: | ||
|  |   cancellation_signal signal_; | ||
|  |   Executor ex_; | ||
|  | }; | ||
|  | 
 | ||
|  | 
 | ||
|  | template <typename Handler, typename Executor> | ||
|  | class spawn_cancellation_handler<Handler, Executor, | ||
|  |     typename enable_if< | ||
|  |       is_same< | ||
|  |         typename associated_executor<Handler, | ||
|  |           Executor>::asio_associated_executor_is_unspecialised, | ||
|  |         void | ||
|  |       >::value | ||
|  |     >::type> | ||
|  | { | ||
|  | public: | ||
|  |   spawn_cancellation_handler(const Handler&, const Executor&) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   cancellation_slot slot() | ||
|  |   { | ||
|  |     return signal_.slot(); | ||
|  |   } | ||
|  | 
 | ||
|  |   void operator()(cancellation_type_t type) | ||
|  |   { | ||
|  |     signal_.emit(type); | ||
|  |   } | ||
|  | 
 | ||
|  | private: | ||
|  |   cancellation_signal signal_; | ||
|  | }; | ||
|  | 
 | ||
|  | template <typename Executor> | ||
|  | class initiate_spawn | ||
|  | { | ||
|  | public: | ||
|  |   typedef Executor executor_type; | ||
|  | 
 | ||
|  |   explicit initiate_spawn(const executor_type& ex) | ||
|  |     : executor_(ex) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   executor_type get_executor() const ASIO_NOEXCEPT | ||
|  |   { | ||
|  |     return executor_; | ||
|  |   } | ||
|  | 
 | ||
|  |   template <typename Handler, typename F> | ||
|  |   void operator()(ASIO_MOVE_ARG(Handler) handler, | ||
|  |       ASIO_MOVE_ARG(F) f) const | ||
|  |   { | ||
|  |     typedef typename decay<Handler>::type handler_type; | ||
|  |     typedef typename decay<F>::type function_type; | ||
|  |     typedef spawn_cancellation_handler< | ||
|  |       handler_type, Executor> cancel_handler_type; | ||
|  | 
 | ||
|  |     typename associated_cancellation_slot<handler_type>::type slot | ||
|  |       = asio::get_associated_cancellation_slot(handler); | ||
|  | 
 | ||
|  |     cancel_handler_type* cancel_handler = slot.is_connected() | ||
|  |       ? &slot.template emplace<cancel_handler_type>(handler, executor_) | ||
|  |       : 0; | ||
|  | 
 | ||
|  |     cancellation_slot proxy_slot( | ||
|  |         cancel_handler | ||
|  |           ? cancel_handler->slot() | ||
|  |           : cancellation_slot()); | ||
|  | 
 | ||
|  |     cancellation_state cancel_state(proxy_slot); | ||
|  | 
 | ||
|  |     (dispatch)(executor_, | ||
|  |         spawned_thread_resumer( | ||
|  |           default_spawned_thread_type::spawn( | ||
|  |             spawn_entry_point<Executor, function_type, handler_type>( | ||
|  |               executor_, ASIO_MOVE_CAST(F)(f), | ||
|  |               ASIO_MOVE_CAST(Handler)(handler)), | ||
|  |             proxy_slot, cancel_state))); | ||
|  |   } | ||
|  | 
 | ||
|  | #if defined(ASIO_HAS_BOOST_CONTEXT_FIBER)
 | ||
|  | 
 | ||
|  |   template <typename Handler, typename StackAllocator, typename F> | ||
|  |   void operator()(ASIO_MOVE_ARG(Handler) handler, allocator_arg_t, | ||
|  |       ASIO_MOVE_ARG(StackAllocator) stack_allocator, | ||
|  |       ASIO_MOVE_ARG(F) f) const | ||
|  |   { | ||
|  |     typedef typename decay<Handler>::type handler_type; | ||
|  |     typedef typename decay<F>::type function_type; | ||
|  |     typedef spawn_cancellation_handler< | ||
|  |       handler_type, Executor> cancel_handler_type; | ||
|  | 
 | ||
|  |     typename associated_cancellation_slot<handler_type>::type slot | ||
|  |       = asio::get_associated_cancellation_slot(handler); | ||
|  | 
 | ||
|  |     cancel_handler_type* cancel_handler = slot.is_connected() | ||
|  |       ? &slot.template emplace<cancel_handler_type>(handler, executor_) | ||
|  |       : 0; | ||
|  | 
 | ||
|  |     cancellation_slot proxy_slot( | ||
|  |         cancel_handler | ||
|  |           ? cancel_handler->slot() | ||
|  |           : cancellation_slot()); | ||
|  | 
 | ||
|  |     cancellation_state cancel_state(proxy_slot); | ||
|  | 
 | ||
|  |     (dispatch)(executor_, | ||
|  |         spawned_thread_resumer( | ||
|  |           spawned_fiber_thread::spawn(allocator_arg_t(), | ||
|  |             ASIO_MOVE_CAST(StackAllocator)(stack_allocator), | ||
|  |             spawn_entry_point<Executor, function_type, handler_type>( | ||
|  |               executor_, ASIO_MOVE_CAST(F)(f), | ||
|  |               ASIO_MOVE_CAST(Handler)(handler)), | ||
|  |             proxy_slot, cancel_state))); | ||
|  |   } | ||
|  | 
 | ||
|  | #endif // defined(ASIO_HAS_BOOST_CONTEXT_FIBER)
 | ||
|  | 
 | ||
|  | private: | ||
|  |   executor_type executor_; | ||
|  | }; | ||
|  | 
 | ||
|  | } // namespace detail
 | ||
|  | 
 | ||
|  | template <typename Executor, typename F, | ||
|  |     ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature< | ||
|  |       typename result_of<F(basic_yield_context<Executor>)>::type>::type) | ||
|  |         CompletionToken> | ||
|  | inline ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX(CompletionToken, | ||
|  |     typename detail::spawn_signature< | ||
|  |       typename result_of<F(basic_yield_context<Executor>)>::type>::type) | ||
|  | spawn(const Executor& ex, ASIO_MOVE_ARG(F) function, | ||
|  |     ASIO_MOVE_ARG(CompletionToken) token, | ||
|  | #if defined(ASIO_HAS_BOOST_COROUTINE)
 | ||
|  |     typename constraint< | ||
|  |       !is_same< | ||
|  |         typename decay<CompletionToken>::type, | ||
|  |         boost::coroutines::attributes | ||
|  |       >::value | ||
|  |     >::type, | ||
|  | #endif // defined(ASIO_HAS_BOOST_COROUTINE)
 | ||
|  |     typename constraint< | ||
|  |       is_executor<Executor>::value || execution::is_executor<Executor>::value | ||
|  |     >::type) | ||
|  |   ASIO_INITFN_AUTO_RESULT_TYPE_SUFFIX(( | ||
|  |     async_initiate<CompletionToken, | ||
|  |       typename detail::spawn_signature< | ||
|  |         typename result_of<F(basic_yield_context<Executor>)>::type>::type>( | ||
|  |           declval<detail::initiate_spawn<Executor> >(), | ||
|  |           token, ASIO_MOVE_CAST(F)(function)))) | ||
|  | { | ||
|  |   return async_initiate<CompletionToken, | ||
|  |     typename detail::spawn_signature< | ||
|  |       typename result_of<F(basic_yield_context<Executor>)>::type>::type>( | ||
|  |         detail::initiate_spawn<Executor>(ex), | ||
|  |         token, ASIO_MOVE_CAST(F)(function)); | ||
|  | } | ||
|  | 
 | ||
|  | template <typename ExecutionContext, typename F, | ||
|  |     ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature< | ||
|  |       typename result_of<F(basic_yield_context< | ||
|  |         typename ExecutionContext::executor_type>)>::type>::type) | ||
|  |           CompletionToken> | ||
|  | inline ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX(CompletionToken, | ||
|  |     typename detail::spawn_signature< | ||
|  |       typename result_of<F(basic_yield_context< | ||
|  |         typename ExecutionContext::executor_type>)>::type>::type) | ||
|  | spawn(ExecutionContext& ctx, ASIO_MOVE_ARG(F) function, | ||
|  |     ASIO_MOVE_ARG(CompletionToken) token, | ||
|  | #if defined(ASIO_HAS_BOOST_COROUTINE)
 | ||
|  |     typename constraint< | ||
|  |       !is_same< | ||
|  |         typename decay<CompletionToken>::type, | ||
|  |         boost::coroutines::attributes | ||
|  |       >::value | ||
|  |     >::type, | ||
|  | #endif // defined(ASIO_HAS_BOOST_COROUTINE)
 | ||
|  |     typename constraint< | ||
|  |       is_convertible<ExecutionContext&, execution_context&>::value | ||
|  |     >::type) | ||
|  |   ASIO_INITFN_AUTO_RESULT_TYPE_SUFFIX(( | ||
|  |     async_initiate<CompletionToken, | ||
|  |       typename detail::spawn_signature< | ||
|  |         typename result_of<F(basic_yield_context< | ||
|  |           typename ExecutionContext::executor_type>)>::type>::type>( | ||
|  |             declval<detail::initiate_spawn< | ||
|  |               typename ExecutionContext::executor_type> >(), | ||
|  |             token, ASIO_MOVE_CAST(F)(function)))) | ||
|  | { | ||
|  |   return (spawn)(ctx.get_executor(), ASIO_MOVE_CAST(F)(function), | ||
|  |       ASIO_MOVE_CAST(CompletionToken)(token)); | ||
|  | } | ||
|  | 
 | ||
|  | template <typename Executor, typename F, | ||
|  |     ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature< | ||
|  |       typename result_of<F(basic_yield_context<Executor>)>::type>::type) | ||
|  |         CompletionToken> | ||
|  | inline ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX(CompletionToken, | ||
|  |     typename detail::spawn_signature< | ||
|  |       typename result_of<F(basic_yield_context<Executor>)>::type>::type) | ||
|  | spawn(const basic_yield_context<Executor>& ctx, | ||
|  |     ASIO_MOVE_ARG(F) function, | ||
|  |     ASIO_MOVE_ARG(CompletionToken) token, | ||
|  | #if defined(ASIO_HAS_BOOST_COROUTINE)
 | ||
|  |     typename constraint< | ||
|  |       !is_same< | ||
|  |         typename decay<CompletionToken>::type, | ||
|  |         boost::coroutines::attributes | ||
|  |       >::value | ||
|  |     >::type, | ||
|  | #endif // defined(ASIO_HAS_BOOST_COROUTINE)
 | ||
|  |     typename constraint< | ||
|  |       is_executor<Executor>::value || execution::is_executor<Executor>::value | ||
|  |     >::type) | ||
|  |   ASIO_INITFN_AUTO_RESULT_TYPE_SUFFIX(( | ||
|  |     async_initiate<CompletionToken, | ||
|  |       typename detail::spawn_signature< | ||
|  |         typename result_of<F(basic_yield_context<Executor>)>::type>::type>( | ||
|  |           declval<detail::initiate_spawn<Executor> >(), | ||
|  |           token, ASIO_MOVE_CAST(F)(function)))) | ||
|  | { | ||
|  |   return (spawn)(ctx.get_executor(), ASIO_MOVE_CAST(F)(function), | ||
|  |       ASIO_MOVE_CAST(CompletionToken)(token)); | ||
|  | } | ||
|  | 
 | ||
|  | #if defined(ASIO_HAS_BOOST_CONTEXT_FIBER)
 | ||
|  | 
 | ||
|  | template <typename Executor, typename StackAllocator, typename F, | ||
|  |     ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature< | ||
|  |       typename result_of<F(basic_yield_context<Executor>)>::type>::type) | ||
|  |         CompletionToken> | ||
|  | inline ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX(CompletionToken, | ||
|  |     typename detail::spawn_signature< | ||
|  |       typename result_of<F(basic_yield_context<Executor>)>::type>::type) | ||
|  | spawn(const Executor& ex, allocator_arg_t, | ||
|  |     ASIO_MOVE_ARG(StackAllocator) stack_allocator, | ||
|  |     ASIO_MOVE_ARG(F) function, | ||
|  |     ASIO_MOVE_ARG(CompletionToken) token, | ||
|  |     typename constraint< | ||
|  |       is_executor<Executor>::value || execution::is_executor<Executor>::value | ||
|  |     >::type) | ||
|  |   ASIO_INITFN_AUTO_RESULT_TYPE_SUFFIX(( | ||
|  |     async_initiate<CompletionToken, | ||
|  |       typename detail::spawn_signature< | ||
|  |         typename result_of<F(basic_yield_context<Executor>)>::type>::type>( | ||
|  |           declval<detail::initiate_spawn<Executor> >(), | ||
|  |           token, allocator_arg_t(), | ||
|  |           ASIO_MOVE_CAST(StackAllocator)(stack_allocator), | ||
|  |           ASIO_MOVE_CAST(F)(function)))) | ||
|  | { | ||
|  |   return async_initiate<CompletionToken, | ||
|  |     typename detail::spawn_signature< | ||
|  |       typename result_of<F(basic_yield_context<Executor>)>::type>::type>( | ||
|  |         detail::initiate_spawn<Executor>(ex), token, allocator_arg_t(), | ||
|  |         ASIO_MOVE_CAST(StackAllocator)(stack_allocator), | ||
|  |         ASIO_MOVE_CAST(F)(function)); | ||
|  | } | ||
|  | 
 | ||
|  | template <typename ExecutionContext, typename StackAllocator, typename F, | ||
|  |     ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature< | ||
|  |       typename result_of<F(basic_yield_context< | ||
|  |         typename ExecutionContext::executor_type>)>::type>::type) | ||
|  |           CompletionToken> | ||
|  | inline ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX(CompletionToken, | ||
|  |     typename detail::spawn_signature< | ||
|  |       typename result_of<F(basic_yield_context< | ||
|  |         typename ExecutionContext::executor_type>)>::type>::type) | ||
|  | spawn(ExecutionContext& ctx, allocator_arg_t, | ||
|  |     ASIO_MOVE_ARG(StackAllocator) stack_allocator, | ||
|  |     ASIO_MOVE_ARG(F) function, | ||
|  |     ASIO_MOVE_ARG(CompletionToken) token, | ||
|  |     typename constraint< | ||
|  |       is_convertible<ExecutionContext&, execution_context&>::value | ||
|  |     >::type) | ||
|  |   ASIO_INITFN_AUTO_RESULT_TYPE_SUFFIX(( | ||
|  |     async_initiate<CompletionToken, | ||
|  |       typename detail::spawn_signature< | ||
|  |         typename result_of<F(basic_yield_context< | ||
|  |           typename ExecutionContext::executor_type>)>::type>::type>( | ||
|  |             declval<detail::initiate_spawn< | ||
|  |               typename ExecutionContext::executor_type> >(), | ||
|  |             token, allocator_arg_t(), | ||
|  |             ASIO_MOVE_CAST(StackAllocator)(stack_allocator), | ||
|  |             ASIO_MOVE_CAST(F)(function)))) | ||
|  | { | ||
|  |   return (spawn)(ctx.get_executor(), allocator_arg_t(), | ||
|  |       ASIO_MOVE_CAST(StackAllocator)(stack_allocator), | ||
|  |       ASIO_MOVE_CAST(F)(function), | ||
|  |       ASIO_MOVE_CAST(CompletionToken)(token)); | ||
|  | } | ||
|  | 
 | ||
|  | template <typename Executor, typename StackAllocator, typename F, | ||
|  |     ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature< | ||
|  |       typename result_of<F(basic_yield_context<Executor>)>::type>::type) | ||
|  |         CompletionToken> | ||
|  | inline ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX(CompletionToken, | ||
|  |     typename detail::spawn_signature< | ||
|  |       typename result_of<F(basic_yield_context<Executor>)>::type>::type) | ||
|  | spawn(const basic_yield_context<Executor>& ctx, allocator_arg_t, | ||
|  |     ASIO_MOVE_ARG(StackAllocator) stack_allocator, | ||
|  |     ASIO_MOVE_ARG(F) function, | ||
|  |     ASIO_MOVE_ARG(CompletionToken) token, | ||
|  |     typename constraint< | ||
|  |       is_executor<Executor>::value || execution::is_executor<Executor>::value | ||
|  |     >::type) | ||
|  |   ASIO_INITFN_AUTO_RESULT_TYPE_SUFFIX(( | ||
|  |     async_initiate<CompletionToken, | ||
|  |       typename detail::spawn_signature< | ||
|  |         typename result_of<F(basic_yield_context<Executor>)>::type>::type>( | ||
|  |           declval<detail::initiate_spawn<Executor> >(), | ||
|  |           token, allocator_arg_t(), | ||
|  |           ASIO_MOVE_CAST(StackAllocator)(stack_allocator), | ||
|  |           ASIO_MOVE_CAST(F)(function)))) | ||
|  | { | ||
|  |   return (spawn)(ctx.get_executor(), allocator_arg_t(), | ||
|  |       ASIO_MOVE_CAST(StackAllocator)(stack_allocator), | ||
|  |       ASIO_MOVE_CAST(F)(function), | ||
|  |       ASIO_MOVE_CAST(CompletionToken)(token)); | ||
|  | } | ||
|  | 
 | ||
|  | #endif // defined(ASIO_HAS_BOOST_CONTEXT_FIBER)
 | ||
|  | 
 | ||
|  | #if defined(ASIO_HAS_BOOST_COROUTINE)
 | ||
|  | 
 | ||
|  | namespace detail { | ||
|  | 
 | ||
|  | template <typename Executor, typename Function, typename Handler> | ||
|  | class old_spawn_entry_point | ||
|  | { | ||
|  | public: | ||
|  |   template <typename F, typename H> | ||
|  |   old_spawn_entry_point(const Executor& ex, | ||
|  |       ASIO_MOVE_ARG(F) f, ASIO_MOVE_ARG(H) h) | ||
|  |     : executor_(ex), | ||
|  |       function_(ASIO_MOVE_CAST(F)(f)), | ||
|  |       handler_(ASIO_MOVE_CAST(H)(h)) | ||
|  |   { | ||
|  |   } | ||
|  | 
 | ||
|  |   void operator()(spawned_thread_base* spawned_thread) | ||
|  |   { | ||
|  |     const basic_yield_context<Executor> yield(spawned_thread, executor_); | ||
|  |     this->call(yield, | ||
|  |         void_type<typename result_of<Function( | ||
|  |           basic_yield_context<Executor>)>::type>()); | ||
|  |   } | ||
|  | 
 | ||
|  | private: | ||
|  |   void call(const basic_yield_context<Executor>& yield, void_type<void>) | ||
|  |   { | ||
|  |     function_(yield); | ||
|  |     ASIO_MOVE_OR_LVALUE(Handler)(handler_)(); | ||
|  |   } | ||
|  | 
 | ||
|  |   template <typename T> | ||
|  |   void call(const basic_yield_context<Executor>& yield, void_type<T>) | ||
|  |   { | ||
|  |     ASIO_MOVE_OR_LVALUE(Handler)(handler_)(function_(yield)); | ||
|  |   } | ||
|  | 
 | ||
|  |   Executor executor_; | ||
|  |   Function function_; | ||
|  |   Handler handler_; | ||
|  | }; | ||
|  | 
 | ||
|  | inline void default_spawn_handler() {} | ||
|  | 
 | ||
|  | } // namespace detail
 | ||
|  | 
 | ||
|  | template <typename Function> | ||
|  | inline void spawn(ASIO_MOVE_ARG(Function) function, | ||
|  |     const boost::coroutines::attributes& attributes) | ||
|  | { | ||
|  |   typedef typename decay<Function>::type function_type; | ||
|  | 
 | ||
|  |   typename associated_executor<function_type>::type ex( | ||
|  |       (get_associated_executor)(function)); | ||
|  | 
 | ||
|  |   asio::spawn(ex, ASIO_MOVE_CAST(Function)(function), attributes); | ||
|  | } | ||
|  | 
 | ||
|  | template <typename Handler, typename Function> | ||
|  | void spawn(ASIO_MOVE_ARG(Handler) handler, | ||
|  |     ASIO_MOVE_ARG(Function) function, | ||
|  |     const boost::coroutines::attributes& attributes, | ||
|  |     typename constraint< | ||
|  |       !is_executor<typename decay<Handler>::type>::value && | ||
|  |       !execution::is_executor<typename decay<Handler>::type>::value && | ||
|  |       !is_convertible<Handler&, execution_context&>::value>::type) | ||
|  | { | ||
|  |   typedef typename decay<Handler>::type handler_type; | ||
|  |   typedef typename decay<Function>::type function_type; | ||
|  |   typedef typename associated_executor<handler_type>::type executor_type; | ||
|  | 
 | ||
|  |   executor_type ex((get_associated_executor)(handler)); | ||
|  | 
 | ||
|  |   (dispatch)(ex, | ||
|  |       detail::spawned_thread_resumer( | ||
|  |         detail::spawned_coroutine_thread::spawn( | ||
|  |           detail::old_spawn_entry_point<executor_type, | ||
|  |             function_type, void (*)()>( | ||
|  |               ex, ASIO_MOVE_CAST(Function)(function), | ||
|  |               &detail::default_spawn_handler), attributes))); | ||
|  | } | ||
|  | 
 | ||
|  | template <typename Executor, typename Function> | ||
|  | void spawn(basic_yield_context<Executor> ctx, | ||
|  |     ASIO_MOVE_ARG(Function) function, | ||
|  |     const boost::coroutines::attributes& attributes) | ||
|  | { | ||
|  |   typedef typename decay<Function>::type function_type; | ||
|  | 
 | ||
|  |   (dispatch)(ctx.get_executor(), | ||
|  |       detail::spawned_thread_resumer( | ||
|  |         detail::spawned_coroutine_thread::spawn( | ||
|  |           detail::old_spawn_entry_point<Executor, | ||
|  |             function_type, void (*)()>(ctx.get_executor(), | ||
|  |               ASIO_MOVE_CAST(Function)(function), | ||
|  |               &detail::default_spawn_handler), attributes))); | ||
|  | } | ||
|  | 
 | ||
|  | template <typename Function, typename Executor> | ||
|  | inline void spawn(const Executor& ex, | ||
|  |     ASIO_MOVE_ARG(Function) function, | ||
|  |     const boost::coroutines::attributes& attributes, | ||
|  |     typename constraint< | ||
|  |       is_executor<Executor>::value || execution::is_executor<Executor>::value | ||
|  |     >::type) | ||
|  | { | ||
|  |   asio::spawn(asio::strand<Executor>(ex), | ||
|  |       ASIO_MOVE_CAST(Function)(function), attributes); | ||
|  | } | ||
|  | 
 | ||
|  | template <typename Function, typename Executor> | ||
|  | inline void spawn(const strand<Executor>& ex, | ||
|  |     ASIO_MOVE_ARG(Function) function, | ||
|  |     const boost::coroutines::attributes& attributes) | ||
|  | { | ||
|  |   asio::spawn(asio::bind_executor( | ||
|  |         ex, &detail::default_spawn_handler), | ||
|  |       ASIO_MOVE_CAST(Function)(function), attributes); | ||
|  | } | ||
|  | 
 | ||
|  | #if !defined(ASIO_NO_TS_EXECUTORS)
 | ||
|  | 
 | ||
|  | template <typename Function> | ||
|  | inline void spawn(const asio::io_context::strand& s, | ||
|  |     ASIO_MOVE_ARG(Function) function, | ||
|  |     const boost::coroutines::attributes& attributes) | ||
|  | { | ||
|  |   asio::spawn(asio::bind_executor( | ||
|  |         s, &detail::default_spawn_handler), | ||
|  |       ASIO_MOVE_CAST(Function)(function), attributes); | ||
|  | } | ||
|  | 
 | ||
|  | #endif // !defined(ASIO_NO_TS_EXECUTORS)
 | ||
|  | 
 | ||
|  | template <typename Function, typename ExecutionContext> | ||
|  | inline void spawn(ExecutionContext& ctx, | ||
|  |     ASIO_MOVE_ARG(Function) function, | ||
|  |     const boost::coroutines::attributes& attributes, | ||
|  |     typename constraint<is_convertible< | ||
|  |       ExecutionContext&, execution_context&>::value>::type) | ||
|  | { | ||
|  |   asio::spawn(ctx.get_executor(), | ||
|  |       ASIO_MOVE_CAST(Function)(function), attributes); | ||
|  | } | ||
|  | 
 | ||
|  | #endif // defined(ASIO_HAS_BOOST_COROUTINE)
 | ||
|  | 
 | ||
|  | } // namespace asio
 | ||
|  | 
 | ||
|  | #include "asio/detail/pop_options.hpp"
 | ||
|  | 
 | ||
|  | #endif // ASIO_IMPL_SPAWN_HPP
 |