// // impl/executor.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2019 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" #include "asio/detail/atomic_count.hpp" #include "asio/detail/executor_function.hpp" #include "asio/detail/global.hpp" #include "asio/detail/memory.hpp" #include "asio/detail/recycling_allocator.hpp" #include "asio/executor.hpp" #include "asio/system_executor.hpp" #include "asio/detail/push_options.hpp" namespace asio { #if !defined(GENERATING_DOCUMENTATION) #if defined(ASIO_HAS_MOVE) // Lightweight, move-only function object wrapper. class executor::function { public: template explicit function(F f, const Alloc& a) { // Allocate and construct an operation to wrap the function. typedef detail::executor_function func_type; typename func_type::ptr p = { detail::addressof(a), func_type::ptr::allocate(a), 0 }; func_ = new (p.v) func_type(ASIO_MOVE_CAST(F)(f), a); p.v = 0; } function(function&& other) ASIO_NOEXCEPT : func_(other.func_) { other.func_ = 0; } ~function() { if (func_) func_->destroy(); } void operator()() { if (func_) { detail::executor_function_base* func = func_; func_ = 0; func->complete(); } } private: detail::executor_function_base* func_; }; #else // defined(ASIO_HAS_MOVE) // Not so lightweight, copyable function object wrapper. class executor::function { public: template explicit function(const F& f, const Alloc&) : impl_(new impl(f)) { } void operator()() { impl_->invoke_(impl_.get()); } private: // Base class for polymorphic function implementations. struct impl_base { void (*invoke_)(impl_base*); }; // Polymorphic function implementation. template struct impl : impl_base { impl(const F& f) : function_(f) { invoke_ = &function::invoke; } F function_; }; // Helper to invoke a function. template static void invoke(impl_base* i) { static_cast*>(i)->function_(); } detail::shared_ptr impl_; }; #endif // defined(ASIO_HAS_MOVE) // Default polymorphic allocator 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; } impl(const Executor& e, const Allocator& a) ASIO_NOEXCEPT : impl_base(false), ref_count_(1), executor_(e), allocator_(a) { } impl_base* clone() const ASIO_NOEXCEPT { ++ref_count_; return const_cast(static_cast(this)); } void destroy() ASIO_NOEXCEPT { if (--ref_count_ == 0) { allocator_type alloc(allocator_); impl* p = this; p->~impl(); alloc.deallocate(p, 1); } } void on_work_started() ASIO_NOEXCEPT { executor_.on_work_started(); } void on_work_finished() ASIO_NOEXCEPT { executor_.on_work_finished(); } execution_context& context() ASIO_NOEXCEPT { return executor_.context(); } void dispatch(ASIO_MOVE_ARG(function) f) { executor_.dispatch(ASIO_MOVE_CAST(function)(f), allocator_); } void post(ASIO_MOVE_ARG(function) f) { executor_.post(ASIO_MOVE_CAST(function)(f), allocator_); } void defer(ASIO_MOVE_ARG(function) f) { executor_.defer(ASIO_MOVE_CAST(function)(f), allocator_); } type_id_result_type target_type() const ASIO_NOEXCEPT { return type_id(); } void* target() ASIO_NOEXCEPT { return &executor_; } const void* target() const ASIO_NOEXCEPT { return &executor_; } bool equals(const impl_base* e) const ASIO_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 allocator 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 > >(); } impl() : impl_base(true) { } impl_base* clone() const ASIO_NOEXCEPT { return const_cast(static_cast(this)); } void destroy() ASIO_NOEXCEPT { } void on_work_started() ASIO_NOEXCEPT { executor_.on_work_started(); } void on_work_finished() ASIO_NOEXCEPT { executor_.on_work_finished(); } execution_context& context() ASIO_NOEXCEPT { return executor_.context(); } void dispatch(ASIO_MOVE_ARG(function) f) { executor_.dispatch(ASIO_MOVE_CAST(function)(f), allocator_); } void post(ASIO_MOVE_ARG(function) f) { executor_.post(ASIO_MOVE_CAST(function)(f), allocator_); } void defer(ASIO_MOVE_ARG(function) f) { executor_.defer(ASIO_MOVE_CAST(function)(f), allocator_); } type_id_result_type target_type() const ASIO_NOEXCEPT { return type_id(); } void* target() ASIO_NOEXCEPT { return &executor_; } const void* target() const ASIO_NOEXCEPT { return &executor_; } bool equals(const impl_base* e) const ASIO_NOEXCEPT { return this == e; } private: system_executor executor_; Allocator allocator_; }; template executor::executor(Executor e) : impl_(impl >::create(e)) { } template executor::executor(allocator_arg_t, const Allocator& a, Executor e) : impl_(impl::create(e, a)) { } template void executor::dispatch(ASIO_MOVE_ARG(Function) f, const Allocator& a) const { impl_base* i = get_impl(); if (i->fast_dispatch_) system_executor().dispatch(ASIO_MOVE_CAST(Function)(f), a); else i->dispatch(function(ASIO_MOVE_CAST(Function)(f), a)); } template void executor::post(ASIO_MOVE_ARG(Function) f, const Allocator& a) const { get_impl()->post(function(ASIO_MOVE_CAST(Function)(f), a)); } template void executor::defer(ASIO_MOVE_ARG(Function) f, const Allocator& a) const { get_impl()->defer(function(ASIO_MOVE_CAST(Function)(f), a)); } template Executor* executor::target() ASIO_NOEXCEPT { return impl_ && impl_->target_type() == type_id() ? static_cast(impl_->target()) : 0; } template const Executor* executor::target() const ASIO_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 // ASIO_IMPL_EXECUTOR_HPP