Simplify and improve performance of executor operations.

This commit is contained in:
Christopher Kohlhoff 2017-03-17 16:35:30 +11:00
parent e5acea17d7
commit bbe092b3d7
7 changed files with 74 additions and 132 deletions

View File

@ -31,11 +31,12 @@ template <typename Handler, typename Alloc,
class executor_op : public Operation
{
public:
ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(executor_op, Alloc);
ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(executor_op);
executor_op(Handler& h, const Alloc& allocator)
template <typename H>
executor_op(ASIO_MOVE_ARG(H) h, const Alloc& allocator)
: Operation(&executor_op::do_complete),
handler_(ASIO_MOVE_CAST(Handler)(h)),
handler_(ASIO_MOVE_CAST(H)(h)),
allocator_(allocator)
{
}
@ -46,7 +47,8 @@ public:
{
// Take ownership of the handler object.
executor_op* o(static_cast<executor_op*>(base));
ptr p = { o->allocator_, o, o };
Alloc allocator(o->allocator_);
ptr p = { detail::addressof(allocator), o, o };
ASIO_HANDLER_COMPLETION((*o));

View File

@ -18,6 +18,7 @@
#include "asio/detail/config.hpp"
#include "asio/detail/memory.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/recycling_allocator.hpp"
#include "asio/associated_allocator.hpp"
#include "asio/handler_alloc_hook.hpp"
@ -164,18 +165,30 @@ public:
} \
/**/
#define ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(op, alloc) \
#define ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(op) \
struct ptr \
{ \
ASIO_REBIND_ALLOC(alloc, op) a; \
const Alloc* a; \
void* v; \
op* p; \
~ptr() \
{ \
reset(); \
} \
static op* allocate(const Alloc& a) \
{ \
typedef typename ::asio::detail::get_recycling_allocator< \
Alloc>::type recycling_allocator_type; \
ASIO_REBIND_ALLOC(recycling_allocator_type, op) a1( \
::asio::detail::get_recycling_allocator<Alloc>::get(a)); \
return a1.allocate(1); \
} \
void reset() \
{ \
typedef typename ::asio::detail::get_recycling_allocator< \
Alloc>::type recycling_allocator_type; \
ASIO_REBIND_ALLOC(recycling_allocator_type, op) a1( \
::asio::detail::get_recycling_allocator<Alloc>::get(*a)); \
if (p) \
{ \
p->~op(); \
@ -183,7 +196,7 @@ public:
} \
if (v) \
{ \
a.deallocate(static_cast<op*>(v), 1); \
a1.deallocate(static_cast<op*>(v), 1); \
v = 0; \
} \
} \

View File

@ -99,27 +99,23 @@ 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)
{
// Make a local, non-const copy of the function.
typedef typename decay<Function>::type function_type;
function_type tmp(ASIO_MOVE_CAST(Function)(function));
// If we are already in the strand then the function can run immediately.
if (call_stack<strand_impl>::contains(impl.get()))
{
// Make a local, non-const copy of the function.
function_type tmp(ASIO_MOVE_CAST(Function)(function));
fenced_block b(fenced_block::full);
asio_handler_invoke_helpers::invoke(tmp, 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(ASIO_MOVE_CAST(Function)(function), a);
ASIO_HANDLER_CREATION((impl->service_->context(), *p.p,
"strand_executor", impl.get(), 0, "dispatch"));
@ -128,7 +124,7 @@ 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);
ex.dispatch(invoker<Executor>(impl, ex), a);
}
// Request invocation of the given function and return immediately.
@ -136,19 +132,12 @@ 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)
{
// 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));
// 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(ASIO_MOVE_CAST(Function)(function), a);
ASIO_HANDLER_CREATION((impl->service_->context(), *p.p,
"strand_executor", impl.get(), 0, "post"));
@ -157,7 +146,7 @@ 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);
ex.post(invoker<Executor>(impl, ex), a);
}
// Request invocation of the given function and return immediately.
@ -165,19 +154,12 @@ 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)
{
// 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));
// 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(ASIO_MOVE_CAST(Function)(function), a);
ASIO_HANDLER_CREATION((impl->service_->context(), *p.p,
"strand_executor", impl.get(), 0, "defer"));
@ -186,7 +168,7 @@ 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);
ex.defer(invoker<Executor>(impl, ex), a);
}
} // namespace detail

View File

@ -39,15 +39,10 @@ public:
template <typename F, typename Alloc>
explicit function(F f, const Alloc& a)
{
// Construct an allocator to be used for the operation.
typedef typename detail::get_recycling_allocator<Alloc>::type alloc_type;
alloc_type allocator(detail::get_recycling_allocator<Alloc>::get(a));
// Allocate and construct an operation to wrap the function.
typedef detail::executor_op<F, alloc_type> op;
typename op::ptr p = { allocator, 0, 0 };
p.v = p.a.allocate(1);
op_ = new (p.v) op(f, allocator);
typedef detail::executor_op<F, Alloc> op;
typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
op_ = new (p.v) op(ASIO_MOVE_CAST(F)(f), a);
p.v = 0;
}

View File

