summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/asio/include/asio/impl/spawn.hpp
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/asio/include/asio/impl/spawn.hpp')
-rw-r--r--3rdparty/asio/include/asio/impl/spawn.hpp1499
1 files changed, 1184 insertions, 315 deletions
diff --git a/3rdparty/asio/include/asio/impl/spawn.hpp b/3rdparty/asio/include/asio/impl/spawn.hpp
index 82a05f086a2..38a96406ed4 100644
--- a/3rdparty/asio/include/asio/impl/spawn.hpp
+++ b/3rdparty/asio/include/asio/impl/spawn.hpp
@@ -2,7 +2,7 @@
// impl/spawn.hpp
// ~~~~~~~~~~~~~~
//
-// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2003-2024 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)
@@ -16,513 +16,1382 @@
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
+#include <tuple>
#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/handler_alloc_helpers.hpp"
+#include "asio/detail/bind_handler.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/system_error.hpp"
+#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 {
- template <typename Handler, typename T>
- class coro_handler
+#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)
{
- public:
- coro_handler(basic_yield_context<Handler> ctx)
- : coro_(ctx.coro_.lock()),
- ca_(ctx.ca_),
- handler_(ctx.handler_),
- ready_(0),
- ec_(ctx.ec_),
- value_(0)
+ }
+
+ template <typename F>
+ static spawned_thread_base* spawn(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<decay_t<F>>(
+ static_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(F&& f,
+ cancellation_slot parent_cancel_slot = cancellation_slot(),
+ cancellation_state cancel_state = cancellation_state())
+ {
+ return spawn(static_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();
+ }
- void operator()(T value)
+private:
+ template <typename Function>
+ class entry_point
+ {
+ public:
+ template <typename F>
+ entry_point(F&& f,
+ spawned_coroutine_thread** spawned_thread_out)
+ : function_(static_cast<F&&>(f)),
+ spawned_thread_out_(spawned_thread_out)
{
- *ec_ = asio::error_code();
- *value_ = ASIO_MOVE_CAST(T)(value);
- if (--*ready_ == 0)
- (*coro_)();
}
- void operator()(asio::error_code ec, T value)
+ void operator()(caller_type& caller)
{
- *ec_ = ec;
- *value_ = ASIO_MOVE_CAST(T)(value);
- if (--*ready_ == 0)
- (*coro_)();
+ Function function(static_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:
- shared_ptr<typename basic_yield_context<Handler>::callee_type> coro_;
- typename basic_yield_context<Handler>::caller_type& ca_;
- Handler handler_;
- atomic_count* ready_;
- asio::error_code* ec_;
- T* value_;
+ private:
+ Function function_;
+ spawned_coroutine_thread** spawned_thread_out_;
};
- template <typename Handler>
- class coro_handler<Handler, void>
+ 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(fiber_type&& caller)
+ : caller_(static_cast<fiber_type&&>(caller)),
+ on_suspend_fn_(0),
+ on_suspend_arg_(0)
{
- public:
- coro_handler(basic_yield_context<Handler> ctx)
- : coro_(ctx.coro_.lock()),
- ca_(ctx.ca_),
- handler_(ctx.handler_),
- ready_(0),
- ec_(ctx.ec_)
+ }
+
+ template <typename StackAllocator, typename F>
+ static spawned_thread_base* spawn(allocator_arg_t,
+ StackAllocator&& stack_allocator,
+ 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(),
+ static_cast<StackAllocator&&>(stack_allocator),
+ entry_point<decay_t<F>>(
+ static_cast<F&&>(f), &spawned_thread));
+ callee = fiber_type(static_cast<fiber_type&&>(callee)).resume();
+ spawned_thread->callee_ = static_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(F&& f,
+ cancellation_slot parent_cancel_slot = cancellation_slot(),
+ cancellation_state cancel_state = cancellation_state())
+ {
+ return spawn(allocator_arg_t(), boost::context::fixedsize_stack(),
+ static_cast<F&&>(f), parent_cancel_slot, cancel_state);
+ }
+
+ void resume()
+ {
+ callee_ = fiber_type(static_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 operator()()
+ 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(static_cast<fiber_type&&>(caller_)).resume();
+ }
+
+ void destroy()
+ {
+ fiber_type callee = static_cast<fiber_type&&>(callee_);
+ if (terminal_)
+ fiber_type(static_cast<fiber_type&&>(callee)).resume();
+ }
+
+private:
+ template <typename Function>
+ class entry_point
+ {
+ public:
+ template <typename F>
+ entry_point(F&& f,
+ spawned_fiber_thread** spawned_thread_out)
+ : function_(static_cast<F&&>(f)),
+ spawned_thread_out_(spawned_thread_out)
{
- *ec_ = asio::error_code();
- if (--*ready_ == 0)
- (*coro_)();
}
- void operator()(asio::error_code ec)
+ fiber_type operator()(fiber_type&& caller)
{
- *ec_ = ec;
- if (--*ready_ == 0)
- (*coro_)();
+ Function function(static_cast<Function&&>(function_));
+ spawned_fiber_thread spawned_thread(
+ static_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 static_cast<fiber_type&&>(spawned_thread.caller_);
}
- //private:
- shared_ptr<typename basic_yield_context<Handler>::callee_type> coro_;
- typename basic_yield_context<Handler>::caller_type& ca_;
- Handler handler_;
- atomic_count* ready_;
- asio::error_code* ec_;
+ private:
+ Function function_;
+ spawned_fiber_thread** spawned_thread_out_;
};
- template <typename Handler, typename T>
- inline void* asio_handler_allocate(std::size_t size,
- coro_handler<Handler, T>* this_handler)
+ 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)
+ {
+ }
+
+ spawned_thread_resumer(spawned_thread_resumer&& other) noexcept
+ : spawned_thread_(other.spawned_thread_)
{
- return asio_handler_alloc_helpers::allocate(
- size, this_handler->handler_);
+ other.spawned_thread_ = 0;
}
- template <typename Handler, typename T>
- inline void asio_handler_deallocate(void* pointer, std::size_t size,
- coro_handler<Handler, T>* this_handler)
+ ~spawned_thread_resumer()
{
- asio_handler_alloc_helpers::deallocate(
- pointer, size, this_handler->handler_);
+ if (spawned_thread_)
+ spawned_thread_->destroy();
}
- template <typename Handler, typename T>
- inline bool asio_handler_is_continuation(coro_handler<Handler, T>*)
+ void operator()()
{
- return true;
+ spawned_thread_->attach(&spawned_thread_);
+ spawned_thread_->resume();
}
- template <typename Function, typename Handler, typename T>
- inline void asio_handler_invoke(Function& function,
- coro_handler<Handler, T>* this_handler)
+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)
{
- asio_handler_invoke_helpers::invoke(
- function, this_handler->handler_);
+ spawned_thread->detach();
}
- template <typename Function, typename Handler, typename T>
- inline void asio_handler_invoke(const Function& function,
- coro_handler<Handler, T>* this_handler)
+ spawned_thread_destroyer(spawned_thread_destroyer&& other) noexcept
+ : spawned_thread_(other.spawned_thread_)
{
- asio_handler_invoke_helpers::invoke(
- function, this_handler->handler_);
+ other.spawned_thread_ = 0;
}
- template <typename Handler, typename T>
- class coro_async_result
+ ~spawned_thread_destroyer()
{
- public:
- typedef coro_handler<Handler, T> completion_handler_type;
- typedef T return_type;
+ if (spawned_thread_)
+ spawned_thread_->destroy();
+ }
- explicit coro_async_result(completion_handler_type& h)
- : handler_(h),
- ca_(h.ca_),
- ready_(2)
+ void operator()()
+ {
+ if (spawned_thread_)
{
- h.ready_ = &ready_;
- out_ec_ = h.ec_;
- if (!out_ec_) h.ec_ = &ec_;
- h.value_ = &value_;
+ spawned_thread_->destroy();
+ spawned_thread_ = 0;
}
+ }
- return_type get()
- {
- // Must not hold shared_ptr to coro while suspended.
- handler_.coro_.reset();
+private:
+ spawned_thread_base* spawned_thread_;
+};
- if (--ready_ != 0)
- ca_();
- if (!out_ec_ && ec_) throw asio::system_error(ec_);
- return ASIO_MOVE_CAST(return_type)(value_);
- }
+// 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;
- private:
- completion_handler_type& handler_;
- typename basic_yield_context<Handler>::caller_type& ca_;
- atomic_count ready_;
- asio::error_code* out_ec_;
- asio::error_code ec_;
- return_type value_;
- };
+ spawn_handler_base(const basic_yield_context<Executor>& yield)
+ : yield_(yield),
+ spawned_thread_(yield.spawned_thread_)
+ {
+ spawned_thread_->detach();
+ }
+
+ spawn_handler_base(spawn_handler_base&& other) noexcept
+ : yield_(other.yield_),
+ spawned_thread_(other.spawned_thread_)
- template <typename Handler>
- class coro_async_result<Handler, void>
{
- public:
- typedef coro_handler<Handler, void> completion_handler_type;
- typedef void return_type;
+ other.spawned_thread_ = 0;
+ }
- explicit coro_async_result(completion_handler_type& h)
- : handler_(h),
- ca_(h.ca_),
- ready_(2)
- {
- h.ready_ = &ready_;
- out_ec_ = h.ec_;
- if (!out_ec_) h.ec_ = &ec_;
- }
+ ~spawn_handler_base()
+ {
+ if (spawned_thread_)
+ (post)(yield_.executor_, spawned_thread_destroyer(spawned_thread_));
+ }
- void get()
- {
- // Must not hold shared_ptr to coro while suspended.
- handler_.coro_.reset();
+ executor_type get_executor() const noexcept
+ {
+ return yield_.executor_;
+ }
- if (--ready_ != 0)
- ca_();
- if (!out_ec_ && ec_) throw asio::system_error(ec_);
- }
+ cancellation_slot_type get_cancellation_slot() const noexcept
+ {
+ return spawned_thread_->get_cancellation_slot();
+ }
- private:
- completion_handler_type& handler_;
- typename basic_yield_context<Handler>::caller_type& ca_;
- atomic_count ready_;
- asio::error_code* out_ec_;
- asio::error_code ec_;
- };
+ void resume()
+ {
+ spawned_thread_resumer resumer(spawned_thread_);
+ spawned_thread_ = 0;
+ resumer();
+ }
-} // namespace detail
+protected:
+ const basic_yield_context<Executor>& yield_;
+ spawned_thread_base* spawned_thread_;
+};
-#if !defined(GENERATING_DOCUMENTATION)
+// Completion handlers for when basic_yield_context is used as a token.
+template <typename Executor, typename Signature>
+class spawn_handler;
-template <typename Handler, typename ReturnType>
-class async_result<basic_yield_context<Handler>, ReturnType()>
- : public detail::coro_async_result<Handler, void>
+template <typename Executor, typename R>
+class spawn_handler<Executor, R()>
+ : public spawn_handler_base<Executor>
{
public:
- explicit async_result(
- typename detail::coro_async_result<Handler,
- void>::completion_handler_type& h)
- : detail::coro_async_result<Handler, void>(h)
+ 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 Handler, typename ReturnType, typename Arg1>
-class async_result<basic_yield_context<Handler>, ReturnType(Arg1)>
- : public detail::coro_async_result<Handler, typename decay<Arg1>::type>
+template <typename Executor, typename R>
+class spawn_handler<Executor, R(asio::error_code)>
+ : public spawn_handler_base<Executor>
{
public:
- explicit async_result(
- typename detail::coro_async_result<Handler,
- typename decay<Arg1>::type>::completion_handler_type& h)
- : detail::coro_async_result<Handler, Arg1>(h)
+ 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 Handler, typename ReturnType>
-class async_result<basic_yield_context<Handler>,
- ReturnType(asio::error_code)>
- : public detail::coro_async_result<Handler, void>
+template <typename Executor, typename R>
+class spawn_handler<Executor, R(exception_ptr)>
+ : public spawn_handler_base<Executor>
{
public:
- explicit async_result(
- typename detail::coro_async_result<Handler,
- void>::completion_handler_type& h)
- : detail::coro_async_result<Handler, void>(h)
+ 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 Handler, typename ReturnType, typename Arg2>
-class async_result<basic_yield_context<Handler>,
- ReturnType(asio::error_code, Arg2)>
- : public detail::coro_async_result<Handler, typename decay<Arg2>::type>
+template <typename Executor, typename R, typename T>
+class spawn_handler<Executor, R(T)>
+ : public spawn_handler_base<Executor>
{
public:
- explicit async_result(
- typename detail::coro_async_result<Handler,
- typename decay<Arg2>::type>::completion_handler_type& h)
- : detail::coro_async_result<Handler, Arg2>(h)
+ 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)
{
}
-};
-#if !defined(ASIO_NO_DEPRECATED)
+ void operator()(T value)
+ {
+ result_ = &value;
+ this->resume();
+ }
-template <typename Handler, typename ReturnType>
-struct handler_type<basic_yield_context<Handler>, ReturnType()>
-{
- typedef detail::coro_handler<Handler, void> type;
+ static return_type on_resume(result_type& result)
+ {
+ return static_cast<return_type&&>(*result);
+ }
+
+private:
+ result_type& result_;
};
-template <typename Handler, typename ReturnType, typename Arg1>
-struct handler_type<basic_yield_context<Handler>, ReturnType(Arg1)>
+template <typename Executor, typename R, typename T>
+class spawn_handler<Executor, R(asio::error_code, T)>
+ : public spawn_handler_base<Executor>
{
- typedef detail::coro_handler<Handler, typename decay<Arg1>::type> type;
+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 static_cast<return_type&&>(*result.value_);
+ }
+
+private:
+ result_type& result_;
};
-template <typename Handler, typename ReturnType>
-struct handler_type<basic_yield_context<Handler>,
- ReturnType(asio::error_code)>
+template <typename Executor, typename R, typename T>
+class spawn_handler<Executor, R(exception_ptr, T)>
+ : public spawn_handler_base<Executor>
{
- typedef detail::coro_handler<Handler, void> type;
+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 static_cast<return_type&&>(*result.value_);
+ }
+
+private:
+ result_type& result_;
};
-template <typename Handler, typename ReturnType, typename Arg2>
-struct handler_type<basic_yield_context<Handler>,
- ReturnType(asio::error_code, Arg2)>
+template <typename Executor, typename R, typename... Ts>
+class spawn_handler<Executor, R(Ts...)>
+ : public spawn_handler_base<Executor>
{
- typedef detail::coro_handler<Handler, typename decay<Arg2>::type> type;
+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()(Args&&... args)
+ {
+ return_type value(static_cast<Args&&>(args)...);
+ result_ = &value;
+ this->resume();
+ }
+
+ static return_type on_resume(result_type& result)
+ {
+ return static_cast<return_type&&>(*result);
+ }
+
+private:
+ result_type& result_;
};
-template <typename Handler, typename T>
-class async_result<detail::coro_handler<Handler, T> >
- : public detail::coro_async_result<Handler, T>
+template <typename Executor, typename R, typename... Ts>
+class spawn_handler<Executor, R(asio::error_code, Ts...)>
+ : public spawn_handler_base<Executor>
{
public:
- typedef typename detail::coro_async_result<Handler, T>::return_type type;
+ typedef std::tuple<Ts...> return_type;
- explicit async_result(
- typename detail::coro_async_result<Handler,
- void>::completion_handler_type& h)
- : detail::coro_async_result<Handler, T>(h)
+ 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)
{
}
-};
-#endif // !defined(ASIO_NO_DEPRECATED)
+ template <typename... Args>
+ void operator()(asio::error_code ec,
+ Args&&... args)
+ {
+ return_type value(static_cast<Args&&>(args)...);
+ if (this->yield_.ec_)
+ {
+ *this->yield_.ec_ = ec;
+ result_.ec_ = 0;
+ }
+ else
+ result_.ec_ = &ec;
+ result_.value_ = &value;
+ this->resume();
+ }
-template <typename Handler, typename T, typename Allocator>
-struct associated_allocator<detail::coro_handler<Handler, T>, Allocator>
+ static return_type on_resume(result_type& result)
+ {
+ if (result.ec_)
+ throw_error(*result.ec_);
+ return static_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>
{
- typedef typename associated_allocator<Handler, Allocator>::type type;
+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)
+ {
+ }
- static type get(const detail::coro_handler<Handler, T>& h,
- const Allocator& a = Allocator()) ASIO_NOEXCEPT
+ template <typename... Args>
+ void operator()(exception_ptr ex, Args&&... args)
{
- return associated_allocator<Handler, Allocator>::get(h.handler_, a);
+ return_type value(static_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 static_cast<return_type&&>(*result.value_);
+ }
+
+private:
+ result_type& result_;
};
-template <typename Handler, typename T, typename Executor>
-struct associated_executor<detail::coro_handler<Handler, T>, Executor>
+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>
{
- typedef typename associated_executor<Handler, Executor>::type type;
+public:
+ typedef typename detail::spawn_handler<Executor, Signature> handler_type;
+ typedef typename handler_type::return_type return_type;
+
+#if defined(ASIO_HAS_VARIADIC_LAMBDA_CAPTURES)
- static type get(const detail::coro_handler<Handler, T>& h,
- const Executor& ex = Executor()) ASIO_NOEXCEPT
+ template <typename Initiation, typename... InitArgs>
+ static return_type initiate(Initiation&& init,
+ const basic_yield_context<Executor>& yield,
+ InitArgs&&... init_args)
{
- return associated_executor<Handler, Executor>::get(h.handler_, ex);
+ typename handler_type::result_type result
+ = typename handler_type::result_type();
+
+ yield.spawned_thread_->suspend_with(
+ [&]()
+ {
+ static_cast<Initiation&&>(init)(
+ handler_type(yield, result),
+ static_cast<InitArgs&&>(init_args)...);
+ });
+
+ return handler_type::on_resume(result);
}
-};
-namespace detail {
+#else // defined(ASIO_HAS_VARIADIC_LAMBDA_CAPTURES)
- template <typename Handler, typename Function>
- struct spawn_data : private noncopyable
+ template <typename Initiation, typename... InitArgs>
+ struct suspend_with_helper
{
- spawn_data(ASIO_MOVE_ARG(Handler) handler,
- bool call_handler, ASIO_MOVE_ARG(Function) function)
- : handler_(ASIO_MOVE_CAST(Handler)(handler)),
- call_handler_(call_handler),
- function_(ASIO_MOVE_CAST(Function)(function))
+ typename handler_type::result_type& result_;
+ Initiation&& init_;
+ const basic_yield_context<Executor>& yield_;
+ std::tuple<InitArgs&&...> init_args_;
+
+ template <std::size_t... I>
+ void do_invoke(detail::index_sequence<I...>)
{
+ static_cast<Initiation&&>(init_)(
+ handler_type(yield_, result_),
+ static_cast<InitArgs&&>(std::get<I>(init_args_))...);
}
- weak_ptr<typename basic_yield_context<Handler>::callee_type> coro_;
- Handler handler_;
- bool call_handler_;
- Function function_;
+ void operator()()
+ {
+ this->do_invoke(detail::make_index_sequence<sizeof...(InitArgs)>());
+ }
};
- template <typename Handler, typename Function>
- struct coro_entry_point
+ template <typename Initiation, typename... InitArgs>
+ static return_type initiate(Initiation&& init,
+ const basic_yield_context<Executor>& yield,
+ 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, static_cast<Initiation&&>(init), yield,
+ std::tuple<InitArgs&&...>(
+ static_cast<InitArgs&&>(init_args)...)});
+
+ return handler_type::on_resume(result);
+ }
+
+#endif // defined(ASIO_HAS_VARIADIC_LAMBDA_CAPTURES)
+};
+
+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,
+ F&& f, H&& h)
+ : executor_(ex),
+ function_(static_cast<F&&>(f)),
+ handler_(static_cast<H&&>(h)),
+ work_(handler_, executor_)
+ {
+ }
+
+ void operator()(spawned_thread_base* spawned_thread)
{
- void operator()(typename basic_yield_context<Handler>::caller_type& ca)
+ const basic_yield_context<Executor> yield(spawned_thread, executor_);
+ this->call(yield,
+ void_type<result_of_t<Function(basic_yield_context<Executor>)>>());
+ }
+
+private:
+ void call(const basic_yield_context<Executor>& yield, void_type<void>)
+ {
+#if !defined(ASIO_NO_EXCEPTIONS)
+ try
+#endif // !defined(ASIO_NO_EXCEPTIONS)
{
- shared_ptr<spawn_data<Handler, Function> > data(data_);
-#if !defined(BOOST_COROUTINES_UNIDIRECT) && !defined(BOOST_COROUTINES_V2)
- ca(); // Yield until coroutine pointer has been initialised.
-#endif // !defined(BOOST_COROUTINES_UNIDIRECT) && !defined(BOOST_COROUTINES_V2)
- const basic_yield_context<Handler> yield(
- data->coro_, ca, data->handler_);
-
- (data->function_)(yield);
- if (data->call_handler_)
- (data->handler_)();
+ 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)
+ }
- shared_ptr<spawn_data<Handler, Function> > data_;
- };
-
- template <typename Handler, typename Function>
- struct spawn_helper
+ template <typename T>
+ void call(const basic_yield_context<Executor>& yield, void_type<T>)
{
- void operator()()
+#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(), static_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 (...)
{
- typedef typename basic_yield_context<Handler>::callee_type callee_type;
- coro_entry_point<Handler, Function> entry_point = { data_ };
- shared_ptr<callee_type> coro(new callee_type(entry_point, attributes_));
- data_->coro_ = coro;
- (*coro)();
+ 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)
+ }
- shared_ptr<spawn_data<Handler, Function> > data_;
- boost::coroutines::attributes attributes_;
- };
+ Executor executor_;
+ Function function_;
+ Handler handler_;
+ handler_work<Handler, Executor> work_;
+};
+
+struct spawn_cancellation_signal_emitter
+{
+ cancellation_signal* signal_;
+ cancellation_type_t type_;
- template <typename Function, typename Handler, typename Function1>
- inline void asio_handler_invoke(Function& function,
- spawn_helper<Handler, Function1>* this_handler)
+ void operator()()
{
- asio_handler_invoke_helpers::invoke(
- function, this_handler->data_->handler_);
+ signal_->emit(type_);
}
+};
- template <typename Function, typename Handler, typename Function1>
- inline void asio_handler_invoke(const Function& function,
- spawn_helper<Handler, Function1>* this_handler)
+template <typename Handler, typename Executor, typename = void>
+class spawn_cancellation_handler
+{
+public:
+ spawn_cancellation_handler(const Handler&, const Executor& ex)
+ : ex_(ex)
{
- asio_handler_invoke_helpers::invoke(
- function, this_handler->data_->handler_);
}
- inline void default_spawn_handler() {}
+ cancellation_slot slot()
+ {
+ return signal_.slot();
+ }
-} // namespace detail
+ void operator()(cancellation_type_t type)
+ {
+ spawn_cancellation_signal_emitter emitter = { &signal_, type };
+ (dispatch)(ex_, emitter);
+ }
-template <typename Function>
-inline void spawn(ASIO_MOVE_ARG(Function) function,
- const boost::coroutines::attributes& attributes)
+private:
+ cancellation_signal signal_;
+ Executor ex_;
+};
+
+
+template <typename Handler, typename Executor>
+class spawn_cancellation_handler<Handler, Executor,
+ enable_if_t<
+ is_same<
+ typename associated_executor<Handler,
+ Executor>::asio_associated_executor_is_unspecialised,
+ void
+ >::value
+ >>
{
- typedef typename decay<Function>::type function_type;
+public:
+ spawn_cancellation_handler(const Handler&, const Executor&)
+ {
+ }
- typename associated_executor<function_type>::type ex(
- (get_associated_executor)(function));
+ 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;
- asio::spawn(ex, ASIO_MOVE_CAST(Function)(function), attributes);
+ explicit initiate_spawn(const executor_type& ex)
+ : executor_(ex)
+ {
+ }
+
+ executor_type get_executor() const noexcept
+ {
+ return executor_;
+ }
+
+ template <typename Handler, typename F>
+ void operator()(Handler&& handler,
+ F&& f) const
+ {
+ typedef decay_t<Handler> handler_type;
+ typedef decay_t<F> function_type;
+ typedef spawn_cancellation_handler<
+ handler_type, Executor> cancel_handler_type;
+
+ associated_cancellation_slot_t<handler_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_, static_cast<F&&>(f),
+ static_cast<Handler&&>(handler)),
+ proxy_slot, cancel_state)));
+ }
+
+#if defined(ASIO_HAS_BOOST_CONTEXT_FIBER)
+
+ template <typename Handler, typename StackAllocator, typename F>
+ void operator()(Handler&& handler, allocator_arg_t,
+ StackAllocator&& stack_allocator,
+ F&& f) const
+ {
+ typedef decay_t<Handler> handler_type;
+ typedef decay_t<F> function_type;
+ typedef spawn_cancellation_handler<
+ handler_type, Executor> cancel_handler_type;
+
+ associated_cancellation_slot_t<handler_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(),
+ static_cast<StackAllocator&&>(stack_allocator),
+ spawn_entry_point<Executor, function_type, handler_type>(
+ executor_, static_cast<F&&>(f),
+ static_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<
+ result_of_t<F(basic_yield_context<Executor>)>>::type) CompletionToken>
+inline auto spawn(const Executor& ex, F&& function, CompletionToken&& token,
+#if defined(ASIO_HAS_BOOST_COROUTINE)
+ constraint_t<
+ !is_same<
+ decay_t<CompletionToken>,
+ boost::coroutines::attributes
+ >::value
+ >,
+#endif // defined(ASIO_HAS_BOOST_COROUTINE)
+ constraint_t<
+ is_executor<Executor>::value || execution::is_executor<Executor>::value
+ >)
+ -> decltype(
+ async_initiate<CompletionToken,
+ typename detail::spawn_signature<
+ result_of_t<F(basic_yield_context<Executor>)>>::type>(
+ declval<detail::initiate_spawn<Executor>>(),
+ token, static_cast<F&&>(function)))
+{
+ return async_initiate<CompletionToken,
+ typename detail::spawn_signature<
+ result_of_t<F(basic_yield_context<Executor>)>>::type>(
+ detail::initiate_spawn<Executor>(ex),
+ token, static_cast<F&&>(function));
}
-template <typename Handler, typename Function>
-void spawn(ASIO_MOVE_ARG(Handler) handler,
- ASIO_MOVE_ARG(Function) function,
- const boost::coroutines::attributes& attributes,
- typename enable_if<!is_executor<typename decay<Handler>::type>::value &&
- !is_convertible<Handler&, execution_context&>::value>::type*)
+template <typename ExecutionContext, typename F,
+ ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
+ result_of_t<F(basic_yield_context<
+ typename ExecutionContext::executor_type>)>>::type) CompletionToken>
+inline auto spawn(ExecutionContext& ctx, F&& function, CompletionToken&& token,
+#if defined(ASIO_HAS_BOOST_COROUTINE)
+ constraint_t<
+ !is_same<
+ decay_t<CompletionToken>,
+ boost::coroutines::attributes
+ >::value
+ >,
+#endif // defined(ASIO_HAS_BOOST_COROUTINE)
+ constraint_t<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >)
+ -> decltype(
+ async_initiate<CompletionToken,
+ typename detail::spawn_signature<
+ result_of_t<F(basic_yield_context<
+ typename ExecutionContext::executor_type>)>>::type>(
+ declval<detail::initiate_spawn<
+ typename ExecutionContext::executor_type>>(),
+ token, static_cast<F&&>(function)))
{
- typedef typename decay<Handler>::type handler_type;
+ return (spawn)(ctx.get_executor(), static_cast<F&&>(function),
+ static_cast<CompletionToken&&>(token));
+}
- typename associated_executor<handler_type>::type ex(
- (get_associated_executor)(handler));
+template <typename Executor, typename F,
+ ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
+ result_of_t<F(basic_yield_context<Executor>)>>::type)
+ CompletionToken>
+inline auto spawn(const basic_yield_context<Executor>& ctx,
+ F&& function, CompletionToken&& token,
+#if defined(ASIO_HAS_BOOST_COROUTINE)
+ constraint_t<
+ !is_same<
+ decay_t<CompletionToken>,
+ boost::coroutines::attributes
+ >::value
+ >,
+#endif // defined(ASIO_HAS_BOOST_COROUTINE)
+ constraint_t<
+ is_executor<Executor>::value || execution::is_executor<Executor>::value
+ >)
+ -> decltype(
+ async_initiate<CompletionToken,
+ typename detail::spawn_signature<
+ result_of_t<F(basic_yield_context<Executor>)>>::type>(
+ declval<detail::initiate_spawn<Executor>>(),
+ token, static_cast<F&&>(function)))
+{
+ return (spawn)(ctx.get_executor(), static_cast<F&&>(function),
+ static_cast<CompletionToken&&>(token));
+}
- typename associated_allocator<handler_type>::type a(
- (get_associated_allocator)(handler));
+#if defined(ASIO_HAS_BOOST_CONTEXT_FIBER)
+
+template <typename Executor, typename StackAllocator, typename F,
+ ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
+ result_of_t<F(basic_yield_context<Executor>)>>::type)
+ CompletionToken>
+inline auto spawn(const Executor& ex, allocator_arg_t,
+ StackAllocator&& stack_allocator, F&& function, CompletionToken&& token,
+ constraint_t<
+ is_executor<Executor>::value || execution::is_executor<Executor>::value
+ >)
+ -> decltype(
+ async_initiate<CompletionToken,
+ typename detail::spawn_signature<
+ result_of_t<F(basic_yield_context<Executor>)>>::type>(
+ declval<detail::initiate_spawn<Executor>>(),
+ token, allocator_arg_t(),
+ static_cast<StackAllocator&&>(stack_allocator),
+ static_cast<F&&>(function)))
+{
+ return async_initiate<CompletionToken,
+ typename detail::spawn_signature<
+ result_of_t<F(basic_yield_context<Executor>)>>::type>(
+ detail::initiate_spawn<Executor>(ex), token, allocator_arg_t(),
+ static_cast<StackAllocator&&>(stack_allocator),
+ static_cast<F&&>(function));
+}
- detail::spawn_helper<handler_type, Function> helper;
- helper.data_.reset(
- new detail::spawn_data<handler_type, Function>(
- ASIO_MOVE_CAST(Handler)(handler), true,
- ASIO_MOVE_CAST(Function)(function)));
- helper.attributes_ = attributes;
+template <typename ExecutionContext, typename StackAllocator, typename F,
+ ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
+ result_of_t<F(basic_yield_context<
+ typename ExecutionContext::executor_type>)>>::type) CompletionToken>
+inline auto spawn(ExecutionContext& ctx, allocator_arg_t,
+ StackAllocator&& stack_allocator, F&& function, CompletionToken&& token,
+ constraint_t<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >)
+ -> decltype(
+ async_initiate<CompletionToken,
+ typename detail::spawn_signature<
+ result_of_t<F(basic_yield_context<
+ typename ExecutionContext::executor_type>)>>::type>(
+ declval<detail::initiate_spawn<
+ typename ExecutionContext::executor_type>>(),
+ token, allocator_arg_t(),
+ static_cast<StackAllocator&&>(stack_allocator),
+ static_cast<F&&>(function)))
+{
+ return (spawn)(ctx.get_executor(), allocator_arg_t(),
+ static_cast<StackAllocator&&>(stack_allocator),
+ static_cast<F&&>(function), static_cast<CompletionToken&&>(token));
+}
- ex.dispatch(helper, a);
+template <typename Executor, typename StackAllocator, typename F,
+ ASIO_COMPLETION_TOKEN_FOR(typename detail::spawn_signature<
+ result_of_t<F(basic_yield_context<Executor>)>>::type) CompletionToken>
+inline auto spawn(const basic_yield_context<Executor>& ctx, allocator_arg_t,
+ StackAllocator&& stack_allocator, F&& function, CompletionToken&& token,
+ constraint_t<
+ is_executor<Executor>::value || execution::is_executor<Executor>::value
+ >)
+ -> decltype(
+ async_initiate<CompletionToken,
+ typename detail::spawn_signature<
+ result_of_t<F(basic_yield_context<Executor>)>>::type>(
+ declval<detail::initiate_spawn<Executor>>(), token,
+ allocator_arg_t(), static_cast<StackAllocator&&>(stack_allocator),
+ static_cast<F&&>(function)))
+{
+ return (spawn)(ctx.get_executor(), allocator_arg_t(),
+ static_cast<StackAllocator&&>(stack_allocator),
+ static_cast<F&&>(function), static_cast<CompletionToken&&>(token));
}
-template <typename Handler, typename Function>
-void spawn(basic_yield_context<Handler> ctx,
- ASIO_MOVE_ARG(Function) function,
- const boost::coroutines::attributes& attributes)
+#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
{
- Handler handler(ctx.handler_); // Explicit copy that might be moved from.
+public:
+ template <typename F, typename H>
+ old_spawn_entry_point(const Executor& ex, F&& f, H&& h)
+ : executor_(ex),
+ function_(static_cast<F&&>(f)),
+ handler_(static_cast<H&&>(h))
+ {
+ }
- typename associated_executor<Handler>::type ex(
- (get_associated_executor)(handler));
+ void operator()(spawned_thread_base* spawned_thread)
+ {
+ const basic_yield_context<Executor> yield(spawned_thread, executor_);
+ this->call(yield,
+ void_type<result_of_t<Function(basic_yield_context<Executor>)>>());
+ }
- typename associated_allocator<Handler>::type a(
- (get_associated_allocator)(handler));
+private:
+ void call(const basic_yield_context<Executor>& yield, void_type<void>)
+ {
+ function_(yield);
+ static_cast<Handler&&>(handler_)();
+ }
- detail::spawn_helper<Handler, Function> helper;
- helper.data_.reset(
- new detail::spawn_data<Handler, Function>(
- ASIO_MOVE_CAST(Handler)(handler), false,
- ASIO_MOVE_CAST(Function)(function)));
- helper.attributes_ = attributes;
+ template <typename T>
+ void call(const basic_yield_context<Executor>& yield, void_type<T>)
+ {
+ static_cast<Handler&&>(handler_)(function_(yield));
+ }
- ex.dispatch(helper, a);
+ Executor executor_;
+ Function function_;
+ Handler handler_;
+};
+
+inline void default_spawn_handler() {}
+
+} // namespace detail
+
+template <typename Function>
+inline void spawn(Function&& function,
+ const boost::coroutines::attributes& attributes)
+{
+ associated_executor_t<decay_t<Function>> ex(
+ (get_associated_executor)(function));
+
+ asio::spawn(ex, static_cast<Function&&>(function), attributes);
+}
+
+template <typename Handler, typename Function>
+void spawn(Handler&& handler, Function&& function,
+ const boost::coroutines::attributes& attributes,
+ constraint_t<
+ !is_executor<decay_t<Handler>>::value &&
+ !execution::is_executor<decay_t<Handler>>::value &&
+ !is_convertible<Handler&, execution_context&>::value>)
+{
+ typedef associated_executor_t<decay_t<Handler>> 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,
+ decay_t<Function>, void (*)()>(
+ ex, static_cast<Function&&>(function),
+ &detail::default_spawn_handler), attributes)));
+}
+
+template <typename Executor, typename Function>
+void spawn(basic_yield_context<Executor> ctx, Function&& function,
+ const boost::coroutines::attributes& attributes)
+{
+ (dispatch)(ctx.get_executor(),
+ detail::spawned_thread_resumer(
+ detail::spawned_coroutine_thread::spawn(
+ detail::old_spawn_entry_point<Executor,
+ decay_t<Function>, void (*)()>(
+ ctx.get_executor(), static_cast<Function&&>(function),
+ &detail::default_spawn_handler), attributes)));
}
template <typename Function, typename Executor>
-inline void spawn(const Executor& ex,
- ASIO_MOVE_ARG(Function) function,
+inline void spawn(const Executor& ex, Function&& function,
const boost::coroutines::attributes& attributes,
- typename enable_if<is_executor<Executor>::value>::type*)
+ constraint_t<
+ is_executor<Executor>::value || execution::is_executor<Executor>::value
+ >)
{
asio::spawn(asio::strand<Executor>(ex),
- ASIO_MOVE_CAST(Function)(function), attributes);
+ static_cast<Function&&>(function), attributes);
}
template <typename Function, typename Executor>
-inline void spawn(const strand<Executor>& ex,
- ASIO_MOVE_ARG(Function) function,
+inline void spawn(const strand<Executor>& ex, Function&& function,
const boost::coroutines::attributes& attributes)
{
asio::spawn(asio::bind_executor(
ex, &detail::default_spawn_handler),
- ASIO_MOVE_CAST(Function)(function), attributes);
+ static_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,
+inline void spawn(const asio::io_context::strand& s, Function&& function,
const boost::coroutines::attributes& attributes)
{
asio::spawn(asio::bind_executor(
s, &detail::default_spawn_handler),
- ASIO_MOVE_CAST(Function)(function), attributes);
+ static_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,
+inline void spawn(ExecutionContext& ctx, Function&& function,
const boost::coroutines::attributes& attributes,
- typename enable_if<is_convertible<
- ExecutionContext&, execution_context&>::value>::type*)
+ constraint_t<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >)
{
asio::spawn(ctx.get_executor(),
- ASIO_MOVE_CAST(Function)(function), attributes);
+ static_cast<Function&&>(function), attributes);
}
-#endif // !defined(GENERATING_DOCUMENTATION)
+#endif // defined(ASIO_HAS_BOOST_COROUTINE)
} // namespace asio