timed_cancel_op.hpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. //
  2. // detail/timed_cancel_op.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #ifndef BOOST_ASIO_DETAIL_TIMED_CANCEL_OP_HPP
  11. #define BOOST_ASIO_DETAIL_TIMED_CANCEL_OP_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/detail/config.hpp>
  16. #include <boost/asio/associated_cancellation_slot.hpp>
  17. #include <boost/asio/associator.hpp>
  18. #include <boost/asio/basic_waitable_timer.hpp>
  19. #include <boost/asio/cancellation_signal.hpp>
  20. #include <boost/asio/detail/atomic_count.hpp>
  21. #include <boost/asio/detail/completion_payload.hpp>
  22. #include <boost/asio/detail/completion_payload_handler.hpp>
  23. #include <boost/asio/detail/handler_alloc_helpers.hpp>
  24. #include <boost/asio/detail/type_traits.hpp>
  25. #include <boost/asio/detail/push_options.hpp>
  26. namespace boost {
  27. namespace asio {
  28. namespace detail {
  29. template <typename Op, typename... Signatures>
  30. class timed_cancel_op_handler;
  31. template <typename Op>
  32. class timed_cancel_timer_handler;
  33. template <typename Handler, typename Timer, typename... Signatures>
  34. class timed_cancel_op
  35. {
  36. public:
  37. using handler_type = Handler;
  38. BOOST_ASIO_DEFINE_TAGGED_HANDLER_PTR(
  39. thread_info_base::timed_cancel_tag, timed_cancel_op);
  40. timed_cancel_op(Handler& handler, Timer timer,
  41. cancellation_type_t cancel_type)
  42. : ref_count_(2),
  43. handler_(static_cast<Handler&&>(handler)),
  44. timer_(static_cast<Timer&&>(timer)),
  45. cancellation_type_(cancel_type),
  46. cancel_proxy_(nullptr),
  47. has_payload_(false),
  48. has_pending_timer_wait_(true)
  49. {
  50. }
  51. ~timed_cancel_op()
  52. {
  53. if (has_payload_)
  54. payload_storage_.payload_.~payload_type();
  55. }
  56. cancellation_slot get_cancellation_slot() noexcept
  57. {
  58. return cancellation_signal_.slot();
  59. }
  60. template <typename Initiation, typename... Args>
  61. void start(Initiation&& initiation, Args&&... args)
  62. {
  63. using op_handler_type =
  64. timed_cancel_op_handler<timed_cancel_op, Signatures...>;
  65. op_handler_type op_handler(this);
  66. using timer_handler_type =
  67. timed_cancel_timer_handler<timed_cancel_op>;
  68. timer_handler_type timer_handler(this);
  69. associated_cancellation_slot_t<Handler> slot
  70. = (get_associated_cancellation_slot)(handler_);
  71. if (slot.is_connected())
  72. cancel_proxy_ = &slot.template emplace<cancel_proxy>(this);
  73. timer_.async_wait(static_cast<timer_handler_type&&>(timer_handler));
  74. async_initiate<op_handler_type, Signatures...>(
  75. static_cast<Initiation&&>(initiation),
  76. static_cast<op_handler_type&>(op_handler),
  77. static_cast<Args&&>(args)...);
  78. }
  79. template <typename Message>
  80. void handle_op(Message&& message)
  81. {
  82. if (cancel_proxy_)
  83. cancel_proxy_->op_ = nullptr;
  84. new (&payload_storage_.payload_) payload_type(
  85. static_cast<Message&&>(message));
  86. has_payload_ = true;
  87. if (has_pending_timer_wait_)
  88. {
  89. timer_.cancel();
  90. release();
  91. }
  92. else
  93. {
  94. complete();
  95. }
  96. }
  97. void handle_timer()
  98. {
  99. has_pending_timer_wait_ = false;
  100. if (has_payload_)
  101. {
  102. complete();
  103. }
  104. else
  105. {
  106. cancellation_signal_.emit(cancellation_type_);
  107. release();
  108. }
  109. }
  110. void release()
  111. {
  112. if (--ref_count_ == 0)
  113. {
  114. ptr p = { boost::asio::detail::addressof(handler_), this, this };
  115. Handler handler(static_cast<Handler&&>(handler_));
  116. p.h = boost::asio::detail::addressof(handler);
  117. p.reset();
  118. }
  119. }
  120. void complete()
  121. {
  122. if (--ref_count_ == 0)
  123. {
  124. ptr p = { boost::asio::detail::addressof(handler_), this, this };
  125. completion_payload_handler<payload_type, Handler> handler(
  126. static_cast<payload_type&&>(payload_storage_.payload_), handler_);
  127. p.h = boost::asio::detail::addressof(handler.handler());
  128. p.reset();
  129. handler();
  130. }
  131. }
  132. //private:
  133. typedef completion_payload<Signatures...> payload_type;
  134. struct cancel_proxy
  135. {
  136. cancel_proxy(timed_cancel_op* op)
  137. : op_(op)
  138. {
  139. }
  140. void operator()(cancellation_type_t type)
  141. {
  142. if (op_)
  143. op_->cancellation_signal_.emit(type);
  144. }
  145. timed_cancel_op* op_;
  146. };
  147. // The number of handlers that share a reference to the state.
  148. atomic_count ref_count_;
  149. // The handler to be called when the operation completes.
  150. Handler handler_;
  151. // The timer used to determine when to cancel the pending operation.
  152. Timer timer_;
  153. // The cancellation signal and type used to cancel the pending operation.
  154. cancellation_signal cancellation_signal_;
  155. cancellation_type_t cancellation_type_;
  156. // A proxy cancel handler used to allow cancellation of the timed operation.
  157. cancel_proxy* cancel_proxy_;
  158. // Arguments to be passed to the completion handler.
  159. union payload_storage
  160. {
  161. payload_storage() {}
  162. ~payload_storage() {}
  163. char dummy_;
  164. payload_type payload_;
  165. } payload_storage_;
  166. // Whether the payload storage contains a valid payload.
  167. bool has_payload_;
  168. // Whether the asynchronous wait on the timer is still pending
  169. bool has_pending_timer_wait_;
  170. };
  171. template <typename Op, typename R, typename... Args>
  172. class timed_cancel_op_handler<Op, R(Args...)>
  173. {
  174. public:
  175. using cancellation_slot_type = cancellation_slot;
  176. explicit timed_cancel_op_handler(Op* op)
  177. : op_(op)
  178. {
  179. }
  180. timed_cancel_op_handler(timed_cancel_op_handler&& other) noexcept
  181. : op_(other.op_)
  182. {
  183. other.op_ = nullptr;
  184. }
  185. ~timed_cancel_op_handler()
  186. {
  187. if (op_)
  188. op_->release();
  189. }
  190. cancellation_slot_type get_cancellation_slot() const noexcept
  191. {
  192. return op_->get_cancellation_slot();
  193. }
  194. template <typename... Args2>
  195. enable_if_t<
  196. is_constructible<completion_message<R(Args...)>, int, Args2...>::value
  197. > operator()(Args2&&... args)
  198. {
  199. Op* op = op_;
  200. op_ = nullptr;
  201. typedef completion_message<R(Args...)> message_type;
  202. op->handle_op(message_type(0, static_cast<Args2&&>(args)...));
  203. }
  204. //protected:
  205. Op* op_;
  206. };
  207. template <typename Op, typename R, typename... Args, typename... Signatures>
  208. class timed_cancel_op_handler<Op, R(Args...), Signatures...> :
  209. public timed_cancel_op_handler<Op, Signatures...>
  210. {
  211. public:
  212. using timed_cancel_op_handler<Op, Signatures...>::timed_cancel_op_handler;
  213. using timed_cancel_op_handler<Op, Signatures...>::operator();
  214. template <typename... Args2>
  215. enable_if_t<
  216. is_constructible<completion_message<R(Args...)>, int, Args2...>::value
  217. > operator()(Args2&&... args)
  218. {
  219. Op* op = this->op_;
  220. this->op_ = nullptr;
  221. typedef completion_message<R(Args...)> message_type;
  222. op->handle_op(message_type(0, static_cast<Args2&&>(args)...));
  223. }
  224. };
  225. template <typename Op>
  226. class timed_cancel_timer_handler
  227. {
  228. public:
  229. using cancellation_slot_type = cancellation_slot;
  230. explicit timed_cancel_timer_handler(Op* op)
  231. : op_(op)
  232. {
  233. }
  234. timed_cancel_timer_handler(timed_cancel_timer_handler&& other) noexcept
  235. : op_(other.op_)
  236. {
  237. other.op_ = nullptr;
  238. }
  239. ~timed_cancel_timer_handler()
  240. {
  241. if (op_)
  242. op_->release();
  243. }
  244. cancellation_slot_type get_cancellation_slot() const noexcept
  245. {
  246. return cancellation_slot_type();
  247. }
  248. void operator()(const boost::system::error_code&)
  249. {
  250. Op* op = op_;
  251. op_ = nullptr;
  252. op->handle_timer();
  253. }
  254. //private:
  255. Op* op_;
  256. };
  257. } // namespace detail
  258. template <template <typename, typename> class Associator,
  259. typename Op, typename... Signatures, typename DefaultCandidate>
  260. struct associator<Associator,
  261. detail::timed_cancel_op_handler<Op, Signatures...>, DefaultCandidate>
  262. : Associator<typename Op::handler_type, DefaultCandidate>
  263. {
  264. static typename Associator<typename Op::handler_type, DefaultCandidate>::type
  265. get(const detail::timed_cancel_op_handler<Op, Signatures...>& h) noexcept
  266. {
  267. return Associator<typename Op::handler_type, DefaultCandidate>::get(
  268. h.op_->handler_);
  269. }
  270. static auto get(const detail::timed_cancel_op_handler<Op, Signatures...>& h,
  271. const DefaultCandidate& c) noexcept
  272. -> decltype(Associator<typename Op::handler_type, DefaultCandidate>::get(
  273. h.op_->handler_, c))
  274. {
  275. return Associator<typename Op::handler_type, DefaultCandidate>::get(
  276. h.op_->handler_, c);
  277. }
  278. };
  279. template <template <typename, typename> class Associator,
  280. typename Op, typename DefaultCandidate>
  281. struct associator<Associator,
  282. detail::timed_cancel_timer_handler<Op>, DefaultCandidate>
  283. : Associator<typename Op::handler_type, DefaultCandidate>
  284. {
  285. static typename Associator<typename Op::handler_type, DefaultCandidate>::type
  286. get(const detail::timed_cancel_timer_handler<Op>& h) noexcept
  287. {
  288. return Associator<typename Op::handler_type, DefaultCandidate>::get(
  289. h.op_->handler_);
  290. }
  291. static auto get(const detail::timed_cancel_timer_handler<Op>& h,
  292. const DefaultCandidate& c) noexcept
  293. -> decltype(Associator<typename Op::handler_type, DefaultCandidate>::get(
  294. h.op_->handler_, c))
  295. {
  296. return Associator<typename Op::handler_type, DefaultCandidate>::get(
  297. h.op_->handler_, c);
  298. }
  299. };
  300. } // namespace asio
  301. } // namespace boost
  302. #include <boost/asio/detail/pop_options.hpp>
  303. #endif // BOOST_ASIO_DETAIL_TIMED_CANCEL_OP_HPP