boost/asio/detail/timed_cancel_op.hpp
//
// detail/timed_cancel_op.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// 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)
//
#ifndef BOOST_ASIO_DETAIL_TIMED_CANCEL_OP_HPP
#define BOOST_ASIO_DETAIL_TIMED_CANCEL_OP_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <boost/asio/associated_cancellation_slot.hpp>
#include <boost/asio/associator.hpp>
#include <boost/asio/basic_waitable_timer.hpp>
#include <boost/asio/cancellation_signal.hpp>
#include <boost/asio/detail/atomic_count.hpp>
#include <boost/asio/detail/completion_payload.hpp>
#include <boost/asio/detail/completion_payload_handler.hpp>
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
template <typename Op, typename... Signatures>
class timed_cancel_op_handler;
template <typename Op>
class timed_cancel_timer_handler;
template <typename Handler, typename Timer, typename... Signatures>
class timed_cancel_op
{
public:
using handler_type = Handler;
BOOST_ASIO_DEFINE_TAGGED_HANDLER_PTR(
thread_info_base::timed_cancel_tag, timed_cancel_op);
timed_cancel_op(Handler& handler, Timer timer,
cancellation_type_t cancel_type)
: ref_count_(2),
handler_(static_cast<Handler&&>(handler)),
timer_(static_cast<Timer&&>(timer)),
cancellation_type_(cancel_type),
cancel_proxy_(nullptr),
has_payload_(false),
has_pending_timer_wait_(true)
{
}
~timed_cancel_op()
{
if (has_payload_)
payload_storage_.payload_.~payload_type();
}
cancellation_slot get_cancellation_slot() noexcept
{
return cancellation_signal_.slot();
}
template <typename Initiation, typename... Args>
void start(Initiation&& initiation, Args&&... args)
{
using op_handler_type =
timed_cancel_op_handler<timed_cancel_op, Signatures...>;
op_handler_type op_handler(this);
using timer_handler_type =
timed_cancel_timer_handler<timed_cancel_op>;
timer_handler_type timer_handler(this);
associated_cancellation_slot_t<Handler> slot
= (get_associated_cancellation_slot)(handler_);
if (slot.is_connected())
cancel_proxy_ = &slot.template emplace<cancel_proxy>(this);
timer_.async_wait(static_cast<timer_handler_type&&>(timer_handler));
async_initiate<op_handler_type, Signatures...>(
static_cast<Initiation&&>(initiation),
static_cast<op_handler_type&>(op_handler),
static_cast<Args&&>(args)...);
}
template <typename Message>
void handle_op(Message&& message)
{
if (cancel_proxy_)
cancel_proxy_->op_ = nullptr;
new (&payload_storage_.payload_) payload_type(
static_cast<Message&&>(message));
has_payload_ = true;
if (has_pending_timer_wait_)
{
timer_.cancel();
release();
}
else
{
complete();
}
}
void handle_timer()
{
has_pending_timer_wait_ = false;
if (has_payload_)
{
complete();
}
else
{
cancellation_signal_.emit(cancellation_type_);
release();
}
}
void release()
{
if (--ref_count_ == 0)
{
ptr p = { boost::asio::detail::addressof(handler_), this, this };
Handler handler(static_cast<Handler&&>(handler_));
p.h = boost::asio::detail::addressof(handler);
p.reset();
}
}
void complete()
{
if (--ref_count_ == 0)
{
ptr p = { boost::asio::detail::addressof(handler_), this, this };
completion_payload_handler<payload_type, Handler> handler(
static_cast<payload_type&&>(payload_storage_.payload_), handler_);
p.h = boost::asio::detail::addressof(handler.handler());
p.reset();
handler();
}
}
//private:
typedef completion_payload<Signatures...> payload_type;
struct cancel_proxy
{
cancel_proxy(timed_cancel_op* op)
: op_(op)
{
}
void operator()(cancellation_type_t type)
{
if (op_)
op_->cancellation_signal_.emit(type);
}
timed_cancel_op* op_;
};
// The number of handlers that share a reference to the state.
atomic_count ref_count_;
// The handler to be called when the operation completes.
Handler handler_;
// The timer used to determine when to cancel the pending operation.
Timer timer_;
// The cancellation signal and type used to cancel the pending operation.
cancellation_signal cancellation_signal_;
cancellation_type_t cancellation_type_;
// A proxy cancel handler used to allow cancellation of the timed operation.
cancel_proxy* cancel_proxy_;
// Arguments to be passed to the completion handler.
union payload_storage
{
payload_storage() {}
~payload_storage() {}
char dummy_;
payload_type payload_;
} payload_storage_;
// Whether the payload storage contains a valid payload.
bool has_payload_;
// Whether the asynchronous wait on the timer is still pending
bool has_pending_timer_wait_;
};
template <typename Op, typename R, typename... Args>
class timed_cancel_op_handler<Op, R(Args...)>
{
public:
using cancellation_slot_type = cancellation_slot;
explicit timed_cancel_op_handler(Op* op)
: op_(op)
{
}
timed_cancel_op_handler(timed_cancel_op_handler&& other) noexcept
: op_(other.op_)
{
other.op_ = nullptr;
}
~timed_cancel_op_handler()
{
if (op_)
op_->release();
}
cancellation_slot_type get_cancellation_slot() const noexcept
{
return op_->get_cancellation_slot();
}
template <typename... Args2>
enable_if_t<
is_constructible<completion_message<R(Args...)>, int, Args2...>::value
> operator()(Args2&&... args)
{
Op* op = op_;
op_ = nullptr;
typedef completion_message<R(Args...)> message_type;
op->handle_op(message_type(0, static_cast<Args2&&>(args)...));
}
//protected:
Op* op_;
};
template <typename Op, typename R, typename... Args, typename... Signatures>
class timed_cancel_op_handler<Op, R(Args...), Signatures...> :
public timed_cancel_op_handler<Op, Signatures...>
{
public:
using timed_cancel_op_handler<Op, Signatures...>::timed_cancel_op_handler;
using timed_cancel_op_handler<Op, Signatures...>::operator();
template <typename... Args2>
enable_if_t<
is_constructible<completion_message<R(Args...)>, int, Args2...>::value
> operator()(Args2&&... args)
{
Op* op = this->op_;
this->op_ = nullptr;
typedef completion_message<R(Args...)> message_type;
op->handle_op(message_type(0, static_cast<Args2&&>(args)...));
}
};
template <typename Op>
class timed_cancel_timer_handler
{
public:
using cancellation_slot_type = cancellation_slot;
explicit timed_cancel_timer_handler(Op* op)
: op_(op)
{
}
timed_cancel_timer_handler(timed_cancel_timer_handler&& other) noexcept
: op_(other.op_)
{
other.op_ = nullptr;
}
~timed_cancel_timer_handler()
{
if (op_)
op_->release();
}
cancellation_slot_type get_cancellation_slot() const noexcept
{
return cancellation_slot_type();
}
void operator()(const boost::system::error_code&)
{
Op* op = op_;
op_ = nullptr;
op->handle_timer();
}
//private:
Op* op_;
};
} // namespace detail
template <template <typename, typename> class Associator,
typename Op, typename... Signatures, typename DefaultCandidate>
struct associator<Associator,
detail::timed_cancel_op_handler<Op, Signatures...>, DefaultCandidate>
: Associator<typename Op::handler_type, DefaultCandidate>
{
static typename Associator<typename Op::handler_type, DefaultCandidate>::type
get(const detail::timed_cancel_op_handler<Op, Signatures...>& h) noexcept
{
return Associator<typename Op::handler_type, DefaultCandidate>::get(
h.op_->handler_);
}
static auto get(const detail::timed_cancel_op_handler<Op, Signatures...>& h,
const DefaultCandidate& c) noexcept
-> decltype(Associator<typename Op::handler_type, DefaultCandidate>::get(
h.op_->handler_, c))
{
return Associator<typename Op::handler_type, DefaultCandidate>::get(
h.op_->handler_, c);
}
};
template <template <typename, typename> class Associator,
typename Op, typename DefaultCandidate>
struct associator<Associator,
detail::timed_cancel_timer_handler<Op>, DefaultCandidate>
: Associator<typename Op::handler_type, DefaultCandidate>
{
static typename Associator<typename Op::handler_type, DefaultCandidate>::type
get(const detail::timed_cancel_timer_handler<Op>& h) noexcept
{
return Associator<typename Op::handler_type, DefaultCandidate>::get(
h.op_->handler_);
}
static auto get(const detail::timed_cancel_timer_handler<Op>& h,
const DefaultCandidate& c) noexcept
-> decltype(Associator<typename Op::handler_type, DefaultCandidate>::get(
h.op_->handler_, c))
{
return Associator<typename Op::handler_type, DefaultCandidate>::get(
h.op_->handler_, c);
}
};
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_DETAIL_TIMED_CANCEL_OP_HPP