blob: a1ff1effaa391e9c5334dd021b4b32dafe14ce06 [file] [log] [blame]
//
// experimental/detail/channel_operation.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2021 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/detail/op_queue.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,
complete_op = 1,
cancel_op = 2,
close_op = 3
};
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:
handler_work_base(int, const Executor& ex)
: executor_(asio::prefer(ex, execution::outstanding_work.tracked))
{
}
template <typename Function, typename Handler>
void post(Function& function, Handler& handler)
{
typename associated_allocator<Handler>::type allocator =
(get_associated_allocator)(handler);
execution::execute(
asio::prefer(
asio::require(executor_, execution::blocking.never),
execution::allocator(allocator)),
ASIO_MOVE_CAST(Function)(function));
}
private:
typename decay<
typename prefer_result<Executor,
execution::outstanding_work_t::tracked_t
>::type
>::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:
handler_work_base(int, const Executor& ex)
: work_(ex)
{
}
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 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);
}
};
} // namespace detail
} // namespace experimental
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_EXPERIMENTAL_DETAIL_CHANNEL_OPERATION_HPP