| // |
| // detail/handler_work.hpp |
| // ~~~~~~~~~~~~~~~~~~~~~~~ |
| // |
| // 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) |
| // |
| |
| #ifndef BOOST_ASIO_DETAIL_HANDLER_WORK_HPP |
| #define BOOST_ASIO_DETAIL_HANDLER_WORK_HPP |
| |
| #if defined(_MSC_VER) && (_MSC_VER >= 1200) |
| # pragma once |
| #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) |
| |
| #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; |
| |
| #if !defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) |
| |
| class any_io_executor; |
| |
| #endif // !defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) |
| |
| 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 { |
| |
| template <typename Executor, typename CandidateExecutor = void, |
| typename IoContext = io_context, |
| typename PolymorphicExecutor = executor, typename = void> |
| class handler_work_base |
| { |
| public: |
| explicit handler_work_base(int, int, const Executor& ex) BOOST_ASIO_NOEXCEPT |
| : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked)) |
| { |
| } |
| |
| template <typename OtherExecutor> |
| handler_work_base(const Executor& 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) |
| |
| bool owns_work() const BOOST_ASIO_NOEXCEPT |
| { |
| return true; |
| } |
| |
| 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(int, int, 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(int, int, 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(int, int, 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: |
| 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(int, int, |
| 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) |
| |
| bool owns_work() const BOOST_ASIO_NOEXCEPT |
| { |
| return !!executor_; |
| } |
| |
| template <typename Function, typename Handler> |
| void dispatch(Function& function, Handler&) |
| { |
| execution::execute( |
| boost::asio::prefer(executor_, execution::blocking.possibly), |
| BOOST_ASIO_MOVE_CAST(Function)(function)); |
| } |
| |
| private: |
| executor_type executor_; |
| }; |
| |
| #if !defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) |
| |
| template <typename Executor, typename IoContext, typename PolymorphicExecutor> |
| class handler_work_base<Executor, void, 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) 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) |
| |
| bool owns_work() const BOOST_ASIO_NOEXCEPT |
| { |
| return !!executor_; |
| } |
| |
| template <typename Function, typename Handler> |
| void dispatch(Function& function, Handler&) |
| { |
| execution::execute( |
| boost::asio::prefer(executor_, execution::blocking.possibly), |
| BOOST_ASIO_MOVE_CAST(Function)(function)); |
| } |
| |
| private: |
| executor_type executor_; |
| }; |
| |
| #endif // !defined(BOOST_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) BOOST_ASIO_NOEXCEPT |
| : base1_type(0, 0, io_ex), |
| base2_type(boost::asio::get_associated_executor(handler, io_ex), io_ex) |
| { |
| } |
| |
| template <typename Function> |
| void complete(Function& function, Handler& 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); |
| } |
| } |
| }; |
| |
| 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(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. |
| boost_asio_handler_invoke_helpers::invoke(function, handler); |
| } |
| else |
| { |
| base1_type::dispatch(function, handler); |
| } |
| } |
| }; |
| |
| } // namespace detail |
| } // namespace asio |
| } // namespace boost |
| |
| #include <boost/asio/detail/pop_options.hpp> |
| |
| #endif // BOOST_ASIO_DETAIL_HANDLER_WORK_HPP |