channel_operation.hpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. //
  2. // experimental/detail/channel_operation.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_EXPERIMENTAL_DETAIL_CHANNEL_OPERATION_HPP
  11. #define BOOST_ASIO_EXPERIMENTAL_DETAIL_CHANNEL_OPERATION_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_allocator.hpp>
  17. #include <boost/asio/associated_executor.hpp>
  18. #include <boost/asio/associated_immediate_executor.hpp>
  19. #include <boost/asio/detail/initiate_post.hpp>
  20. #include <boost/asio/detail/initiate_dispatch.hpp>
  21. #include <boost/asio/detail/op_queue.hpp>
  22. #include <boost/asio/detail/type_traits.hpp>
  23. #include <boost/asio/execution/executor.hpp>
  24. #include <boost/asio/execution/outstanding_work.hpp>
  25. #include <boost/asio/executor_work_guard.hpp>
  26. #include <boost/asio/prefer.hpp>
  27. #include <boost/asio/detail/push_options.hpp>
  28. namespace boost {
  29. namespace asio {
  30. namespace experimental {
  31. namespace detail {
  32. // Base class for all channel operations. A function pointer is used instead of
  33. // virtual functions to avoid the associated overhead.
  34. class channel_operation BOOST_ASIO_INHERIT_TRACKED_HANDLER
  35. {
  36. public:
  37. template <typename Executor, typename = void, typename = void>
  38. class handler_work_base;
  39. template <typename Handler, typename IoExecutor, typename = void>
  40. class handler_work;
  41. void destroy()
  42. {
  43. func_(this, destroy_op, 0);
  44. }
  45. protected:
  46. enum action
  47. {
  48. destroy_op = 0,
  49. immediate_op = 1,
  50. post_op = 2,
  51. dispatch_op = 3,
  52. cancel_op = 4,
  53. close_op = 5
  54. };
  55. typedef void (*func_type)(channel_operation*, action, void*);
  56. channel_operation(func_type func)
  57. : next_(0),
  58. func_(func),
  59. cancellation_key_(0)
  60. {
  61. }
  62. // Prevents deletion through this type.
  63. ~channel_operation()
  64. {
  65. }
  66. friend class boost::asio::detail::op_queue_access;
  67. channel_operation* next_;
  68. func_type func_;
  69. public:
  70. // The operation key used for targeted cancellation.
  71. void* cancellation_key_;
  72. };
  73. template <typename Executor, typename, typename>
  74. class channel_operation::handler_work_base
  75. {
  76. public:
  77. typedef decay_t<
  78. prefer_result_t<Executor,
  79. execution::outstanding_work_t::tracked_t
  80. >
  81. > executor_type;
  82. handler_work_base(int, const Executor& ex)
  83. : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
  84. {
  85. }
  86. const executor_type& get_executor() const noexcept
  87. {
  88. return executor_;
  89. }
  90. template <typename IoExecutor, typename Function, typename Handler>
  91. void post(const IoExecutor& io_exec, Function& function, Handler&)
  92. {
  93. (boost::asio::detail::initiate_post_with_executor<IoExecutor>(io_exec))(
  94. static_cast<Function&&>(function));
  95. }
  96. template <typename Function, typename Handler>
  97. void dispatch(Function& function, Handler& handler)
  98. {
  99. associated_allocator_t<Handler> allocator =
  100. (get_associated_allocator)(handler);
  101. boost::asio::prefer(executor_,
  102. execution::allocator(allocator)
  103. ).execute(static_cast<Function&&>(function));
  104. }
  105. private:
  106. executor_type executor_;
  107. };
  108. template <typename Executor>
  109. class channel_operation::handler_work_base<Executor,
  110. enable_if_t<
  111. execution::is_executor<Executor>::value
  112. >,
  113. enable_if_t<
  114. can_require<Executor, execution::blocking_t::never_t>::value
  115. >
  116. >
  117. {
  118. public:
  119. typedef decay_t<
  120. prefer_result_t<Executor,
  121. execution::outstanding_work_t::tracked_t
  122. >
  123. > executor_type;
  124. handler_work_base(int, const Executor& ex)
  125. : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
  126. {
  127. }
  128. const executor_type& get_executor() const noexcept
  129. {
  130. return executor_;
  131. }
  132. template <typename IoExecutor, typename Function, typename Handler>
  133. void post(const IoExecutor&, Function& function, Handler& handler)
  134. {
  135. associated_allocator_t<Handler> allocator =
  136. (get_associated_allocator)(handler);
  137. boost::asio::prefer(
  138. boost::asio::require(executor_, execution::blocking.never),
  139. execution::allocator(allocator)
  140. ).execute(static_cast<Function&&>(function));
  141. }
  142. template <typename Function, typename Handler>
  143. void dispatch(Function& function, Handler& handler)
  144. {
  145. associated_allocator_t<Handler> allocator =
  146. (get_associated_allocator)(handler);
  147. boost::asio::prefer(executor_,
  148. execution::allocator(allocator)
  149. ).execute(static_cast<Function&&>(function));
  150. }
  151. private:
  152. executor_type executor_;
  153. };
  154. #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
  155. template <typename Executor>
  156. class channel_operation::handler_work_base<Executor,
  157. enable_if_t<
  158. !execution::is_executor<Executor>::value
  159. >
  160. >
  161. {
  162. public:
  163. typedef Executor executor_type;
  164. handler_work_base(int, const Executor& ex)
  165. : work_(ex)
  166. {
  167. }
  168. executor_type get_executor() const noexcept
  169. {
  170. return work_.get_executor();
  171. }
  172. template <typename IoExecutor, typename Function, typename Handler>
  173. void post(const IoExecutor&, Function& function, Handler& handler)
  174. {
  175. associated_allocator_t<Handler> allocator =
  176. (get_associated_allocator)(handler);
  177. work_.get_executor().post(
  178. static_cast<Function&&>(function), allocator);
  179. }
  180. template <typename Function, typename Handler>
  181. void dispatch(Function& function, Handler& handler)
  182. {
  183. associated_allocator_t<Handler> allocator =
  184. (get_associated_allocator)(handler);
  185. work_.get_executor().dispatch(
  186. static_cast<Function&&>(function), allocator);
  187. }
  188. private:
  189. executor_work_guard<Executor> work_;
  190. };
  191. #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
  192. template <typename Handler, typename IoExecutor, typename>
  193. class channel_operation::handler_work :
  194. channel_operation::handler_work_base<IoExecutor>,
  195. channel_operation::handler_work_base<
  196. associated_executor_t<Handler, IoExecutor>, IoExecutor>
  197. {
  198. public:
  199. typedef channel_operation::handler_work_base<IoExecutor> base1_type;
  200. typedef channel_operation::handler_work_base<
  201. associated_executor_t<Handler, IoExecutor>, IoExecutor>
  202. base2_type;
  203. handler_work(Handler& handler, const IoExecutor& io_ex) noexcept
  204. : base1_type(0, io_ex),
  205. base2_type(0, (get_associated_executor)(handler, io_ex))
  206. {
  207. }
  208. template <typename Function>
  209. void post(Function& function, Handler& handler)
  210. {
  211. base2_type::post(base1_type::get_executor(), function, handler);
  212. }
  213. template <typename Function>
  214. void dispatch(Function& function, Handler& handler)
  215. {
  216. base2_type::dispatch(function, handler);
  217. }
  218. template <typename Function>
  219. void immediate(Function& function, Handler& handler, ...)
  220. {
  221. typedef associated_immediate_executor_t<Handler,
  222. typename base1_type::executor_type> immediate_ex_type;
  223. immediate_ex_type immediate_ex = (get_associated_immediate_executor)(
  224. handler, base1_type::get_executor());
  225. (boost::asio::detail::initiate_dispatch_with_executor<immediate_ex_type>(
  226. immediate_ex))(static_cast<Function&&>(function));
  227. }
  228. template <typename Function>
  229. void immediate(Function& function, Handler&,
  230. enable_if_t<
  231. is_same<
  232. typename associated_immediate_executor<
  233. conditional_t<false, Function, Handler>,
  234. typename base1_type::executor_type>::
  235. asio_associated_immediate_executor_is_unspecialised,
  236. void
  237. >::value
  238. >*)
  239. {
  240. (boost::asio::detail::initiate_post_with_executor<
  241. typename base1_type::executor_type>(
  242. base1_type::get_executor()))(
  243. static_cast<Function&&>(function));
  244. }
  245. };
  246. template <typename Handler, typename IoExecutor>
  247. class channel_operation::handler_work<
  248. Handler, IoExecutor,
  249. enable_if_t<
  250. is_same<
  251. typename associated_executor<Handler,
  252. IoExecutor>::asio_associated_executor_is_unspecialised,
  253. void
  254. >::value
  255. >
  256. > : handler_work_base<IoExecutor>
  257. {
  258. public:
  259. typedef channel_operation::handler_work_base<IoExecutor> base1_type;
  260. handler_work(Handler&, const IoExecutor& io_ex) noexcept
  261. : base1_type(0, io_ex)
  262. {
  263. }
  264. template <typename Function>
  265. void post(Function& function, Handler& handler)
  266. {
  267. base1_type::post(base1_type::get_executor(), function, handler);
  268. }
  269. template <typename Function>
  270. void dispatch(Function& function, Handler& handler)
  271. {
  272. base1_type::dispatch(function, handler);
  273. }
  274. template <typename Function>
  275. void immediate(Function& function, Handler& handler, ...)
  276. {
  277. typedef associated_immediate_executor_t<Handler,
  278. typename base1_type::executor_type> immediate_ex_type;
  279. immediate_ex_type immediate_ex = (get_associated_immediate_executor)(
  280. handler, base1_type::get_executor());
  281. (boost::asio::detail::initiate_dispatch_with_executor<immediate_ex_type>(
  282. immediate_ex))(static_cast<Function&&>(function));
  283. }
  284. template <typename Function>
  285. void immediate(Function& function, Handler& handler,
  286. enable_if_t<
  287. is_same<
  288. typename associated_immediate_executor<
  289. conditional_t<false, Function, Handler>,
  290. typename base1_type::executor_type>::
  291. asio_associated_immediate_executor_is_unspecialised,
  292. void
  293. >::value
  294. >*)
  295. {
  296. base1_type::post(base1_type::get_executor(), function, handler);
  297. }
  298. };
  299. } // namespace detail
  300. } // namespace experimental
  301. } // namespace asio
  302. } // namespace boost
  303. #include <boost/asio/detail/pop_options.hpp>
  304. #endif // BOOST_ASIO_EXPERIMENTAL_DETAIL_CHANNEL_OPERATION_HPP