handler_work.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. //
  2. // detail/handler_work.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_HANDLER_WORK_HPP
  11. #define BOOST_ASIO_DETAIL_HANDLER_WORK_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_dispatch.hpp>
  20. #include <boost/asio/detail/type_traits.hpp>
  21. #include <boost/asio/detail/work_dispatcher.hpp>
  22. #include <boost/asio/execution/allocator.hpp>
  23. #include <boost/asio/execution/blocking.hpp>
  24. #include <boost/asio/execution/executor.hpp>
  25. #include <boost/asio/execution/outstanding_work.hpp>
  26. #include <boost/asio/executor_work_guard.hpp>
  27. #include <boost/asio/prefer.hpp>
  28. #include <boost/asio/detail/push_options.hpp>
  29. namespace boost {
  30. namespace asio {
  31. class executor;
  32. class io_context;
  33. #if !defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
  34. class any_completion_executor;
  35. class any_io_executor;
  36. #endif // !defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
  37. namespace execution {
  38. template <typename...> class any_executor;
  39. } // namespace execution
  40. namespace detail {
  41. template <typename Executor, typename CandidateExecutor = void,
  42. typename IoContext = io_context,
  43. typename PolymorphicExecutor = executor, typename = void>
  44. class handler_work_base
  45. {
  46. public:
  47. explicit handler_work_base(int, int, const Executor& ex) noexcept
  48. : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
  49. {
  50. }
  51. template <typename OtherExecutor>
  52. handler_work_base(bool /*base1_owns_work*/, const Executor& ex,
  53. const OtherExecutor& /*candidate*/) noexcept
  54. : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
  55. {
  56. }
  57. handler_work_base(const handler_work_base& other) noexcept
  58. : executor_(other.executor_)
  59. {
  60. }
  61. handler_work_base(handler_work_base&& other) noexcept
  62. : executor_(static_cast<executor_type&&>(other.executor_))
  63. {
  64. }
  65. bool owns_work() const noexcept
  66. {
  67. return true;
  68. }
  69. template <typename Function, typename Handler>
  70. void dispatch(Function& function, Handler& handler)
  71. {
  72. boost::asio::prefer(executor_,
  73. execution::allocator((get_associated_allocator)(handler))
  74. ).execute(static_cast<Function&&>(function));
  75. }
  76. private:
  77. typedef decay_t<
  78. prefer_result_t<Executor, execution::outstanding_work_t::tracked_t>
  79. > executor_type;
  80. executor_type executor_;
  81. };
  82. template <typename Executor, typename CandidateExecutor,
  83. typename IoContext, typename PolymorphicExecutor>
  84. class handler_work_base<Executor, CandidateExecutor,
  85. IoContext, PolymorphicExecutor,
  86. enable_if_t<
  87. !execution::is_executor<Executor>::value
  88. && (!is_same<Executor, PolymorphicExecutor>::value
  89. || !is_same<CandidateExecutor, void>::value)
  90. >
  91. >
  92. {
  93. public:
  94. explicit handler_work_base(int, int, const Executor& ex) noexcept
  95. : executor_(ex),
  96. owns_work_(true)
  97. {
  98. executor_.on_work_started();
  99. }
  100. handler_work_base(bool /*base1_owns_work*/, const Executor& ex,
  101. const Executor& candidate) noexcept
  102. : executor_(ex),
  103. owns_work_(ex != candidate)
  104. {
  105. if (owns_work_)
  106. executor_.on_work_started();
  107. }
  108. template <typename OtherExecutor>
  109. handler_work_base(bool /*base1_owns_work*/, const Executor& ex,
  110. const OtherExecutor& /*candidate*/) noexcept
  111. : executor_(ex),
  112. owns_work_(true)
  113. {
  114. executor_.on_work_started();
  115. }
  116. handler_work_base(const handler_work_base& other) noexcept
  117. : executor_(other.executor_),
  118. owns_work_(other.owns_work_)
  119. {
  120. if (owns_work_)
  121. executor_.on_work_started();
  122. }
  123. handler_work_base(handler_work_base&& other) noexcept
  124. : executor_(static_cast<Executor&&>(other.executor_)),
  125. owns_work_(other.owns_work_)
  126. {
  127. other.owns_work_ = false;
  128. }
  129. ~handler_work_base()
  130. {
  131. if (owns_work_)
  132. executor_.on_work_finished();
  133. }
  134. bool owns_work() const noexcept
  135. {
  136. return owns_work_;
  137. }
  138. template <typename Function, typename Handler>
  139. void dispatch(Function& function, Handler& handler)
  140. {
  141. executor_.dispatch(static_cast<Function&&>(function),
  142. boost::asio::get_associated_allocator(handler));
  143. }
  144. private:
  145. Executor executor_;
  146. bool owns_work_;
  147. };
  148. template <typename Executor, typename IoContext, typename PolymorphicExecutor>
  149. class handler_work_base<Executor, void, IoContext, PolymorphicExecutor,
  150. enable_if_t<
  151. is_same<
  152. Executor,
  153. typename IoContext::executor_type
  154. >::value
  155. >
  156. >
  157. {
  158. public:
  159. explicit handler_work_base(int, int, const Executor&)
  160. {
  161. }
  162. bool owns_work() const noexcept
  163. {
  164. return false;
  165. }
  166. template <typename Function, typename Handler>
  167. void dispatch(Function& function, Handler&)
  168. {
  169. // When using a native implementation, I/O completion handlers are
  170. // already dispatched according to the execution context's executor's
  171. // rules. We can call the function directly.
  172. static_cast<Function&&>(function)();
  173. }
  174. };
  175. template <typename Executor, typename IoContext>
  176. class handler_work_base<Executor, void, IoContext, Executor>
  177. {
  178. public:
  179. explicit handler_work_base(int, int, const Executor& ex) noexcept
  180. #if !defined(BOOST_ASIO_NO_TYPEID)
  181. : executor_(
  182. ex.target_type() == typeid(typename IoContext::executor_type)
  183. ? Executor() : ex)
  184. #else // !defined(BOOST_ASIO_NO_TYPEID)
  185. : executor_(ex)
  186. #endif // !defined(BOOST_ASIO_NO_TYPEID)
  187. {
  188. if (executor_)
  189. executor_.on_work_started();
  190. }
  191. handler_work_base(bool /*base1_owns_work*/, const Executor& ex,
  192. const Executor& candidate) noexcept
  193. : executor_(ex != candidate ? ex : Executor())
  194. {
  195. if (executor_)
  196. executor_.on_work_started();
  197. }
  198. template <typename OtherExecutor>
  199. handler_work_base(const Executor& ex,
  200. const OtherExecutor&) noexcept
  201. : executor_(ex)
  202. {
  203. executor_.on_work_started();
  204. }
  205. handler_work_base(const handler_work_base& other) noexcept
  206. : executor_(other.executor_)
  207. {
  208. if (executor_)
  209. executor_.on_work_started();
  210. }
  211. handler_work_base(handler_work_base&& other) noexcept
  212. : executor_(static_cast<Executor&&>(other.executor_))
  213. {
  214. }
  215. ~handler_work_base()
  216. {
  217. if (executor_)
  218. executor_.on_work_finished();
  219. }
  220. bool owns_work() const noexcept
  221. {
  222. return !!executor_;
  223. }
  224. template <typename Function, typename Handler>
  225. void dispatch(Function& function, Handler& handler)
  226. {
  227. executor_.dispatch(static_cast<Function&&>(function),
  228. boost::asio::get_associated_allocator(handler));
  229. }
  230. private:
  231. Executor executor_;
  232. };
  233. template <typename... SupportableProperties, typename CandidateExecutor,
  234. typename IoContext, typename PolymorphicExecutor>
  235. class handler_work_base<execution::any_executor<SupportableProperties...>,
  236. CandidateExecutor, IoContext, PolymorphicExecutor>
  237. {
  238. public:
  239. typedef execution::any_executor<SupportableProperties...> executor_type;
  240. explicit handler_work_base(int, int, const executor_type& ex) noexcept
  241. #if !defined(BOOST_ASIO_NO_TYPEID)
  242. : executor_(
  243. ex.target_type() == typeid(typename IoContext::executor_type)
  244. ? executor_type()
  245. : boost::asio::prefer(ex, execution::outstanding_work.tracked))
  246. #else // !defined(BOOST_ASIO_NO_TYPEID)
  247. : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
  248. #endif // !defined(BOOST_ASIO_NO_TYPEID)
  249. {
  250. }
  251. handler_work_base(bool base1_owns_work, const executor_type& ex,
  252. const executor_type& candidate) noexcept
  253. : executor_(
  254. !base1_owns_work && ex == candidate
  255. ? executor_type()
  256. : boost::asio::prefer(ex, execution::outstanding_work.tracked))
  257. {
  258. }
  259. template <typename OtherExecutor>
  260. handler_work_base(bool /*base1_owns_work*/, const executor_type& ex,
  261. const OtherExecutor& /*candidate*/) noexcept
  262. : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
  263. {
  264. }
  265. handler_work_base(const handler_work_base& other) noexcept
  266. : executor_(other.executor_)
  267. {
  268. }
  269. handler_work_base(handler_work_base&& other) noexcept
  270. : executor_(static_cast<executor_type&&>(other.executor_))
  271. {
  272. }
  273. bool owns_work() const noexcept
  274. {
  275. return !!executor_;
  276. }
  277. template <typename Function, typename Handler>
  278. void dispatch(Function& function, Handler&)
  279. {
  280. executor_.execute(static_cast<Function&&>(function));
  281. }
  282. private:
  283. executor_type executor_;
  284. };
  285. #if !defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
  286. template <typename Executor, typename CandidateExecutor,
  287. typename IoContext, typename PolymorphicExecutor>
  288. class handler_work_base<
  289. Executor, CandidateExecutor,
  290. IoContext, PolymorphicExecutor,
  291. enable_if_t<
  292. is_same<Executor, any_completion_executor>::value
  293. || is_same<Executor, any_io_executor>::value
  294. >
  295. >
  296. {
  297. public:
  298. typedef Executor executor_type;
  299. explicit handler_work_base(int, int,
  300. const executor_type& ex) noexcept
  301. #if !defined(BOOST_ASIO_NO_TYPEID)
  302. : executor_(
  303. ex.target_type() == typeid(typename IoContext::executor_type)
  304. ? executor_type()
  305. : boost::asio::prefer(ex, execution::outstanding_work.tracked))
  306. #else // !defined(BOOST_ASIO_NO_TYPEID)
  307. : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
  308. #endif // !defined(BOOST_ASIO_NO_TYPEID)
  309. {
  310. }
  311. handler_work_base(bool base1_owns_work, const executor_type& ex,
  312. const executor_type& candidate) noexcept
  313. : executor_(
  314. !base1_owns_work && ex == candidate
  315. ? executor_type()
  316. : boost::asio::prefer(ex, execution::outstanding_work.tracked))
  317. {
  318. }
  319. template <typename OtherExecutor>
  320. handler_work_base(bool /*base1_owns_work*/, const executor_type& ex,
  321. const OtherExecutor& /*candidate*/) noexcept
  322. : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
  323. {
  324. }
  325. handler_work_base(const handler_work_base& other) noexcept
  326. : executor_(other.executor_)
  327. {
  328. }
  329. handler_work_base(handler_work_base&& other) noexcept
  330. : executor_(static_cast<executor_type&&>(other.executor_))
  331. {
  332. }
  333. bool owns_work() const noexcept
  334. {
  335. return !!executor_;
  336. }
  337. template <typename Function, typename Handler>
  338. void dispatch(Function& function, Handler&)
  339. {
  340. executor_.execute(static_cast<Function&&>(function));
  341. }
  342. private:
  343. executor_type executor_;
  344. };
  345. #endif // !defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
  346. template <typename Handler, typename IoExecutor, typename = void>
  347. class handler_work :
  348. handler_work_base<IoExecutor>,
  349. handler_work_base<associated_executor_t<Handler, IoExecutor>, IoExecutor>
  350. {
  351. public:
  352. typedef handler_work_base<IoExecutor> base1_type;
  353. typedef handler_work_base<associated_executor_t<Handler, IoExecutor>,
  354. IoExecutor> base2_type;
  355. handler_work(Handler& handler, const IoExecutor& io_ex) noexcept
  356. : base1_type(0, 0, io_ex),
  357. base2_type(base1_type::owns_work(),
  358. boost::asio::get_associated_executor(handler, io_ex), io_ex)
  359. {
  360. }
  361. template <typename Function>
  362. void complete(Function& function, Handler& handler)
  363. {
  364. if (!base1_type::owns_work() && !base2_type::owns_work())
  365. {
  366. // When using a native implementation, I/O completion handlers are
  367. // already dispatched according to the execution context's executor's
  368. // rules. We can call the function directly.
  369. static_cast<Function&&>(function)();
  370. }
  371. else
  372. {
  373. base2_type::dispatch(function, handler);
  374. }
  375. }
  376. };
  377. template <typename Handler, typename IoExecutor>
  378. class handler_work<
  379. Handler, IoExecutor,
  380. enable_if_t<
  381. is_same<
  382. typename associated_executor<Handler,
  383. IoExecutor>::asio_associated_executor_is_unspecialised,
  384. void
  385. >::value
  386. >
  387. > : handler_work_base<IoExecutor>
  388. {
  389. public:
  390. typedef handler_work_base<IoExecutor> base1_type;
  391. handler_work(Handler&, const IoExecutor& io_ex) noexcept
  392. : base1_type(0, 0, io_ex)
  393. {
  394. }
  395. template <typename Function>
  396. void complete(Function& function, Handler& handler)
  397. {
  398. if (!base1_type::owns_work())
  399. {
  400. // When using a native implementation, I/O completion handlers are
  401. // already dispatched according to the execution context's executor's
  402. // rules. We can call the function directly.
  403. static_cast<Function&&>(function)();
  404. }
  405. else
  406. {
  407. base1_type::dispatch(function, handler);
  408. }
  409. }
  410. };
  411. template <typename Handler, typename IoExecutor>
  412. class immediate_handler_work
  413. {
  414. public:
  415. typedef handler_work<Handler, IoExecutor> handler_work_type;
  416. explicit immediate_handler_work(handler_work_type&& w)
  417. : handler_work_(static_cast<handler_work_type&&>(w))
  418. {
  419. }
  420. template <typename Function>
  421. void complete(Function& function, Handler& handler, const void* io_ex)
  422. {
  423. typedef associated_immediate_executor_t<Handler, IoExecutor>
  424. immediate_ex_type;
  425. immediate_ex_type immediate_ex = (get_associated_immediate_executor)(
  426. handler, *static_cast<const IoExecutor*>(io_ex));
  427. (initiate_dispatch_with_executor<immediate_ex_type>(immediate_ex))(
  428. static_cast<Function&&>(function));
  429. }
  430. private:
  431. handler_work_type handler_work_;
  432. };
  433. } // namespace detail
  434. } // namespace asio
  435. } // namespace boost
  436. #include <boost/asio/detail/pop_options.hpp>
  437. #endif // BOOST_ASIO_DETAIL_HANDLER_WORK_HPP