// // impl/executor.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 ASIO_IMPL_EXECUTOR_HPP #define ASIO_IMPL_EXECUTOR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #if !defined(ASIO_NO_TS_EXECUTORS) #include #include "asio/detail/atomic_count.hpp" #include "asio/detail/global.hpp" #include "asio/detail/memory.hpp" #include "asio/executor.hpp" #include "asio/system_executor.hpp" #include "asio/detail/push_options.hpp" namespace asio { #if !defined(GENERATING_DOCUMENTATION) // Default polymorphic executor implementation. template class executor::impl : public executor::impl_base { public: typedef ASIO_REBIND_ALLOC(Allocator, impl) allocator_type; static impl_base* create(const Executor& e, Allocator a = Allocator()) { raw_mem mem(a); impl* p = new (mem.ptr_) impl(e, a); mem.ptr_ = 0; return p; } static impl_base* create(std::nothrow_t, const Executor& e) noexcept { return new (std::nothrow) impl(e, std::allocator()); } impl(const Executor& e, const Allocator& a) noexcept : impl_base(false), ref_count_(1), executor_(e), allocator_(a) { } impl_base* clone() const noexcept { detail::ref_count_up(ref_count_); return const_cast(static_cast(this)); } void destroy() noexcept { if (detail::ref_count_down(ref_count_)) { allocator_type alloc(allocator_); impl* p = this; p->~impl(); alloc.deallocate(p, 1); } } void on_work_started() noexcept { executor_.on_work_started(); } void on_work_finished() noexcept { executor_.on_work_finished(); } execution_context& context() noexcept { return executor_.context(); } void dispatch(function&& f) { executor_.dispatch(static_cast(f), allocator_); } void post(function&& f) { executor_.post(static_cast(f), allocator_); } void defer(function&& f) { executor_.defer(static_cast(f), allocator_); } type_id_result_type target_type() const noexcept { return type_id(); } void* target() noexcept { return &executor_; } const void* target() const noexcept { return &executor_; } bool equals(const impl_base* e) const noexcept { if (this == e) return true; if (target_type() != e->target_type()) return false; return executor_ == *static_cast(e->target()); } private: mutable detail::atomic_count ref_count_; Executor executor_; Allocator allocator_; struct raw_mem { allocator_type allocator_; impl* ptr_; explicit raw_mem(const Allocator& a) : allocator_(a), ptr_(allocator_.allocate(1)) { } ~raw_mem() { if (ptr_) allocator_.deallocate(ptr_, 1); } private: // Disallow copying and assignment. raw_mem(const raw_mem&); raw_mem operator=(const raw_mem&); }; }; // Polymorphic executor specialisation for system_executor. template class executor::impl : public executor::impl_base { public: static impl_base* create(const system_executor&, const Allocator& = Allocator()) { return &detail::global> >(); } static impl_base* create(std::nothrow_t, const system_executor&) noexcept { return &detail::global> >(); } impl() : impl_base(true) { } impl_base* clone() const noexcept { return const_cast(static_cast(this)); } void destroy() noexcept { } void on_work_started() noexcept { executor_.on_work_started(); } void on_work_finished() noexcept { executor_.on_work_finished(); } execution_context& context() noexcept { return executor_.context(); } void dispatch(function&& f) { executor_.dispatch(static_cast(f), std::allocator()); } void post(function&& f) { executor_.post(static_cast(f), std::allocator()); } void defer(function&& f) { executor_.defer(static_cast(f), std::allocator()); } type_id_result_type target_type() const noexcept { return type_id(); } void* target() noexcept { return &executor_; } const void* target() const noexcept { return &executor_; } bool equals(const impl_base* e) const noexcept { return this == e; } private: system_executor executor_; }; template executor::executor(Executor e) : impl_(impl>::create(e)) { } template executor::executor(std::nothrow_t, Executor e) noexcept : impl_(impl>::create(std::nothrow, e)) { } template executor::executor(allocator_arg_t, const Allocator& a, Executor e) : impl_(impl::create(e, a)) { } template void executor::dispatch(Function&& f, const Allocator& a) const { impl_base* i = get_impl(); if (i->fast_dispatch_) system_executor().dispatch(static_cast(f), a); else i->dispatch(function(static_cast(f), a)); } template void executor::post(Function&& f, const Allocator& a) const { get_impl()->post(function(static_cast(f), a)); } template void executor::defer(Function&& f, const Allocator& a) const { get_impl()->defer(function(static_cast(f), a)); } template Executor* executor::target() noexcept { return impl_ && impl_->target_type() == type_id() ? static_cast(impl_->target()) : 0; } template const Executor* executor::target() const noexcept { return impl_ && impl_->target_type() == type_id() ? static_cast(impl_->target()) : 0; } #endif // !defined(GENERATING_DOCUMENTATION) } // namespace asio #include "asio/detail/pop_options.hpp" #endif // !defined(ASIO_NO_TS_EXECUTORS) #endif // ASIO_IMPL_EXECUTOR_HPP