#include <boost/asio/detail/config.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/type_traits.hpp>
+#include <boost/asio/execution/allocator.hpp>
+#include <boost/asio/execution/blocking.hpp>
+#include <boost/asio/execution/execute.hpp>
+#include <boost/asio/execution/executor.hpp>
+#include <boost/asio/execution/outstanding_work.hpp>
+#include <boost/asio/executor_work_guard.hpp>
+#include <boost/asio/prefer.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
+
+class executor;
+class io_context;
+
+namespace execution {
+
+#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename...> class any_executor;
+
+#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
+
+template <typename, typename, typename, typename, typename,
+ typename, typename, typename, typename> class any_executor;
+
+#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
+
+} // namespace execution
namespace detail {
-// A helper class template to allow completion handlers to be dispatched
-// through either the new executors framework or the old invocaton hook. The
-// primary template uses the new executors framework.
-template <typename Handler,
- typename IoExecutor = system_executor, typename HandlerExecutor
- = typename associated_executor<Handler, IoExecutor>::type>
-class handler_work
+template <typename Executor, typename CandidateExecutor = void,
+ typename IoContext = io_context,
+ typename PolymorphicExecutor = executor, typename = void>
+class handler_work_base
{
public:
- explicit handler_work(Handler& handler) BOOST_ASIO_NOEXCEPT
- : io_executor_(),
- executor_(boost::asio::get_associated_executor(handler, io_executor_))
+ explicit handler_work_base(const Executor& ex) BOOST_ASIO_NOEXCEPT
+ : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
{
}
- handler_work(Handler& handler, const IoExecutor& io_ex) BOOST_ASIO_NOEXCEPT
- : io_executor_(io_ex),
- executor_(boost::asio::get_associated_executor(handler, io_executor_))
+ template <typename OtherExecutor>
+ handler_work_base(const Executor& ex,
+ const OtherExecutor&) BOOST_ASIO_NOEXCEPT
+ : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
{
}
- static void start(Handler& handler) BOOST_ASIO_NOEXCEPT
+ handler_work_base(const handler_work_base& other) BOOST_ASIO_NOEXCEPT
+ : executor_(other.executor_)
{
- HandlerExecutor ex(boost::asio::get_associated_executor(handler));
- ex.on_work_started();
}
- static void start(Handler& handler,
- const IoExecutor& io_ex) BOOST_ASIO_NOEXCEPT
+#if defined(BOOST_ASIO_HAS_MOVE)
+ handler_work_base(handler_work_base&& other) BOOST_ASIO_NOEXCEPT
+ : executor_(BOOST_ASIO_MOVE_CAST(executor_type)(other.executor_))
{
- HandlerExecutor ex(boost::asio::get_associated_executor(handler, io_ex));
- ex.on_work_started();
- io_ex.on_work_started();
}
+#endif // defined(BOOST_ASIO_HAS_MOVE)
- ~handler_work()
+ bool owns_work() const BOOST_ASIO_NOEXCEPT
{
- io_executor_.on_work_finished();
- executor_.on_work_finished();
+ return true;
}
- template <typename Function>
- void complete(Function& function, Handler& handler)
+ template <typename Function, typename Handler>
+ void dispatch(Function& function, Handler& handler)
+ {
+ execution::execute(
+ boost::asio::prefer(executor_,
+ execution::blocking.possibly,
+ execution::allocator((get_associated_allocator)(handler))),
+ BOOST_ASIO_MOVE_CAST(Function)(function));
+ }
+
+private:
+ typedef typename decay<
+ typename prefer_result<Executor,
+ execution::outstanding_work_t::tracked_t
+ >::type
+ >::type executor_type;
+
+ executor_type executor_;
+};
+
+template <typename Executor, typename CandidateExecutor,
+ typename IoContext, typename PolymorphicExecutor>
+class handler_work_base<Executor, CandidateExecutor,
+ IoContext, PolymorphicExecutor,
+ typename enable_if<
+ !execution::is_executor<Executor>::value
+ && (!is_same<Executor, PolymorphicExecutor>::value
+ || !is_same<CandidateExecutor, void>::value)
+ >::type>
+{
+public:
+ explicit handler_work_base(const Executor& ex) BOOST_ASIO_NOEXCEPT
+ : executor_(ex),
+ owns_work_(true)
+ {
+ executor_.on_work_started();
+ }
+
+ handler_work_base(const Executor& ex,
+ const Executor& candidate) BOOST_ASIO_NOEXCEPT
+ : executor_(ex),
+ owns_work_(ex != candidate)
+ {
+ if (owns_work_)
+ executor_.on_work_started();
+ }
+
+ template <typename OtherExecutor>
+ handler_work_base(const Executor& ex,
+ const OtherExecutor&) BOOST_ASIO_NOEXCEPT
+ : executor_(ex),
+ owns_work_(true)
+ {
+ executor_.on_work_started();
+ }
+
+ handler_work_base(const handler_work_base& other) BOOST_ASIO_NOEXCEPT
+ : executor_(other.executor_),
+ owns_work_(other.owns_work_)
+ {
+ if (owns_work_)
+ executor_.on_work_started();
+ }
+
+#if defined(BOOST_ASIO_HAS_MOVE)
+ handler_work_base(handler_work_base&& other) BOOST_ASIO_NOEXCEPT
+ : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)),
+ owns_work_(other.owns_work_)
+ {
+ other.owns_work_ = false;
+ }
+#endif // defined(BOOST_ASIO_HAS_MOVE)
+
+ ~handler_work_base()
+ {
+ if (owns_work_)
+ executor_.on_work_finished();
+ }
+
+ bool owns_work() const BOOST_ASIO_NOEXCEPT
+ {
+ return owns_work_;
+ }
+
+ template <typename Function, typename Handler>
+ void dispatch(Function& function, Handler& handler)
+ {
+ executor_.dispatch(BOOST_ASIO_MOVE_CAST(Function)(function),
+ boost::asio::get_associated_allocator(handler));
+ }
+
+private:
+ Executor executor_;
+ bool owns_work_;
+};
+
+template <typename Executor, typename IoContext, typename PolymorphicExecutor>
+class handler_work_base<Executor, void, IoContext, PolymorphicExecutor,
+ typename enable_if<
+ is_same<
+ Executor,
+ typename IoContext::executor_type
+ >::value
+ >::type>
+{
+public:
+ explicit handler_work_base(const Executor&)
+ {
+ }
+
+ bool owns_work() const BOOST_ASIO_NOEXCEPT
+ {
+ return false;
+ }
+
+ template <typename Function, typename Handler>
+ void dispatch(Function& function, Handler& handler)
+ {
+ // When using a native implementation, I/O completion handlers are
+ // already dispatched according to the execution context's executor's
+ // rules. We can call the function directly.
+ boost_asio_handler_invoke_helpers::invoke(function, handler);
+ }
+};
+
+template <typename Executor, typename IoContext>
+class handler_work_base<Executor, void, IoContext, Executor>
+{
+public:
+ explicit handler_work_base(const Executor& ex) BOOST_ASIO_NOEXCEPT
+#if !defined(BOOST_ASIO_NO_TYPEID)
+ : executor_(
+ ex.target_type() == typeid(typename IoContext::executor_type)
+ ? Executor() : ex)
+#else // !defined(BOOST_ASIO_NO_TYPEID)
+ : executor_(ex)
+#endif // !defined(BOOST_ASIO_NO_TYPEID)
+ {
+ if (executor_)
+ executor_.on_work_started();
+ }
+
+ handler_work_base(const Executor& ex,
+ const Executor& candidate) BOOST_ASIO_NOEXCEPT
+ : executor_(ex != candidate ? ex : Executor())
+ {
+ if (executor_)
+ executor_.on_work_started();
+ }
+
+ template <typename OtherExecutor>
+ handler_work_base(const Executor& ex,
+ const OtherExecutor&) BOOST_ASIO_NOEXCEPT
+ : executor_(ex)
+ {
+ executor_.on_work_started();
+ }
+
+ handler_work_base(const handler_work_base& other) BOOST_ASIO_NOEXCEPT
+ : executor_(other.executor_)
+ {
+ if (executor_)
+ executor_.on_work_started();
+ }
+
+#if defined(BOOST_ASIO_HAS_MOVE)
+ handler_work_base(handler_work_base&& other) BOOST_ASIO_NOEXCEPT
+ : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_))
+ {
+ }
+#endif // defined(BOOST_ASIO_HAS_MOVE)
+
+ ~handler_work_base()
+ {
+ if (executor_)
+ executor_.on_work_finished();
+ }
+
+ bool owns_work() const BOOST_ASIO_NOEXCEPT
+ {
+ return !!executor_;
+ }
+
+ template <typename Function, typename Handler>
+ void dispatch(Function& function, Handler& handler)
{
executor_.dispatch(BOOST_ASIO_MOVE_CAST(Function)(function),
boost::asio::get_associated_allocator(handler));
}
private:
- // Disallow copying and assignment.
- handler_work(const handler_work&);
- handler_work& operator=(const handler_work&);
+ Executor executor_;
+};
+
+template <
+#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
+ typename... SupportableProperties,
+#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
+ typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9,
+#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
+ typename IoContext, typename PolymorphicExecutor>
+class handler_work_base<
+#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
+ execution::any_executor<SupportableProperties...>,
+#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
+ execution::any_executor<T1, T2, T3, T4, T5, T6, T7, T8, T9>,
+#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
+ void, IoContext, PolymorphicExecutor>
+{
+public:
+ typedef
+#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
+ execution::any_executor<SupportableProperties...>
+#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
+ execution::any_executor<T1, T2, T3, T4, T5, T6, T7, T8, T9>
+#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
+ executor_type;
+
+ explicit handler_work_base(const executor_type& ex) BOOST_ASIO_NOEXCEPT
+#if !defined(BOOST_ASIO_NO_TYPEID)
+ : executor_(
+ ex.target_type() == typeid(typename IoContext::executor_type)
+ ? executor_type()
+ : boost::asio::prefer(ex, execution::outstanding_work.tracked))
+#else // !defined(BOOST_ASIO_NO_TYPEID)
+ : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
+#endif // !defined(BOOST_ASIO_NO_TYPEID)
+ {
+ }
+
+ handler_work_base(const executor_type& ex,
+ const executor_type& candidate) BOOST_ASIO_NOEXCEPT
+ : executor_(ex != candidate ? ex : executor_type())
+ {
+ }
+
+ template <typename OtherExecutor>
+ handler_work_base(const executor_type& ex,
+ const OtherExecutor&) BOOST_ASIO_NOEXCEPT
+ : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
+ {
+ }
+
+ handler_work_base(const handler_work_base& other) BOOST_ASIO_NOEXCEPT
+ : executor_(other.executor_)
+ {
+ }
+
+#if defined(BOOST_ASIO_HAS_MOVE)
+ handler_work_base(handler_work_base&& other) BOOST_ASIO_NOEXCEPT
+ : executor_(BOOST_ASIO_MOVE_CAST(executor_type)(other.executor_))
+ {
+ }
+#endif // defined(BOOST_ASIO_HAS_MOVE)
- IoExecutor io_executor_;
- HandlerExecutor executor_;
+ bool owns_work() const BOOST_ASIO_NOEXCEPT
+ {
+ return !!executor_;
+ }
+
+ template <typename Function, typename Handler>
+ void dispatch(Function& function, Handler& handler)
+ {
+ execution::execute(
+ boost::asio::prefer(executor_,
+ execution::blocking.possibly,
+ execution::allocator((get_associated_allocator)(handler))),
+ BOOST_ASIO_MOVE_CAST(Function)(function));
+ }
+
+private:
+ executor_type executor_;
};
-// This specialisation dispatches a handler through the old invocation hook.
-// The specialisation is not strictly required for correctness, as the
-// system_executor will dispatch through the hook anyway. However, by doing
-// this we avoid an extra copy of the handler.
-template <typename Handler>
-class handler_work<Handler, system_executor, system_executor>
+template <typename Handler, typename IoExecutor, typename = void>
+class handler_work :
+ handler_work_base<IoExecutor>,
+ handler_work_base<typename associated_executor<
+ Handler, IoExecutor>::type, IoExecutor>
{
public:
- explicit handler_work(Handler&) BOOST_ASIO_NOEXCEPT {}
- static void start(Handler&) BOOST_ASIO_NOEXCEPT {}
- ~handler_work() {}
+ typedef handler_work_base<IoExecutor> base1_type;
+ typedef handler_work_base<typename associated_executor<
+ Handler, IoExecutor>::type, IoExecutor> base2_type;
+
+ handler_work(Handler& handler, const IoExecutor& io_ex) BOOST_ASIO_NOEXCEPT
+ : base1_type(io_ex),
+ base2_type(boost::asio::get_associated_executor(handler, io_ex), io_ex)
+ {
+ }
template <typename Function>
void complete(Function& function, Handler& handler)
{
- boost_asio_handler_invoke_helpers::invoke(function, handler);
+ if (!base1_type::owns_work() && !base2_type::owns_work())
+ {
+ // When using a native implementation, I/O completion handlers are
+ // already dispatched according to the execution context's executor's
+ // rules. We can call the function directly.
+ boost_asio_handler_invoke_helpers::invoke(function, handler);
+ }
+ else
+ {
+ base2_type::dispatch(function, handler);
+ }
}
+};
-private:
- // Disallow copying and assignment.
- handler_work(const handler_work&);
- handler_work& operator=(const handler_work&);
+template <typename Handler, typename IoExecutor>
+class handler_work<
+ Handler, IoExecutor,
+ typename enable_if<
+ is_same<
+ typename associated_executor<Handler,
+ IoExecutor>::asio_associated_executor_is_unspecialised,
+ void
+ >::value
+ >::type> : handler_work_base<IoExecutor>
+{
+public:
+ typedef handler_work_base<IoExecutor> base1_type;
+
+ handler_work(Handler&, const IoExecutor& io_ex) BOOST_ASIO_NOEXCEPT
+ : base1_type(io_ex)
+ {
+ }
+
+ template <typename Function>
+ void complete(Function& function, Handler& handler)
+ {
+ if (!base1_type::owns_work())
+ {
+ // When using a native implementation, I/O completion handlers are
+ // already dispatched according to the execution context's executor's
+ // rules. We can call the function directly.
+ boost_asio_handler_invoke_helpers::invoke(function, handler);
+ }
+ else
+ {
+ base1_type::dispatch(function, handler);
+ }
+ }
};
} // namespace detail