@ -226,27 +226,23 @@ template <typename Function, typename Allocator>
void io_context::executor_type::dispatch(
ASIO_MOVE_ARG(Function) f, const Allocator& a) const
{
// Make a local, non-const copy of the function.
typedef typename decay<Function>::type function_type;
function_type tmp(ASIO_MOVE_CAST(Function)(f));
// Invoke immediately if we are already inside the thread pool.
if (io_context_.impl_.can_dispatch())
{
// Make a local, non-const copy of the function.
function_type tmp(ASIO_MOVE_CAST(Function)(f));
detail::fenced_block b(detail::fenced_block::full);
asio_handler_invoke_helpers::invoke(tmp, 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 detail::executor_op<function_type, alloc_type, detail::operation> op;
typename op::ptr p = { allocator, 0, 0 };
p.v = p.a.allocate(1);
p.p = new (p.v) op(tmp, allocator);
typedef detail::executor_op<function_type, Allocator, detail::operation> op;
typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a);
ASIO_HANDLER_CREATION((this->context(), *p.p,
"io_context", &this->context(), 0, "post"));
@ -259,19 +255,12 @@ template <typename Function, typename Allocator>
void io_context::executor_type::post(
ASIO_MOVE_ARG(Function) f, const Allocator& a) const
{
// Make a local, non-const copy of the function.
typedef typename decay<Function>::type function_type;
function_type tmp(ASIO_MOVE_CAST(Function)(f));
// 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 detail::executor_op<function_type, alloc_type, detail::operation> op;
typename op::ptr p = { allocator, 0, 0 };
p.v = p.a.allocate(1);
p.p = new (p.v) op(tmp, allocator);
typedef detail::executor_op<function_type, Allocator, detail::operation> op;
typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a);
ASIO_HANDLER_CREATION((this->context(), *p.p,
"io_context", &this->context(), 0, "post"));
@ -284,19 +273,12 @@ template <typename Function, typename Allocator>
void io_context::executor_type::defer(
ASIO_MOVE_ARG(Function) f, const Allocator& a) const
{
// Make a local, non-const copy of the function.
typedef typename decay<Function>::type function_type;
function_type tmp(ASIO_MOVE_CAST(Function)(f));
// 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 detail::executor_op<function_type, alloc_type, detail::operation> op;
typename op::ptr p = { allocator, 0, 0 };
p.v = p.a.allocate(1);
p.p = new (p.v) op(tmp, allocator);
typedef detail::executor_op<function_type, Allocator, detail::operation> op;
typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a);
ASIO_HANDLER_CREATION((this->context(), *p.p,
"io_context", &this->context(), 0, "defer"));

View File

@ -42,21 +42,14 @@ template <typename Function, typename Allocator>
void system_executor::post(
ASIO_MOVE_ARG(Function) f, const Allocator& a) const
{
typedef typename decay<Function>::type function_type;
context_impl& ctx = detail::global<context_impl>();
// Make a local, non-const copy of the function.
typedef typename decay<Function>::type function_type;
function_type tmp(ASIO_MOVE_CAST(Function)(f));
// 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 detail::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 detail::executor_op<function_type, Allocator> op;
typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a);
ASIO_HANDLER_CREATION((ctx, *p.p,
"system_executor", &this->context(), 0, "post"));
@ -69,21 +62,14 @@ template <typename Function, typename Allocator>
void system_executor::defer(
ASIO_MOVE_ARG(Function) f, const Allocator& a) const
{
typedef typename decay<Function>::type function_type;
context_impl& ctx = detail::global<context_impl>();
// Make a local, non-const copy of the function.
typedef typename decay<Function>::type function_type;
function_type tmp(ASIO_MOVE_CAST(Function)(f));
// 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 detail::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 detail::executor_op<function_type, Allocator> op;
typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a);
ASIO_HANDLER_CREATION((ctx, *p.p,
"system_executor", &this->context(), 0, "defer"));

View File

@ -53,27 +53,23 @@ template <typename Function, typename Allocator>
void thread_pool::executor_type::dispatch(
ASIO_MOVE_ARG(Function) f, const Allocator& a) const
{
// Make a local, non-const copy of the function.
typedef typename decay<Function>::type function_type;
function_type tmp(ASIO_MOVE_CAST(Function)(f));
// Invoke immediately if we are already inside the thread pool.
if (pool_.scheduler_.can_dispatch())
{
// Make a local, non-const copy of the function.
function_type tmp(ASIO_MOVE_CAST(Function)(f));
detail::fenced_block b(detail::fenced_block::full);
asio_handler_invoke_helpers::invoke(tmp, 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 detail::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 detail::executor_op<function_type, Allocator> op;
typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a);
ASIO_HANDLER_CREATION((pool_, *p.p,
"thread_pool", &this->context(), 0, "dispatch"));
@ -86,19 +82,12 @@ template <typename Function, typename Allocator>
void thread_pool::executor_type::post(
ASIO_MOVE_ARG(Function) f, const Allocator& a) const
{
// Make a local, non-const copy of the function.
typedef typename decay<Function>::type function_type;
function_type tmp(ASIO_MOVE_CAST(Function)(f));
// 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 detail::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 detail::executor_op<function_type, Allocator> op;
typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a);
ASIO_HANDLER_CREATION((pool_, *p.p,
"thread_pool", &this->context(), 0, "post"));
@ -111,19 +100,12 @@ template <typename Function, typename Allocator>
void thread_pool::executor_type::defer(
ASIO_MOVE_ARG(Function) f, const Allocator& a) const
{
// Make a local, non-const copy of the function.
typedef typename decay<Function>::type function_type;
function_type tmp(ASIO_MOVE_CAST(Function)(f));
// 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 detail::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 detail::executor_op<function_type, Allocator> op;
typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(f), a);
ASIO_HANDLER_CREATION((pool_, *p.p,
"thread_pool", &this->context(), 0, "defer"));