system_executor.hpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671
  1. //
  2. // system_executor.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_SYSTEM_EXECUTOR_HPP
  11. #define ASIO_SYSTEM_EXECUTOR_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/detail/memory.hpp"
  17. #include "asio/execution.hpp"
  18. #include "asio/detail/push_options.hpp"
  19. namespace asio {
  20. class system_context;
  21. /// An executor that uses arbitrary threads.
  22. /**
  23. * The system executor represents an execution context where functions are
  24. * permitted to run on arbitrary threads. When the blocking.never property is
  25. * established, the system executor will schedule the function to run on an
  26. * unspecified system thread pool. When either blocking.possibly or
  27. * blocking.always is established, the executor invokes the function
  28. * immediately.
  29. */
  30. template <typename Blocking, typename Relationship, typename Allocator>
  31. class basic_system_executor
  32. {
  33. public:
  34. /// Default constructor.
  35. basic_system_executor() noexcept
  36. : allocator_(Allocator())
  37. {
  38. }
  39. #if !defined(GENERATING_DOCUMENTATION)
  40. private:
  41. friend struct asio_require_fn::impl;
  42. friend struct asio_prefer_fn::impl;
  43. #endif // !defined(GENERATING_DOCUMENTATION)
  44. /// Obtain an executor with the @c blocking.possibly property.
  45. /**
  46. * Do not call this function directly. It is intended for use with the
  47. * asio::require customisation point.
  48. *
  49. * For example:
  50. * @code asio::system_executor ex1;
  51. * auto ex2 = asio::require(ex1,
  52. * asio::execution::blocking.possibly); @endcode
  53. */
  54. basic_system_executor<execution::blocking_t::possibly_t,
  55. Relationship, Allocator>
  56. require(execution::blocking_t::possibly_t) const
  57. {
  58. return basic_system_executor<execution::blocking_t::possibly_t,
  59. Relationship, Allocator>(allocator_);
  60. }
  61. /// Obtain an executor with the @c blocking.always property.
  62. /**
  63. * Do not call this function directly. It is intended for use with the
  64. * asio::require customisation point.
  65. *
  66. * For example:
  67. * @code asio::system_executor ex1;
  68. * auto ex2 = asio::require(ex1,
  69. * asio::execution::blocking.always); @endcode
  70. */
  71. basic_system_executor<execution::blocking_t::always_t,
  72. Relationship, Allocator>
  73. require(execution::blocking_t::always_t) const
  74. {
  75. return basic_system_executor<execution::blocking_t::always_t,
  76. Relationship, Allocator>(allocator_);
  77. }
  78. /// Obtain an executor with the @c blocking.never property.
  79. /**
  80. * Do not call this function directly. It is intended for use with the
  81. * asio::require customisation point.
  82. *
  83. * For example:
  84. * @code asio::system_executor ex1;
  85. * auto ex2 = asio::require(ex1,
  86. * asio::execution::blocking.never); @endcode
  87. */
  88. basic_system_executor<execution::blocking_t::never_t,
  89. Relationship, Allocator>
  90. require(execution::blocking_t::never_t) const
  91. {
  92. return basic_system_executor<execution::blocking_t::never_t,
  93. Relationship, Allocator>(allocator_);
  94. }
  95. /// Obtain an executor with the @c relationship.continuation property.
  96. /**
  97. * Do not call this function directly. It is intended for use with the
  98. * asio::require customisation point.
  99. *
  100. * For example:
  101. * @code asio::system_executor ex1;
  102. * auto ex2 = asio::require(ex1,
  103. * asio::execution::relationship.continuation); @endcode
  104. */
  105. basic_system_executor<Blocking,
  106. execution::relationship_t::continuation_t, Allocator>
  107. require(execution::relationship_t::continuation_t) const
  108. {
  109. return basic_system_executor<Blocking,
  110. execution::relationship_t::continuation_t, Allocator>(allocator_);
  111. }
  112. /// Obtain an executor with the @c relationship.fork property.
  113. /**
  114. * Do not call this function directly. It is intended for use with the
  115. * asio::require customisation point.
  116. *
  117. * For example:
  118. * @code asio::system_executor ex1;
  119. * auto ex2 = asio::require(ex1,
  120. * asio::execution::relationship.fork); @endcode
  121. */
  122. basic_system_executor<Blocking,
  123. execution::relationship_t::fork_t, Allocator>
  124. require(execution::relationship_t::fork_t) const
  125. {
  126. return basic_system_executor<Blocking,
  127. execution::relationship_t::fork_t, Allocator>(allocator_);
  128. }
  129. /// Obtain an executor with the specified @c allocator property.
  130. /**
  131. * Do not call this function directly. It is intended for use with the
  132. * asio::require customisation point.
  133. *
  134. * For example:
  135. * @code asio::system_executor ex1;
  136. * auto ex2 = asio::require(ex1,
  137. * asio::execution::allocator(my_allocator)); @endcode
  138. */
  139. template <typename OtherAllocator>
  140. basic_system_executor<Blocking, Relationship, OtherAllocator>
  141. require(execution::allocator_t<OtherAllocator> a) const
  142. {
  143. return basic_system_executor<Blocking,
  144. Relationship, OtherAllocator>(a.value());
  145. }
  146. /// Obtain an executor with the default @c allocator property.
  147. /**
  148. * Do not call this function directly. It is intended for use with the
  149. * asio::require customisation point.
  150. *
  151. * For example:
  152. * @code asio::system_executor ex1;
  153. * auto ex2 = asio::require(ex1,
  154. * asio::execution::allocator); @endcode
  155. */
  156. basic_system_executor<Blocking, Relationship, std::allocator<void>>
  157. require(execution::allocator_t<void>) const
  158. {
  159. return basic_system_executor<Blocking,
  160. Relationship, std::allocator<void>>();
  161. }
  162. #if !defined(GENERATING_DOCUMENTATION)
  163. private:
  164. friend struct asio_query_fn::impl;
  165. friend struct asio::execution::detail::blocking_t<0>;
  166. friend struct asio::execution::detail::mapping_t<0>;
  167. friend struct asio::execution::detail::outstanding_work_t<0>;
  168. friend struct asio::execution::detail::relationship_t<0>;
  169. #endif // !defined(GENERATING_DOCUMENTATION)
  170. /// Query the current value of the @c mapping property.
  171. /**
  172. * Do not call this function directly. It is intended for use with the
  173. * asio::query customisation point.
  174. *
  175. * For example:
  176. * @code asio::system_executor ex;
  177. * if (asio::query(ex, asio::execution::mapping)
  178. * == asio::execution::mapping.thread)
  179. * ... @endcode
  180. */
  181. static constexpr execution::mapping_t query(
  182. execution::mapping_t) noexcept
  183. {
  184. return execution::mapping.thread;
  185. }
  186. /// Query the current value of the @c context property.
  187. /**
  188. * Do not call this function directly. It is intended for use with the
  189. * asio::query customisation point.
  190. *
  191. * For example:
  192. * @code asio::system_executor ex;
  193. * asio::system_context& pool = asio::query(
  194. * ex, asio::execution::context); @endcode
  195. */
  196. static system_context& query(execution::context_t) noexcept;
  197. /// Query the current value of the @c blocking property.
  198. /**
  199. * Do not call this function directly. It is intended for use with the
  200. * asio::query customisation point.
  201. *
  202. * For example:
  203. * @code asio::system_executor ex;
  204. * if (asio::query(ex, asio::execution::blocking)
  205. * == asio::execution::blocking.always)
  206. * ... @endcode
  207. */
  208. static constexpr execution::blocking_t query(
  209. execution::blocking_t) noexcept
  210. {
  211. return Blocking();
  212. }
  213. /// Query the current value of the @c relationship property.
  214. /**
  215. * Do not call this function directly. It is intended for use with the
  216. * asio::query customisation point.
  217. *
  218. * For example:
  219. * @code asio::system_executor ex;
  220. * if (asio::query(ex, asio::execution::relationship)
  221. * == asio::execution::relationship.continuation)
  222. * ... @endcode
  223. */
  224. static constexpr execution::relationship_t query(
  225. execution::relationship_t) noexcept
  226. {
  227. return Relationship();
  228. }
  229. /// Query the current value of the @c allocator property.
  230. /**
  231. * Do not call this function directly. It is intended for use with the
  232. * asio::query customisation point.
  233. *
  234. * For example:
  235. * @code asio::system_executor ex;
  236. * auto alloc = asio::query(ex,
  237. * asio::execution::allocator); @endcode
  238. */
  239. template <typename OtherAllocator>
  240. constexpr Allocator query(
  241. execution::allocator_t<OtherAllocator>) const noexcept
  242. {
  243. return allocator_;
  244. }
  245. /// Query the current value of the @c allocator property.
  246. /**
  247. * Do not call this function directly. It is intended for use with the
  248. * asio::query customisation point.
  249. *
  250. * For example:
  251. * @code asio::system_executor ex;
  252. * auto alloc = asio::query(ex,
  253. * asio::execution::allocator); @endcode
  254. */
  255. constexpr Allocator query(
  256. execution::allocator_t<void>) const noexcept
  257. {
  258. return allocator_;
  259. }
  260. /// Query the occupancy (recommended number of work items) for the system
  261. /// context.
  262. /**
  263. * Do not call this function directly. It is intended for use with the
  264. * asio::query customisation point.
  265. *
  266. * For example:
  267. * @code asio::system_executor ex;
  268. * std::size_t occupancy = asio::query(
  269. * ex, asio::execution::occupancy); @endcode
  270. */
  271. std::size_t query(execution::occupancy_t) const noexcept;
  272. public:
  273. /// Compare two executors for equality.
  274. /**
  275. * Two executors are equal if they refer to the same underlying io_context.
  276. */
  277. friend bool operator==(const basic_system_executor&,
  278. const basic_system_executor&) noexcept
  279. {
  280. return true;
  281. }
  282. /// Compare two executors for inequality.
  283. /**
  284. * Two executors are equal if they refer to the same underlying io_context.
  285. */
  286. friend bool operator!=(const basic_system_executor&,
  287. const basic_system_executor&) noexcept
  288. {
  289. return false;
  290. }
  291. /// Execution function.
  292. template <typename Function>
  293. void execute(Function&& f) const
  294. {
  295. this->do_execute(static_cast<Function&&>(f), Blocking());
  296. }
  297. #if !defined(ASIO_NO_TS_EXECUTORS)
  298. public:
  299. /// Obtain the underlying execution context.
  300. system_context& context() const noexcept;
  301. /// Inform the executor that it has some outstanding work to do.
  302. /**
  303. * For the system executor, this is a no-op.
  304. */
  305. void on_work_started() const noexcept
  306. {
  307. }
  308. /// Inform the executor that some work is no longer outstanding.
  309. /**
  310. * For the system executor, this is a no-op.
  311. */
  312. void on_work_finished() const noexcept
  313. {
  314. }
  315. /// Request the system executor to invoke the given function object.
  316. /**
  317. * This function is used to ask the executor to execute the given function
  318. * object. The function object will always be executed inside this function.
  319. *
  320. * @param f The function object to be called. The executor will make
  321. * a copy of the handler object as required. The function signature of the
  322. * function object must be: @code void function(); @endcode
  323. *
  324. * @param a An allocator that may be used by the executor to allocate the
  325. * internal storage needed for function invocation.
  326. */
  327. template <typename Function, typename OtherAllocator>
  328. void dispatch(Function&& f, const OtherAllocator& a) const;
  329. /// Request the system executor to invoke the given function object.
  330. /**
  331. * This function is used to ask the executor to execute the given function
  332. * object. The function object will never be executed inside this function.
  333. * Instead, it will be scheduled to run on an unspecified system thread pool.
  334. *
  335. * @param f The function object to be called. The executor will make
  336. * a copy of the handler object as required. The function signature of the
  337. * function object must be: @code void function(); @endcode
  338. *
  339. * @param a An allocator that may be used by the executor to allocate the
  340. * internal storage needed for function invocation.
  341. */
  342. template <typename Function, typename OtherAllocator>
  343. void post(Function&& f, const OtherAllocator& a) const;
  344. /// Request the system executor to invoke the given function object.
  345. /**
  346. * This function is used to ask the executor to execute the given function
  347. * object. The function object will never be executed inside this function.
  348. * Instead, it will be scheduled to run on an unspecified system thread pool.
  349. *
  350. * @param f The function object to be called. The executor will make
  351. * a copy of the handler object as required. The function signature of the
  352. * function object must be: @code void function(); @endcode
  353. *
  354. * @param a An allocator that may be used by the executor to allocate the
  355. * internal storage needed for function invocation.
  356. */
  357. template <typename Function, typename OtherAllocator>
  358. void defer(Function&& f, const OtherAllocator& a) const;
  359. #endif // !defined(ASIO_NO_TS_EXECUTORS)
  360. private:
  361. template <typename, typename, typename> friend class basic_system_executor;
  362. // Constructor used by require().
  363. basic_system_executor(const Allocator& a)
  364. : allocator_(a)
  365. {
  366. }
  367. /// Execution helper implementation for the possibly blocking property.
  368. template <typename Function>
  369. void do_execute(Function&& f,
  370. execution::blocking_t::possibly_t) const;
  371. /// Execution helper implementation for the always blocking property.
  372. template <typename Function>
  373. void do_execute(Function&& f,
  374. execution::blocking_t::always_t) const;
  375. /// Execution helper implementation for the never blocking property.
  376. template <typename Function>
  377. void do_execute(Function&& f,
  378. execution::blocking_t::never_t) const;
  379. // The allocator used for execution functions.
  380. Allocator allocator_;
  381. };
  382. /// An executor that uses arbitrary threads.
  383. /**
  384. * The system executor represents an execution context where functions are
  385. * permitted to run on arbitrary threads. When the blocking.never property is
  386. * established, the system executor will schedule the function to run on an
  387. * unspecified system thread pool. When either blocking.possibly or
  388. * blocking.always is established, the executor invokes the function
  389. * immediately.
  390. */
  391. typedef basic_system_executor<execution::blocking_t::possibly_t,
  392. execution::relationship_t::fork_t, std::allocator<void>>
  393. system_executor;
  394. #if !defined(GENERATING_DOCUMENTATION)
  395. namespace traits {
  396. #if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
  397. template <typename Blocking, typename Relationship, typename Allocator>
  398. struct equality_comparable<
  399. asio::basic_system_executor<Blocking, Relationship, Allocator>
  400. >
  401. {
  402. static constexpr bool is_valid = true;
  403. static constexpr bool is_noexcept = true;
  404. };
  405. #endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
  406. #if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
  407. template <typename Blocking, typename Relationship,
  408. typename Allocator, typename Function>
  409. struct execute_member<
  410. asio::basic_system_executor<Blocking, Relationship, Allocator>,
  411. Function
  412. >
  413. {
  414. static constexpr bool is_valid = true;
  415. static constexpr bool is_noexcept = false;
  416. typedef void result_type;
  417. };
  418. #endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
  419. #if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
  420. template <typename Blocking, typename Relationship, typename Allocator>
  421. struct require_member<
  422. asio::basic_system_executor<Blocking, Relationship, Allocator>,
  423. asio::execution::blocking_t::possibly_t
  424. >
  425. {
  426. static constexpr bool is_valid = true;
  427. static constexpr bool is_noexcept = false;
  428. typedef asio::basic_system_executor<
  429. asio::execution::blocking_t::possibly_t,
  430. Relationship, Allocator> result_type;
  431. };
  432. template <typename Blocking, typename Relationship, typename Allocator>
  433. struct require_member<
  434. asio::basic_system_executor<Blocking, Relationship, Allocator>,
  435. asio::execution::blocking_t::always_t
  436. >
  437. {
  438. static constexpr bool is_valid = true;
  439. static constexpr bool is_noexcept = false;
  440. typedef asio::basic_system_executor<
  441. asio::execution::blocking_t::always_t,
  442. Relationship, Allocator> result_type;
  443. };
  444. template <typename Blocking, typename Relationship, typename Allocator>
  445. struct require_member<
  446. asio::basic_system_executor<Blocking, Relationship, Allocator>,
  447. asio::execution::blocking_t::never_t
  448. >
  449. {
  450. static constexpr bool is_valid = true;
  451. static constexpr bool is_noexcept = false;
  452. typedef asio::basic_system_executor<
  453. asio::execution::blocking_t::never_t,
  454. Relationship, Allocator> result_type;
  455. };
  456. template <typename Blocking, typename Relationship, typename Allocator>
  457. struct require_member<
  458. asio::basic_system_executor<Blocking, Relationship, Allocator>,
  459. asio::execution::relationship_t::fork_t
  460. >
  461. {
  462. static constexpr bool is_valid = true;
  463. static constexpr bool is_noexcept = false;
  464. typedef asio::basic_system_executor<Blocking,
  465. asio::execution::relationship_t::fork_t,
  466. Allocator> result_type;
  467. };
  468. template <typename Blocking, typename Relationship, typename Allocator>
  469. struct require_member<
  470. asio::basic_system_executor<Blocking, Relationship, Allocator>,
  471. asio::execution::relationship_t::continuation_t
  472. >
  473. {
  474. static constexpr bool is_valid = true;
  475. static constexpr bool is_noexcept = false;
  476. typedef asio::basic_system_executor<Blocking,
  477. asio::execution::relationship_t::continuation_t,
  478. Allocator> result_type;
  479. };
  480. template <typename Blocking, typename Relationship, typename Allocator>
  481. struct require_member<
  482. asio::basic_system_executor<Blocking, Relationship, Allocator>,
  483. asio::execution::allocator_t<void>
  484. >
  485. {
  486. static constexpr bool is_valid = true;
  487. static constexpr bool is_noexcept = false;
  488. typedef asio::basic_system_executor<Blocking,
  489. Relationship, std::allocator<void>> result_type;
  490. };
  491. template <typename Blocking, typename Relationship,
  492. typename Allocator, typename OtherAllocator>
  493. struct require_member<
  494. asio::basic_system_executor<Blocking, Relationship, Allocator>,
  495. asio::execution::allocator_t<OtherAllocator>
  496. >
  497. {
  498. static constexpr bool is_valid = true;
  499. static constexpr bool is_noexcept = false;
  500. typedef asio::basic_system_executor<Blocking,
  501. Relationship, OtherAllocator> result_type;
  502. };
  503. #endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
  504. #if !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
  505. template <typename Blocking, typename Relationship,
  506. typename Allocator, typename Property>
  507. struct query_static_constexpr_member<
  508. asio::basic_system_executor<Blocking, Relationship, Allocator>,
  509. Property,
  510. typename asio::enable_if<
  511. asio::is_convertible<
  512. Property,
  513. asio::execution::mapping_t
  514. >::value
  515. >::type
  516. >
  517. {
  518. static constexpr bool is_valid = true;
  519. static constexpr bool is_noexcept = true;
  520. typedef asio::execution::mapping_t::thread_t result_type;
  521. static constexpr result_type value() noexcept
  522. {
  523. return result_type();
  524. }
  525. };
  526. #endif // !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
  527. #if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
  528. template <typename Blocking, typename Relationship,
  529. typename Allocator, typename Property>
  530. struct query_member<
  531. asio::basic_system_executor<Blocking, Relationship, Allocator>,
  532. Property,
  533. typename asio::enable_if<
  534. asio::is_convertible<
  535. Property,
  536. asio::execution::blocking_t
  537. >::value
  538. >::type
  539. >
  540. {
  541. static constexpr bool is_valid = true;
  542. static constexpr bool is_noexcept = true;
  543. typedef asio::execution::blocking_t result_type;
  544. };
  545. template <typename Blocking, typename Relationship,
  546. typename Allocator, typename Property>
  547. struct query_member<
  548. asio::basic_system_executor<Blocking, Relationship, Allocator>,
  549. Property,
  550. typename asio::enable_if<
  551. asio::is_convertible<
  552. Property,
  553. asio::execution::relationship_t
  554. >::value
  555. >::type
  556. >
  557. {
  558. static constexpr bool is_valid = true;
  559. static constexpr bool is_noexcept = true;
  560. typedef asio::execution::relationship_t result_type;
  561. };
  562. template <typename Blocking, typename Relationship, typename Allocator>
  563. struct query_member<
  564. asio::basic_system_executor<Blocking, Relationship, Allocator>,
  565. asio::execution::context_t
  566. >
  567. {
  568. static constexpr bool is_valid = true;
  569. static constexpr bool is_noexcept = true;
  570. typedef asio::system_context& result_type;
  571. };
  572. template <typename Blocking, typename Relationship, typename Allocator>
  573. struct query_member<
  574. asio::basic_system_executor<Blocking, Relationship, Allocator>,
  575. asio::execution::allocator_t<void>
  576. >
  577. {
  578. static constexpr bool is_valid = true;
  579. static constexpr bool is_noexcept = true;
  580. typedef Allocator result_type;
  581. };
  582. template <typename Blocking, typename Relationship, typename Allocator>
  583. struct query_member<
  584. asio::basic_system_executor<Blocking, Relationship, Allocator>,
  585. asio::execution::allocator_t<Allocator>
  586. >
  587. {
  588. static constexpr bool is_valid = true;
  589. static constexpr bool is_noexcept = true;
  590. typedef Allocator result_type;
  591. };
  592. #endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
  593. } // namespace traits
  594. #endif // !defined(GENERATING_DOCUMENTATION)
  595. } // namespace asio
  596. #include "asio/detail/pop_options.hpp"
  597. #include "asio/impl/system_executor.hpp"
  598. #endif // ASIO_SYSTEM_EXECUTOR_HPP