// // detail/handler_work.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // 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) // #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 #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace asio { class executor; class io_context; #if !defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) class any_completion_executor; class any_io_executor; #endif // !defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) namespace execution { template class any_executor; } // namespace execution namespace detail { template class handler_work_base { public: explicit handler_work_base(int, int, const Executor& ex) noexcept : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked)) { } template handler_work_base(bool /*base1_owns_work*/, const Executor& ex, const OtherExecutor& /*candidate*/) noexcept : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked)) { } handler_work_base(const handler_work_base& other) noexcept : executor_(other.executor_) { } handler_work_base(handler_work_base&& other) noexcept : executor_(static_cast(other.executor_)) { } bool owns_work() const noexcept { return true; } template void dispatch(Function& function, Handler& handler) { boost::asio::prefer(executor_, execution::allocator((get_associated_allocator)(handler)) ).execute(static_cast(function)); } private: typedef decay_t< prefer_result_t > executor_type; executor_type executor_; }; template class handler_work_base::value && (!is_same::value || !is_same::value) > > { public: explicit handler_work_base(int, int, const Executor& ex) noexcept : executor_(ex), owns_work_(true) { executor_.on_work_started(); } handler_work_base(bool /*base1_owns_work*/, const Executor& ex, const Executor& candidate) noexcept : executor_(ex), owns_work_(ex != candidate) { if (owns_work_) executor_.on_work_started(); } template handler_work_base(bool /*base1_owns_work*/, const Executor& ex, const OtherExecutor& /*candidate*/) noexcept : executor_(ex), owns_work_(true) { executor_.on_work_started(); } handler_work_base(const handler_work_base& other) noexcept : executor_(other.executor_), owns_work_(other.owns_work_) { if (owns_work_) executor_.on_work_started(); } handler_work_base(handler_work_base&& other) noexcept : executor_(static_cast(other.executor_)), owns_work_(other.owns_work_) { other.owns_work_ = false; } ~handler_work_base() { if (owns_work_) executor_.on_work_finished(); } bool owns_work() const noexcept { return owns_work_; } template void dispatch(Function& function, Handler& handler) { executor_.dispatch(static_cast(function), boost::asio::get_associated_allocator(handler)); } private: Executor executor_; bool owns_work_; }; template class handler_work_base::value > > { public: explicit handler_work_base(int, int, const Executor&) { } bool owns_work() const noexcept { return false; } template void dispatch(Function& function, 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. static_cast(function)(); } }; template class handler_work_base { public: explicit handler_work_base(int, int, const Executor& ex) 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(bool /*base1_owns_work*/, const Executor& ex, const Executor& candidate) noexcept : executor_(ex != candidate ? ex : Executor()) { if (executor_) executor_.on_work_started(); } template handler_work_base(const Executor& ex, const OtherExecutor&) noexcept : executor_(ex) { executor_.on_work_started(); } handler_work_base(const handler_work_base& other) noexcept : executor_(other.executor_) { if (executor_) executor_.on_work_started(); } handler_work_base(handler_work_base&& other) noexcept : executor_(static_cast(other.executor_)) { } ~handler_work_base() { if (executor_) executor_.on_work_finished(); } bool owns_work() const noexcept { return !!executor_; } template void dispatch(Function& function, Handler& handler) { executor_.dispatch(static_cast(function), boost::asio::get_associated_allocator(handler)); } private: Executor executor_; }; template class handler_work_base, CandidateExecutor, IoContext, PolymorphicExecutor> { public: typedef execution::any_executor executor_type; explicit handler_work_base(int, int, const executor_type& ex) 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(bool base1_owns_work, const executor_type& ex, const executor_type& candidate) noexcept : executor_( !base1_owns_work && ex == candidate ? executor_type() : boost::asio::prefer(ex, execution::outstanding_work.tracked)) { } template handler_work_base(bool /*base1_owns_work*/, const executor_type& ex, const OtherExecutor& /*candidate*/) noexcept : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked)) { } handler_work_base(const handler_work_base& other) noexcept : executor_(other.executor_) { } handler_work_base(handler_work_base&& other) noexcept : executor_(static_cast(other.executor_)) { } bool owns_work() const noexcept { return !!executor_; } template void dispatch(Function& function, Handler&) { executor_.execute(static_cast(function)); } private: executor_type executor_; }; #if !defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) template class handler_work_base< Executor, CandidateExecutor, IoContext, PolymorphicExecutor, enable_if_t< is_same::value || is_same::value > > { public: typedef Executor executor_type; explicit handler_work_base(int, int, const executor_type& ex) 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(bool base1_owns_work, const executor_type& ex, const executor_type& candidate) noexcept : executor_( !base1_owns_work && ex == candidate ? executor_type() : boost::asio::prefer(ex, execution::outstanding_work.tracked)) { } template handler_work_base(bool /*base1_owns_work*/, const executor_type& ex, const OtherExecutor& /*candidate*/) noexcept : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked)) { } handler_work_base(const handler_work_base& other) noexcept : executor_(other.executor_) { } handler_work_base(handler_work_base&& other) noexcept : executor_(static_cast(other.executor_)) { } bool owns_work() const noexcept { return !!executor_; } template void dispatch(Function& function, Handler&) { executor_.execute(static_cast(function)); } private: executor_type executor_; }; #endif // !defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) template class handler_work : handler_work_base, handler_work_base, IoExecutor> { public: typedef handler_work_base base1_type; typedef handler_work_base, IoExecutor> base2_type; handler_work(Handler& handler, const IoExecutor& io_ex) noexcept : base1_type(0, 0, io_ex), base2_type(base1_type::owns_work(), boost::asio::get_associated_executor(handler, io_ex), io_ex) { } template 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. static_cast(function)(); } else { base2_type::dispatch(function, handler); } } }; template class handler_work< Handler, IoExecutor, enable_if_t< is_same< typename associated_executor::asio_associated_executor_is_unspecialised, void >::value > > : handler_work_base { public: typedef handler_work_base base1_type; handler_work(Handler&, const IoExecutor& io_ex) noexcept : base1_type(0, 0, io_ex) { } template 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. static_cast(function)(); } else { base1_type::dispatch(function, handler); } } }; template class immediate_handler_work { public: typedef handler_work handler_work_type; explicit immediate_handler_work(handler_work_type&& w) : handler_work_(static_cast(w)) { } template void complete(Function& function, Handler& handler, const void* io_ex) { typedef associated_immediate_executor_t immediate_ex_type; immediate_ex_type immediate_ex = (get_associated_immediate_executor)( handler, *static_cast(io_ex)); (initiate_dispatch_with_executor(immediate_ex))( static_cast(function)); } private: handler_work_type handler_work_; }; } // namespace detail } // namespace asio } // namespace boost #include #endif // BOOST_ASIO_DETAIL_HANDLER_WORK_HPP