285 lines
7.6 KiB
C++
285 lines
7.6 KiB
C++
//
|
|
// experimental/detail/channel_operation.hpp
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
// Copyright (c) 2003-2023 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_EXPERIMENTAL_DETAIL_CHANNEL_OPERATION_HPP
|
|
#define ASIO_EXPERIMENTAL_DETAIL_CHANNEL_OPERATION_HPP
|
|
|
|
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
|
# pragma once
|
|
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
|
|
|
#include "asio/detail/config.hpp"
|
|
#include "asio/associated_allocator.hpp"
|
|
#include "asio/associated_executor.hpp"
|
|
#include "asio/associated_immediate_executor.hpp"
|
|
#include "asio/detail/initiate_post.hpp"
|
|
#include "asio/detail/initiate_dispatch.hpp"
|
|
#include "asio/detail/op_queue.hpp"
|
|
#include "asio/detail/type_traits.hpp"
|
|
#include "asio/execution/executor.hpp"
|
|
#include "asio/execution/outstanding_work.hpp"
|
|
#include "asio/executor_work_guard.hpp"
|
|
#include "asio/prefer.hpp"
|
|
|
|
#include "asio/detail/push_options.hpp"
|
|
|
|
namespace asio {
|
|
namespace experimental {
|
|
namespace detail {
|
|
|
|
// Base class for all channel operations. A function pointer is used instead of
|
|
// virtual functions to avoid the associated overhead.
|
|
class channel_operation ASIO_INHERIT_TRACKED_HANDLER
|
|
{
|
|
public:
|
|
template <typename Executor, typename = void>
|
|
class handler_work_base;
|
|
|
|
template <typename Handler, typename IoExecutor, typename = void>
|
|
class handler_work;
|
|
|
|
void destroy()
|
|
{
|
|
func_(this, destroy_op, 0);
|
|
}
|
|
|
|
protected:
|
|
enum action
|
|
{
|
|
destroy_op = 0,
|
|
immediate_op = 1,
|
|
complete_op = 2,
|
|
cancel_op = 3,
|
|
close_op = 4
|
|
};
|
|
|
|
typedef void (*func_type)(channel_operation*, action, void*);
|
|
|
|
channel_operation(func_type func)
|
|
: next_(0),
|
|
func_(func),
|
|
cancellation_key_(0)
|
|
{
|
|
}
|
|
|
|
// Prevents deletion through this type.
|
|
~channel_operation()
|
|
{
|
|
}
|
|
|
|
friend class asio::detail::op_queue_access;
|
|
channel_operation* next_;
|
|
func_type func_;
|
|
|
|
public:
|
|
// The operation key used for targeted cancellation.
|
|
void* cancellation_key_;
|
|
};
|
|
|
|
template <typename Executor, typename>
|
|
class channel_operation::handler_work_base
|
|
{
|
|
public:
|
|
typedef typename decay<
|
|
typename prefer_result<Executor,
|
|
execution::outstanding_work_t::tracked_t
|
|
>::type
|
|
>::type executor_type;
|
|
|
|
handler_work_base(int, const Executor& ex)
|
|
: executor_(asio::prefer(ex, execution::outstanding_work.tracked))
|
|
{
|
|
}
|
|
|
|
const executor_type& get_executor() const ASIO_NOEXCEPT
|
|
{
|
|
return executor_;
|
|
}
|
|
|
|
template <typename Function, typename Handler>
|
|
void post(Function& function, Handler& handler)
|
|
{
|
|
typename associated_allocator<Handler>::type allocator =
|
|
(get_associated_allocator)(handler);
|
|
|
|
#if defined(ASIO_NO_DEPRECATED)
|
|
asio::prefer(
|
|
asio::require(executor_, execution::blocking.never),
|
|
execution::allocator(allocator)
|
|
).execute(ASIO_MOVE_CAST(Function)(function));
|
|
#else // defined(ASIO_NO_DEPRECATED)
|
|
execution::execute(
|
|
asio::prefer(
|
|
asio::require(executor_, execution::blocking.never),
|
|
execution::allocator(allocator)),
|
|
ASIO_MOVE_CAST(Function)(function));
|
|
#endif // defined(ASIO_NO_DEPRECATED)
|
|
}
|
|
|
|
private:
|
|
executor_type executor_;
|
|
};
|
|
|
|
#if !defined(ASIO_NO_TS_EXECUTORS)
|
|
|
|
template <typename Executor>
|
|
class channel_operation::handler_work_base<Executor,
|
|
typename enable_if<
|
|
!execution::is_executor<Executor>::value
|
|
>::type>
|
|
{
|
|
public:
|
|
typedef Executor executor_type;
|
|
|
|
handler_work_base(int, const Executor& ex)
|
|
: work_(ex)
|
|
{
|
|
}
|
|
|
|
executor_type get_executor() const ASIO_NOEXCEPT
|
|
{
|
|
return work_.get_executor();
|
|
}
|
|
|
|
template <typename Function, typename Handler>
|
|
void post(Function& function, Handler& handler)
|
|
{
|
|
typename associated_allocator<Handler>::type allocator =
|
|
(get_associated_allocator)(handler);
|
|
|
|
work_.get_executor().post(
|
|
ASIO_MOVE_CAST(Function)(function), allocator);
|
|
}
|
|
|
|
private:
|
|
executor_work_guard<Executor> work_;
|
|
};
|
|
|
|
#endif // !defined(ASIO_NO_TS_EXECUTORS)
|
|
|
|
template <typename Handler, typename IoExecutor, typename>
|
|
class channel_operation::handler_work :
|
|
channel_operation::handler_work_base<IoExecutor>,
|
|
channel_operation::handler_work_base<
|
|
typename associated_executor<Handler, IoExecutor>::type, IoExecutor>
|
|
{
|
|
public:
|
|
typedef channel_operation::handler_work_base<IoExecutor> base1_type;
|
|
|
|
typedef channel_operation::handler_work_base<
|
|
typename associated_executor<Handler, IoExecutor>::type, IoExecutor>
|
|
base2_type;
|
|
|
|
handler_work(Handler& handler, const IoExecutor& io_ex) ASIO_NOEXCEPT
|
|
: base1_type(0, io_ex),
|
|
base2_type(0, (get_associated_executor)(handler, io_ex))
|
|
{
|
|
}
|
|
|
|
template <typename Function>
|
|
void complete(Function& function, Handler& handler)
|
|
{
|
|
base2_type::post(function, handler);
|
|
}
|
|
|
|
template <typename Function>
|
|
void immediate(Function& function, Handler& handler, ...)
|
|
{
|
|
typedef typename associated_immediate_executor<Handler,
|
|
typename base1_type::executor_type>::type immediate_ex_type;
|
|
|
|
immediate_ex_type immediate_ex = (get_associated_immediate_executor)(
|
|
handler, base1_type::get_executor());
|
|
|
|
(asio::detail::initiate_dispatch_with_executor<immediate_ex_type>(
|
|
immediate_ex))(ASIO_MOVE_CAST(Function)(function));
|
|
}
|
|
|
|
template <typename Function>
|
|
void immediate(Function& function, Handler&,
|
|
typename enable_if<
|
|
is_same<
|
|
typename associated_immediate_executor<
|
|
typename conditional<false, Function, Handler>::type,
|
|
typename base1_type::executor_type>::
|
|
asio_associated_immediate_executor_is_unspecialised,
|
|
void
|
|
>::value
|
|
>::type*)
|
|
{
|
|
(asio::detail::initiate_post_with_executor<
|
|
typename base1_type::executor_type>(
|
|
base1_type::get_executor()))(
|
|
ASIO_MOVE_CAST(Function)(function));
|
|
}
|
|
};
|
|
|
|
template <typename Handler, typename IoExecutor>
|
|
class channel_operation::handler_work<
|
|
Handler, IoExecutor,
|
|
typename enable_if<
|
|
is_same<
|
|
typename associated_executor<Handler,
|
|
IoExecutor>::asio_associated_executor_is_unspecialised,
|
|
void
|
|
>::value
|
|
>::type> : handler_work_base<IoExecutor>
|
|
{
|
|
public:
|
|
typedef channel_operation::handler_work_base<IoExecutor> base1_type;
|
|
|
|
handler_work(Handler&, const IoExecutor& io_ex) ASIO_NOEXCEPT
|
|
: base1_type(0, io_ex)
|
|
{
|
|
}
|
|
|
|
template <typename Function>
|
|
void complete(Function& function, Handler& handler)
|
|
{
|
|
base1_type::post(function, handler);
|
|
}
|
|
|
|
template <typename Function>
|
|
void immediate(Function& function, Handler& handler, ...)
|
|
{
|
|
typedef typename associated_immediate_executor<Handler,
|
|
typename base1_type::executor_type>::type immediate_ex_type;
|
|
|
|
immediate_ex_type immediate_ex = (get_associated_immediate_executor)(
|
|
handler, base1_type::get_executor());
|
|
|
|
(asio::detail::initiate_dispatch_with_executor<immediate_ex_type>(
|
|
immediate_ex))(ASIO_MOVE_CAST(Function)(function));
|
|
}
|
|
|
|
template <typename Function>
|
|
void immediate(Function& function, Handler& handler,
|
|
typename enable_if<
|
|
is_same<
|
|
typename associated_immediate_executor<
|
|
typename conditional<false, Function, Handler>::type,
|
|
typename base1_type::executor_type>::
|
|
asio_associated_immediate_executor_is_unspecialised,
|
|
void
|
|
>::value
|
|
>::type*)
|
|
{
|
|
base1_type::post(function, handler);
|
|
}
|
|
};
|
|
|
|
} // namespace detail
|
|
} // namespace experimental
|
|
} // namespace asio
|
|
|
|
#include "asio/detail/pop_options.hpp"
|
|
|
|
#endif // ASIO_EXPERIMENTAL_DETAIL_CHANNEL_OPERATION_HPP
|