handler_work.hpp 13 KB

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