diff options
Diffstat (limited to '3rdparty/asio/include/asio/detail/impl/strand_executor_service.hpp')
-rw-r--r-- | 3rdparty/asio/include/asio/detail/impl/strand_executor_service.hpp | 285 |
1 files changed, 217 insertions, 68 deletions
diff --git a/3rdparty/asio/include/asio/detail/impl/strand_executor_service.hpp b/3rdparty/asio/include/asio/detail/impl/strand_executor_service.hpp index fedea1cf3b4..3ffb398dcf6 100644 --- a/3rdparty/asio/include/asio/detail/impl/strand_executor_service.hpp +++ b/3rdparty/asio/include/asio/detail/impl/strand_executor_service.hpp @@ -2,7 +2,7 @@ // detail/impl/strand_executor_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// 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) @@ -15,19 +15,130 @@ # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) -#include "asio/detail/call_stack.hpp" #include "asio/detail/fenced_block.hpp" -#include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/recycling_allocator.hpp" #include "asio/executor_work_guard.hpp" +#include "asio/defer.hpp" +#include "asio/dispatch.hpp" +#include "asio/post.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { +template <typename F, typename Allocator> +class strand_executor_service::allocator_binder +{ +public: + typedef Allocator allocator_type; + + allocator_binder(F&& f, const Allocator& a) + : f_(static_cast<F&&>(f)), + allocator_(a) + { + } + + allocator_binder(const allocator_binder& other) + : f_(other.f_), + allocator_(other.allocator_) + { + } + + allocator_binder(allocator_binder&& other) + : f_(static_cast<F&&>(other.f_)), + allocator_(static_cast<allocator_type&&>(other.allocator_)) + { + } + + allocator_type get_allocator() const noexcept + { + return allocator_; + } + + void operator()() + { + f_(); + } + +private: + F f_; + allocator_type allocator_; +}; + template <typename Executor> -class strand_executor_service::invoker +class strand_executor_service::invoker<Executor, + enable_if_t< + execution::is_executor<Executor>::value + >> +{ +public: + invoker(const implementation_type& impl, Executor& ex) + : impl_(impl), + executor_(asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + invoker(const invoker& other) + : impl_(other.impl_), + executor_(other.executor_) + { + } + + invoker(invoker&& other) + : impl_(static_cast<implementation_type&&>(other.impl_)), + executor_(static_cast<executor_type&&>(other.executor_)) + { + } + + struct on_invoker_exit + { + invoker* this_; + + ~on_invoker_exit() + { + if (push_waiting_to_ready(this_->impl_)) + { + recycling_allocator<void> allocator; + executor_type ex = this_->executor_; + asio::prefer( + asio::require( + static_cast<executor_type&&>(ex), + execution::blocking.never), + execution::allocator(allocator) + ).execute(static_cast<invoker&&>(*this_)); + } + } + }; + + void operator()() + { + // Ensure the next handler, if any, is scheduled on block exit. + on_invoker_exit on_exit = { this }; + (void)on_exit; + + run_ready_handlers(impl_); + } + +private: + typedef decay_t< + prefer_result_t< + Executor, + execution::outstanding_work_t::tracked_t + > + > executor_type; + + implementation_type impl_; + executor_type executor_; +}; + +#if !defined(ASIO_NO_TS_EXECUTORS) + +template <typename Executor> +class strand_executor_service::invoker<Executor, + enable_if_t< + !execution::is_executor<Executor>::value + >> { public: invoker(const implementation_type& impl, Executor& ex) @@ -42,13 +153,11 @@ public: { } -#if defined(ASIO_HAS_MOVE) invoker(invoker&& other) - : impl_(ASIO_MOVE_CAST(implementation_type)(other.impl_)), - work_(ASIO_MOVE_CAST(executor_work_guard<Executor>)(other.work_)) + : impl_(static_cast<implementation_type&&>(other.impl_)), + work_(static_cast<executor_work_guard<Executor>&&>(other.work_)) { } -#endif // defined(ASIO_HAS_MOVE) struct on_invoker_exit { @@ -56,38 +165,22 @@ public: ~on_invoker_exit() { - this_->impl_->mutex_->lock(); - this_->impl_->ready_queue_.push(this_->impl_->waiting_queue_); - bool more_handlers = this_->impl_->locked_ = - !this_->impl_->ready_queue_.empty(); - this_->impl_->mutex_->unlock(); - - if (more_handlers) + if (push_waiting_to_ready(this_->impl_)) { Executor ex(this_->work_.get_executor()); recycling_allocator<void> allocator; - ex.post(ASIO_MOVE_CAST(invoker)(*this_), allocator); + ex.post(static_cast<invoker&&>(*this_), allocator); } } }; void operator()() { - // Indicate that this strand is executing on the current thread. - call_stack<strand_impl>::context ctx(impl_.get()); - // Ensure the next handler, if any, is scheduled on block exit. on_invoker_exit on_exit = { this }; (void)on_exit; - // Run all ready handlers. No lock is required since the ready queue is - // accessed only within the strand. - asio::error_code ec; - while (scheduler_operation* o = impl_->ready_queue_.front()) - { - impl_->ready_queue_.pop(); - o->complete(impl_.get(), ec, 0); - } + run_ready_handlers(impl_); } private: @@ -95,31 +188,89 @@ private: executor_work_guard<Executor> work_; }; +#endif // !defined(ASIO_NO_TS_EXECUTORS) + +template <typename Executor, typename Function> +inline void strand_executor_service::execute(const implementation_type& impl, + Executor& ex, Function&& function, + enable_if_t< + can_query<Executor, execution::allocator_t<void>>::value + >*) +{ + return strand_executor_service::do_execute(impl, ex, + static_cast<Function&&>(function), + asio::query(ex, execution::allocator)); +} + +template <typename Executor, typename Function> +inline void strand_executor_service::execute(const implementation_type& impl, + Executor& ex, Function&& function, + enable_if_t< + !can_query<Executor, execution::allocator_t<void>>::value + >*) +{ + return strand_executor_service::do_execute(impl, ex, + static_cast<Function&&>(function), + std::allocator<void>()); +} + +template <typename Executor, typename Function, typename Allocator> +void strand_executor_service::do_execute(const implementation_type& impl, + Executor& ex, Function&& function, const Allocator& a) +{ + typedef decay_t<Function> function_type; + + // If the executor is not never-blocking, and we are already in the strand, + // then the function can run immediately. + if (asio::query(ex, execution::blocking) != execution::blocking.never + && running_in_this_thread(impl)) + { + // Make a local, non-const copy of the function. + function_type tmp(static_cast<Function&&>(function)); + + fenced_block b(fenced_block::full); + static_cast<function_type&&>(tmp)(); + return; + } + + // Allocate and construct an operation to wrap the function. + typedef executor_op<function_type, Allocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(static_cast<Function&&>(function), a); + + ASIO_HANDLER_CREATION((impl->service_->context(), *p.p, + "strand_executor", impl.get(), 0, "execute")); + + // Add the function to the strand and schedule the strand if required. + bool first = enqueue(impl, p.p); + p.v = p.p = 0; + if (first) + { + ex.execute(invoker<Executor>(impl, ex)); + } +} + template <typename Executor, typename Function, typename Allocator> void strand_executor_service::dispatch(const implementation_type& impl, - Executor& ex, ASIO_MOVE_ARG(Function) function, const Allocator& a) + Executor& ex, Function&& function, const Allocator& a) { - // Make a local, non-const copy of the function. - typedef typename decay<Function>::type function_type; - function_type tmp(ASIO_MOVE_CAST(Function)(function)); + typedef decay_t<Function> function_type; // If we are already in the strand then the function can run immediately. - if (call_stack<strand_impl>::contains(impl.get())) + if (running_in_this_thread(impl)) { + // Make a local, non-const copy of the function. + function_type tmp(static_cast<Function&&>(function)); + fenced_block b(fenced_block::full); - asio_handler_invoke_helpers::invoke(tmp, tmp); + static_cast<function_type&&>(tmp)(); return; } - // Construct an allocator to be used for the operation. - typedef typename detail::get_recycling_allocator<Allocator>::type alloc_type; - alloc_type allocator(detail::get_recycling_allocator<Allocator>::get(a)); - // Allocate and construct an operation to wrap the function. - typedef executor_op<function_type, alloc_type> op; - typename op::ptr p = { allocator, 0, 0 }; - p.v = p.a.allocate(1); - p.p = new (p.v) op(tmp, allocator); + typedef executor_op<function_type, Allocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(static_cast<Function&&>(function), a); ASIO_HANDLER_CREATION((impl->service_->context(), *p.p, "strand_executor", impl.get(), 0, "dispatch")); @@ -128,27 +279,24 @@ void strand_executor_service::dispatch(const implementation_type& impl, bool first = enqueue(impl, p.p); p.v = p.p = 0; if (first) - ex.dispatch(invoker<Executor>(impl, ex), allocator); + { + asio::dispatch(ex, + allocator_binder<invoker<Executor>, Allocator>( + invoker<Executor>(impl, ex), a)); + } } // Request invocation of the given function and return immediately. template <typename Executor, typename Function, typename Allocator> void strand_executor_service::post(const implementation_type& impl, - Executor& ex, ASIO_MOVE_ARG(Function) function, const Allocator& a) + Executor& ex, Function&& function, const Allocator& a) { - // Make a local, non-const copy of the function. - typedef typename decay<Function>::type function_type; - function_type tmp(ASIO_MOVE_CAST(Function)(function)); - - // Construct an allocator to be used for the operation. - typedef typename detail::get_recycling_allocator<Allocator>::type alloc_type; - alloc_type allocator(detail::get_recycling_allocator<Allocator>::get(a)); + typedef decay_t<Function> function_type; // Allocate and construct an operation to wrap the function. - typedef executor_op<function_type, alloc_type> op; - typename op::ptr p = { allocator, 0, 0 }; - p.v = p.a.allocate(1); - p.p = new (p.v) op(tmp, allocator); + typedef executor_op<function_type, Allocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(static_cast<Function&&>(function), a); ASIO_HANDLER_CREATION((impl->service_->context(), *p.p, "strand_executor", impl.get(), 0, "post")); @@ -157,27 +305,24 @@ void strand_executor_service::post(const implementation_type& impl, bool first = enqueue(impl, p.p); p.v = p.p = 0; if (first) - ex.post(invoker<Executor>(impl, ex), allocator); + { + asio::post(ex, + allocator_binder<invoker<Executor>, Allocator>( + invoker<Executor>(impl, ex), a)); + } } // Request invocation of the given function and return immediately. template <typename Executor, typename Function, typename Allocator> void strand_executor_service::defer(const implementation_type& impl, - Executor& ex, ASIO_MOVE_ARG(Function) function, const Allocator& a) + Executor& ex, Function&& function, const Allocator& a) { - // Make a local, non-const copy of the function. - typedef typename decay<Function>::type function_type; - function_type tmp(ASIO_MOVE_CAST(Function)(function)); - - // Construct an allocator to be used for the operation. - typedef typename detail::get_recycling_allocator<Allocator>::type alloc_type; - alloc_type allocator(detail::get_recycling_allocator<Allocator>::get(a)); + typedef decay_t<Function> function_type; // Allocate and construct an operation to wrap the function. - typedef executor_op<function_type, alloc_type> op; - typename op::ptr p = { allocator, 0, 0 }; - p.v = p.a.allocate(1); - p.p = new (p.v) op(tmp, allocator); + typedef executor_op<function_type, Allocator> op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(static_cast<Function&&>(function), a); ASIO_HANDLER_CREATION((impl->service_->context(), *p.p, "strand_executor", impl.get(), 0, "defer")); @@ -186,7 +331,11 @@ void strand_executor_service::defer(const implementation_type& impl, bool first = enqueue(impl, p.p); p.v = p.p = 0; if (first) - ex.defer(invoker<Executor>(impl, ex), allocator); + { + asio::defer(ex, + allocator_binder<invoker<Executor>, Allocator>( + invoker<Executor>(impl, ex), a)); + } } } // namespace detail |