123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 |
- //
- // 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
|