saved_handler.hpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. //
  2. // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // Official repository: https://github.com/boostorg/beast
  8. //
  9. #ifndef BOOST_BEAST_CORE_IMPL_SAVED_HANDLER_HPP
  10. #define BOOST_BEAST_CORE_IMPL_SAVED_HANDLER_HPP
  11. #include <boost/beast/core/detail/allocator.hpp>
  12. #include <boost/asio/associated_allocator.hpp>
  13. #include <boost/asio/associated_cancellation_slot.hpp>
  14. #include <boost/asio/associated_executor.hpp>
  15. #include <boost/asio/error.hpp>
  16. #include <boost/asio/executor_work_guard.hpp>
  17. #include <boost/assert.hpp>
  18. #include <boost/core/empty_value.hpp>
  19. #include <boost/core/exchange.hpp>
  20. #include <utility>
  21. namespace boost {
  22. namespace beast {
  23. //------------------------------------------------------------------------------
  24. class saved_handler::base
  25. {
  26. protected:
  27. ~base() = default;
  28. saved_handler * owner_;
  29. public:
  30. base(saved_handler * owner) : owner_(owner){}
  31. void set_owner(saved_handler * new_owner) { owner_ = new_owner;}
  32. virtual void destroy() = 0;
  33. virtual void invoke() = 0;
  34. };
  35. //------------------------------------------------------------------------------
  36. template<class Handler, class Alloc>
  37. class saved_handler::impl final : public base
  38. {
  39. using alloc_type = typename
  40. beast::detail::allocator_traits<
  41. Alloc>::template rebind_alloc<impl>;
  42. using alloc_traits =
  43. beast::detail::allocator_traits<alloc_type>;
  44. struct ebo_pair : boost::empty_value<alloc_type>
  45. {
  46. Handler h;
  47. template<class Handler_>
  48. ebo_pair(
  49. alloc_type const& a,
  50. Handler_&& h_)
  51. : boost::empty_value<alloc_type>(
  52. boost::empty_init_t{}, a)
  53. , h(std::forward<Handler_>(h_))
  54. {
  55. }
  56. };
  57. ebo_pair v_;
  58. #if defined(BOOST_ASIO_NO_TS_EXECUTORS)
  59. typename std::decay<decltype(net::prefer(std::declval<
  60. net::associated_executor_t<Handler>>(),
  61. net::execution::outstanding_work.tracked))>::type
  62. wg2_;
  63. #else // defined(BOOST_ASIO_NO_TS_EXECUTORS)
  64. net::executor_work_guard<
  65. net::associated_executor_t<Handler>> wg2_;
  66. #endif // defined(BOOST_ASIO_NO_TS_EXECUTORS)
  67. net::cancellation_slot slot_{net::get_associated_cancellation_slot(v_.h)};
  68. public:
  69. template<class Handler_>
  70. impl(alloc_type const& a, Handler_&& h,
  71. saved_handler * owner)
  72. : base(owner), v_(a, std::forward<Handler_>(h))
  73. #if defined(BOOST_ASIO_NO_TS_EXECUTORS)
  74. , wg2_(net::prefer(
  75. net::get_associated_executor(v_.h),
  76. net::execution::outstanding_work.tracked))
  77. #else // defined(BOOST_ASIO_NO_TS_EXECUTORS)
  78. , wg2_(net::get_associated_executor(v_.h))
  79. #endif // defined(BOOST_ASIO_NO_TS_EXECUTORS)
  80. {
  81. }
  82. ~impl()
  83. {
  84. }
  85. void
  86. destroy() override
  87. {
  88. auto v = std::move(v_);
  89. slot_.clear();
  90. alloc_traits::destroy(v.get(), this);
  91. alloc_traits::deallocate(v.get(), this, 1);
  92. }
  93. void
  94. invoke() override
  95. {
  96. slot_.clear();
  97. auto v = std::move(v_);
  98. alloc_traits::destroy(v.get(), this);
  99. alloc_traits::deallocate(v.get(), this, 1);
  100. v.h();
  101. }
  102. void self_complete()
  103. {
  104. slot_.clear();
  105. owner_->p_ = nullptr;
  106. auto v = std::move(v_);
  107. alloc_traits::destroy(v.get(), this);
  108. alloc_traits::deallocate(v.get(), this, 1);
  109. v.h(net::error::operation_aborted);
  110. }
  111. };
  112. //------------------------------------------------------------------------------
  113. template<class Handler, class Allocator>
  114. void
  115. saved_handler::
  116. emplace(Handler&& handler, Allocator const& alloc,
  117. net::cancellation_type cancel_type)
  118. {
  119. // Can't delete a handler before invoking
  120. BOOST_ASSERT(! has_value());
  121. using handler_type =
  122. typename std::decay<Handler>::type;
  123. using alloc_type = typename
  124. detail::allocator_traits<Allocator>::
  125. template rebind_alloc<impl<
  126. handler_type, Allocator>>;
  127. using alloc_traits =
  128. beast::detail::allocator_traits<alloc_type>;
  129. struct storage
  130. {
  131. alloc_type a;
  132. impl<Handler, Allocator>* p;
  133. explicit
  134. storage(Allocator const& a_)
  135. : a(a_)
  136. , p(alloc_traits::allocate(a, 1))
  137. {
  138. }
  139. ~storage()
  140. {
  141. if(p)
  142. alloc_traits::deallocate(a, p, 1);
  143. }
  144. };
  145. auto cancel_slot = net::get_associated_cancellation_slot(handler);
  146. storage s(alloc);
  147. alloc_traits::construct(s.a, s.p,
  148. s.a, std::forward<Handler>(handler), this);
  149. auto tmp = boost::exchange(s.p, nullptr);
  150. p_ = tmp;
  151. if (cancel_slot.is_connected())
  152. {
  153. struct cancel_op
  154. {
  155. impl<Handler, Allocator>* p;
  156. net::cancellation_type accepted_ct;
  157. cancel_op(impl<Handler, Allocator>* p,
  158. net::cancellation_type accepted_ct)
  159. : p(p), accepted_ct(accepted_ct) {}
  160. void operator()(net::cancellation_type ct)
  161. {
  162. if ((ct & accepted_ct) != net::cancellation_type::none)
  163. p->self_complete();
  164. }
  165. };
  166. cancel_slot.template emplace<cancel_op>(tmp, cancel_type);
  167. }
  168. }
  169. template<class Handler>
  170. void
  171. saved_handler::
  172. emplace(Handler&& handler, net::cancellation_type cancel_type)
  173. {
  174. // Can't delete a handler before invoking
  175. BOOST_ASSERT(! has_value());
  176. emplace(
  177. std::forward<Handler>(handler),
  178. net::get_associated_allocator(handler),
  179. cancel_type);
  180. }
  181. } // beast
  182. } // boost
  183. #endif