channel_operation.hpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. //
  2. // experimental/detail/channel_operation.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2025 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. boost::asio::detail::empty_work_function());
  96. }
  97. template <typename Function, typename Handler>
  98. void dispatch(Function& function, Handler& handler)
  99. {
  100. associated_allocator_t<Handler> allocator =
  101. (get_associated_allocator)(handler);
  102. boost::asio::prefer(executor_,
  103. execution::allocator(allocator)
  104. ).execute(static_cast<Function&&>(function));
  105. }
  106. private:
  107. executor_type executor_;
  108. };
  109. template <typename Executor>
  110. class channel_operation::handler_work_base<Executor,
  111. enable_if_t<
  112. execution::is_executor<Executor>::value
  113. >,
  114. enable_if_t<
  115. can_require<Executor, execution::blocking_t::never_t>::value
  116. >
  117. >
  118. {
  119. public:
  120. typedef decay_t<
  121. prefer_result_t<Executor,
  122. execution::outstanding_work_t::tracked_t
  123. >
  124. > executor_type;
  125. handler_work_base(int, const Executor& ex)
  126. : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
  127. {
  128. }
  129. const executor_type& get_executor() const noexcept
  130. {
  131. return executor_;
  132. }
  133. template <typename IoExecutor, typename Function, typename Handler>
  134. void post(const IoExecutor&, Function& function, Handler& handler)
  135. {
  136. associated_allocator_t<Handler> allocator =
  137. (get_associated_allocator)(handler);
  138. boost::asio::prefer(
  139. boost::asio::require(executor_, execution::blocking.never),
  140. execution::allocator(allocator)
  141. ).execute(static_cast<Function&&>(function));
  142. }
  143. template <typename Function, typename Handler>
  144. void dispatch(Function& function, Handler& handler)
  145. {
  146. associated_allocator_t<Handler> allocator =
  147. (get_associated_allocator)(handler);
  148. boost::asio::prefer(executor_,
  149. execution::allocator(allocator)
  150. ).execute(static_cast<Function&&>(function));
  151. }
  152. private:
  153. executor_type executor_;
  154. };
  155. #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
  156. template <typename Executor>
  157. class channel_operation::handler_work_base<Executor,
  158. enable_if_t<
  159. !execution::is_executor<Executor>::value
  160. >
  161. >
  162. {
  163. public:
  164. typedef Executor executor_type;
  165. handler_work_base(int, const Executor& ex)
  166. : work_(ex)
  167. {
  168. }
  169. executor_type get_executor() const noexcept
  170. {
  171. return work_.get_executor();
  172. }
  173. template <typename IoExecutor, typename Function, typename Handler>
  174. void post(const IoExecutor&, Function& function, Handler& handler)
  175. {
  176. associated_allocator_t<Handler> allocator =
  177. (get_associated_allocator)(handler);
  178. work_.get_executor().post(
  179. static_cast<Function&&>(function), allocator);
  180. }
  181. template <typename Function, typename Handler>
  182. void dispatch(Function& function, Handler& handler)
  183. {
  184. associated_allocator_t<Handler> allocator =
  185. (get_associated_allocator)(handler);
  186. work_.get_executor().dispatch(
  187. static_cast<Function&&>(function), allocator);
  188. }
  189. private:
  190. executor_work_guard<Executor> work_;
  191. };
  192. #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
  193. template <typename Handler, typename IoExecutor, typename>
  194. class channel_operation::handler_work :
  195. channel_operation::handler_work_base<IoExecutor>,
  196. channel_operation::handler_work_base<
  197. associated_executor_t<Handler, IoExecutor>, IoExecutor>
  198. {
  199. public:
  200. typedef channel_operation::handler_work_base<IoExecutor> base1_type;
  201. typedef channel_operation::handler_work_base<
  202. associated_executor_t<Handler, IoExecutor>, IoExecutor>
  203. base2_type;
  204. handler_work(Handler& handler, const IoExecutor& io_ex) noexcept
  205. : base1_type(0, io_ex),
  206. base2_type(0, (get_associated_executor)(handler, io_ex))
  207. {
  208. }
  209. template <typename Function>
  210. void post(Function& function, Handler& handler)
  211. {
  212. base2_type::post(base1_type::get_executor(), function, handler);
  213. }
  214. template <typename Function>
  215. void dispatch(Function& function, Handler& handler)
  216. {
  217. base2_type::dispatch(function, handler);
  218. }
  219. template <typename Function>
  220. void immediate(Function& function, Handler& handler, ...)
  221. {
  222. typedef associated_immediate_executor_t<Handler,
  223. typename base1_type::executor_type> immediate_ex_type;
  224. immediate_ex_type immediate_ex = (get_associated_immediate_executor)(
  225. handler, base1_type::get_executor());
  226. (boost::asio::detail::initiate_dispatch_with_executor<
  227. immediate_ex_type>(immediate_ex))(
  228. static_cast<Function&&>(function),
  229. boost::asio::detail::empty_work_function());
  230. }
  231. template <typename Function>
  232. void immediate(Function& function, Handler&,
  233. enable_if_t<
  234. is_same<
  235. typename associated_immediate_executor<
  236. conditional_t<false, Function, Handler>,
  237. typename base1_type::executor_type>::
  238. asio_associated_immediate_executor_is_unspecialised,
  239. void
  240. >::value
  241. >*)
  242. {
  243. (boost::asio::detail::initiate_post_with_executor<
  244. typename base1_type::executor_type>(
  245. base1_type::get_executor()))(
  246. static_cast<Function&&>(function),
  247. boost::asio::detail::empty_work_function());
  248. }
  249. };
  250. template <typename Handler, typename IoExecutor>
  251. class channel_operation::handler_work<
  252. Handler, IoExecutor,
  253. enable_if_t<
  254. is_same<
  255. typename associated_executor<Handler,
  256. IoExecutor>::asio_associated_executor_is_unspecialised,
  257. void
  258. >::value
  259. >
  260. > : handler_work_base<IoExecutor>
  261. {
  262. public:
  263. typedef channel_operation::handler_work_base<IoExecutor> base1_type;
  264. handler_work(Handler&, const IoExecutor& io_ex) noexcept
  265. : base1_type(0, io_ex)
  266. {
  267. }
  268. template <typename Function>
  269. void post(Function& function, Handler& handler)
  270. {
  271. base1_type::post(base1_type::get_executor(), function, handler);
  272. }
  273. template <typename Function>
  274. void dispatch(Function& function, Handler& handler)
  275. {
  276. base1_type::dispatch(function, handler);
  277. }
  278. template <typename Function>
  279. void immediate(Function& function, Handler& handler, ...)
  280. {
  281. typedef associated_immediate_executor_t<Handler,
  282. typename base1_type::executor_type> immediate_ex_type;
  283. immediate_ex_type immediate_ex = (get_associated_immediate_executor)(
  284. handler, base1_type::get_executor());
  285. (boost::asio::detail::initiate_dispatch_with_executor<
  286. immediate_ex_type>(immediate_ex))(
  287. static_cast<Function&&>(function),
  288. boost::asio::detail::empty_work_function());
  289. }
  290. template <typename Function>
  291. void immediate(Function& function, Handler& handler,
  292. enable_if_t<
  293. is_same<
  294. typename associated_immediate_executor<
  295. conditional_t<false, Function, Handler>,
  296. typename base1_type::executor_type>::
  297. asio_associated_immediate_executor_is_unspecialised,
  298. void
  299. >::value
  300. >*)
  301. {
  302. base1_type::post(base1_type::get_executor(), function, handler);
  303. }
  304. };
  305. } // namespace detail
  306. } // namespace experimental
  307. } // namespace asio
  308. } // namespace boost
  309. #include <boost/asio/detail/pop_options.hpp>
  310. #endif // BOOST_ASIO_EXPERIMENTAL_DETAIL_CHANNEL_OPERATION_HPP