diff options
Diffstat (limited to '3rdparty/asio/include/asio/detail/handler_work.hpp')
-rw-r--r-- | 3rdparty/asio/include/asio/detail/handler_work.hpp | 500 |
1 files changed, 465 insertions, 35 deletions
diff --git a/3rdparty/asio/include/asio/detail/handler_work.hpp b/3rdparty/asio/include/asio/detail/handler_work.hpp index 327c552434b..c564eb944c3 100644 --- a/3rdparty/asio/include/asio/detail/handler_work.hpp +++ b/3rdparty/asio/include/asio/detail/handler_work.hpp @@ -2,7 +2,7 @@ // detail/handler_work.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2021 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) @@ -18,73 +18,503 @@ #include "asio/detail/config.hpp" #include "asio/associated_executor.hpp" #include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/execution/allocator.hpp" +#include "asio/execution/blocking.hpp" +#include "asio/execution/execute.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/outstanding_work.hpp" +#include "asio/executor_work_guard.hpp" +#include "asio/prefer.hpp" #include "asio/detail/push_options.hpp" namespace asio { + +class executor; +class io_context; + +#if !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +class any_io_executor; + +#endif // !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +namespace execution { + +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template <typename...> class any_executor; + +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + +template <typename, typename, typename, typename, typename, + typename, typename, typename, typename> class any_executor; + +#endif // defined(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 Executor - = typename associated_executor<Handler>::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) ASIO_NOEXCEPT - : executor_(associated_executor<Handler>::get(handler)) + explicit handler_work_base(int, int, const Executor& ex) ASIO_NOEXCEPT + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) { } - static void start(Handler& handler) ASIO_NOEXCEPT + template <typename OtherExecutor> + handler_work_base(bool /*base1_owns_work*/, const Executor& ex, + const OtherExecutor& /*candidate*/) ASIO_NOEXCEPT + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) { - Executor ex(associated_executor<Handler>::get(handler)); - ex.on_work_started(); } - ~handler_work() + handler_work_base(const handler_work_base& other) ASIO_NOEXCEPT + : executor_(other.executor_) { - executor_.on_work_finished(); } - template <typename Function> - void complete(Function& function, Handler& handler) +#if defined(ASIO_HAS_MOVE) + handler_work_base(handler_work_base&& other) ASIO_NOEXCEPT + : executor_(ASIO_MOVE_CAST(executor_type)(other.executor_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + bool owns_work() const ASIO_NOEXCEPT + { + return true; + } + + template <typename Function, typename Handler> + void dispatch(Function& function, Handler& handler) + { + execution::execute( + asio::prefer(executor_, + execution::blocking.possibly, + execution::allocator((get_associated_allocator)(handler))), + 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(int, int, const Executor& ex) ASIO_NOEXCEPT + : executor_(ex), + owns_work_(true) + { + executor_.on_work_started(); + } + + handler_work_base(bool /*base1_owns_work*/, const Executor& ex, + const Executor& candidate) ASIO_NOEXCEPT + : executor_(ex), + owns_work_(ex != candidate) + { + if (owns_work_) + executor_.on_work_started(); + } + + template <typename OtherExecutor> + handler_work_base(bool /*base1_owns_work*/, const Executor& ex, + const OtherExecutor& /*candidate*/) ASIO_NOEXCEPT + : executor_(ex), + owns_work_(true) + { + executor_.on_work_started(); + } + + handler_work_base(const handler_work_base& other) ASIO_NOEXCEPT + : executor_(other.executor_), + owns_work_(other.owns_work_) + { + if (owns_work_) + executor_.on_work_started(); + } + +#if defined(ASIO_HAS_MOVE) + handler_work_base(handler_work_base&& other) ASIO_NOEXCEPT + : executor_(ASIO_MOVE_CAST(Executor)(other.executor_)), + owns_work_(other.owns_work_) + { + other.owns_work_ = false; + } +#endif // defined(ASIO_HAS_MOVE) + + ~handler_work_base() + { + if (owns_work_) + executor_.on_work_finished(); + } + + bool owns_work() const ASIO_NOEXCEPT + { + return owns_work_; + } + + template <typename Function, typename Handler> + void dispatch(Function& function, Handler& handler) { executor_.dispatch(ASIO_MOVE_CAST(Function)(function), - associated_allocator<Handler>::get(handler)); + asio::get_associated_allocator(handler)); } private: - // Disallow copying and assignment. - handler_work(const handler_work&); - handler_work& operator=(const handler_work&); + Executor executor_; + bool owns_work_; +}; - typename associated_executor<Handler>::type executor_; +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(int, int, const Executor&) + { + } + + bool owns_work() const 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. + asio_handler_invoke_helpers::invoke(function, handler); + } }; -// 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> +template <typename Executor, typename IoContext> +class handler_work_base<Executor, void, IoContext, Executor> { public: - explicit handler_work(Handler&) ASIO_NOEXCEPT {} - static void start(Handler&) ASIO_NOEXCEPT {} - ~handler_work() {} + explicit handler_work_base(int, int, const Executor& ex) ASIO_NOEXCEPT +#if !defined(ASIO_NO_TYPEID) + : executor_( + ex.target_type() == typeid(typename IoContext::executor_type) + ? Executor() : ex) +#else // !defined(ASIO_NO_TYPEID) + : executor_(ex) +#endif // !defined(ASIO_NO_TYPEID) + { + if (executor_) + executor_.on_work_started(); + } + + handler_work_base(bool /*base1_owns_work*/, const Executor& ex, + const Executor& candidate) ASIO_NOEXCEPT + : executor_(ex != candidate ? ex : Executor()) + { + if (executor_) + executor_.on_work_started(); + } + + template <typename OtherExecutor> + handler_work_base(const Executor& ex, + const OtherExecutor&) ASIO_NOEXCEPT + : executor_(ex) + { + executor_.on_work_started(); + } + + handler_work_base(const handler_work_base& other) ASIO_NOEXCEPT + : executor_(other.executor_) + { + if (executor_) + executor_.on_work_started(); + } + +#if defined(ASIO_HAS_MOVE) + handler_work_base(handler_work_base&& other) ASIO_NOEXCEPT + : executor_(ASIO_MOVE_CAST(Executor)(other.executor_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + ~handler_work_base() + { + if (executor_) + executor_.on_work_finished(); + } + + bool owns_work() const ASIO_NOEXCEPT + { + return !!executor_; + } + + template <typename Function, typename Handler> + void dispatch(Function& function, Handler& handler) + { + executor_.dispatch(ASIO_MOVE_CAST(Function)(function), + asio::get_associated_allocator(handler)); + } + +private: + Executor executor_; +}; + +template < +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + typename... SupportableProperties, +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + typename T1, typename T2, typename T3, typename T4, typename T5, + typename T6, typename T7, typename T8, typename T9, +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) + typename CandidateExecutor, typename IoContext, + typename PolymorphicExecutor> +class handler_work_base< +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + execution::any_executor<SupportableProperties...>, +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + execution::any_executor<T1, T2, T3, T4, T5, T6, T7, T8, T9>, +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) + CandidateExecutor, IoContext, PolymorphicExecutor> +{ +public: + typedef +#if defined(ASIO_HAS_VARIADIC_TEMPLATES) + execution::any_executor<SupportableProperties...> +#else // defined(ASIO_HAS_VARIADIC_TEMPLATES) + execution::any_executor<T1, T2, T3, T4, T5, T6, T7, T8, T9> +#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES) + executor_type; + + explicit handler_work_base(int, int, + const executor_type& ex) ASIO_NOEXCEPT +#if !defined(ASIO_NO_TYPEID) + : executor_( + ex.target_type() == typeid(typename IoContext::executor_type) + ? executor_type() + : asio::prefer(ex, execution::outstanding_work.tracked)) +#else // !defined(ASIO_NO_TYPEID) + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) +#endif // !defined(ASIO_NO_TYPEID) + { + } + + handler_work_base(bool base1_owns_work, const executor_type& ex, + const executor_type& candidate) ASIO_NOEXCEPT + : executor_( + !base1_owns_work && ex == candidate + ? executor_type() + : asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + template <typename OtherExecutor> + handler_work_base(bool /*base1_owns_work*/, const executor_type& ex, + const OtherExecutor& /*candidate*/) ASIO_NOEXCEPT + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + handler_work_base(const handler_work_base& other) ASIO_NOEXCEPT + : executor_(other.executor_) + { + } + +#if defined(ASIO_HAS_MOVE) + handler_work_base(handler_work_base&& other) ASIO_NOEXCEPT + : executor_(ASIO_MOVE_CAST(executor_type)(other.executor_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + bool owns_work() const ASIO_NOEXCEPT + { + return !!executor_; + } + + template <typename Function, typename Handler> + void dispatch(Function& function, Handler&) + { + execution::execute( + asio::prefer(executor_, execution::blocking.possibly), + ASIO_MOVE_CAST(Function)(function)); + } + +private: + executor_type executor_; +}; + +#if !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +template <typename Executor, typename CandidateExecutor, + typename IoContext, typename PolymorphicExecutor> +class handler_work_base< + Executor, CandidateExecutor, + IoContext, PolymorphicExecutor, + typename enable_if< + is_same< + Executor, + any_io_executor + >::value + >::type> +{ +public: + typedef Executor executor_type; + + explicit handler_work_base(int, int, + const executor_type& ex) ASIO_NOEXCEPT +#if !defined(ASIO_NO_TYPEID) + : executor_( + ex.target_type() == typeid(typename IoContext::executor_type) + ? executor_type() + : asio::prefer(ex, execution::outstanding_work.tracked)) +#else // !defined(ASIO_NO_TYPEID) + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) +#endif // !defined(ASIO_NO_TYPEID) + { + } + + handler_work_base(bool base1_owns_work, const executor_type& ex, + const executor_type& candidate) ASIO_NOEXCEPT + : executor_( + !base1_owns_work && ex == candidate + ? executor_type() + : asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + template <typename OtherExecutor> + handler_work_base(bool /*base1_owns_work*/, const executor_type& ex, + const OtherExecutor& /*candidate*/) ASIO_NOEXCEPT + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + handler_work_base(const handler_work_base& other) ASIO_NOEXCEPT + : executor_(other.executor_) + { + } + +#if defined(ASIO_HAS_MOVE) + handler_work_base(handler_work_base&& other) ASIO_NOEXCEPT + : executor_(ASIO_MOVE_CAST(executor_type)(other.executor_)) + { + } +#endif // defined(ASIO_HAS_MOVE) + + bool owns_work() const ASIO_NOEXCEPT + { + return !!executor_; + } + + template <typename Function, typename Handler> + void dispatch(Function& function, Handler&) + { + execution::execute( + asio::prefer(executor_, execution::blocking.possibly), + ASIO_MOVE_CAST(Function)(function)); + } + +private: + executor_type executor_; +}; + +#endif // !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +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: + 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) ASIO_NOEXCEPT + : base1_type(0, 0, io_ex), + base2_type(base1_type::owns_work(), + asio::get_associated_executor(handler, io_ex), io_ex) + { + } template <typename Function> void complete(Function& function, Handler& handler) { - 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. + 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) ASIO_NOEXCEPT + : base1_type(0, 0, 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. + asio_handler_invoke_helpers::invoke(function, handler); + } + else + { + base1_type::dispatch(function, handler); + } + } }; } // namespace detail |