executor_work_guard.hpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. //
  2. // executor_work_guard.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2022 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_EXECUTOR_WORK_GUARD_HPP
  11. #define ASIO_EXECUTOR_WORK_GUARD_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_executor.hpp"
  17. #include "asio/detail/type_traits.hpp"
  18. #include "asio/execution.hpp"
  19. #include "asio/is_executor.hpp"
  20. #include "asio/detail/push_options.hpp"
  21. namespace asio {
  22. #if !defined(ASIO_EXECUTOR_WORK_GUARD_DECL)
  23. #define ASIO_EXECUTOR_WORK_GUARD_DECL
  24. template <typename Executor, typename = void, typename = void>
  25. class executor_work_guard;
  26. #endif // !defined(ASIO_EXECUTOR_WORK_GUARD_DECL)
  27. #if defined(GENERATING_DOCUMENTATION)
  28. /// An object of type @c executor_work_guard controls ownership of executor work
  29. /// within a scope.
  30. template <typename Executor>
  31. class executor_work_guard
  32. {
  33. public:
  34. /// The underlying executor type.
  35. typedef Executor executor_type;
  36. /// Constructs a @c executor_work_guard object for the specified executor.
  37. /**
  38. * Stores a copy of @c e and calls <tt>on_work_started()</tt> on it.
  39. */
  40. explicit executor_work_guard(const executor_type& e) ASIO_NOEXCEPT;
  41. /// Copy constructor.
  42. executor_work_guard(const executor_work_guard& other) ASIO_NOEXCEPT;
  43. /// Move constructor.
  44. executor_work_guard(executor_work_guard&& other) ASIO_NOEXCEPT;
  45. /// Destructor.
  46. /**
  47. * Unless the object has already been reset, or is in a moved-from state,
  48. * calls <tt>on_work_finished()</tt> on the stored executor.
  49. */
  50. ~executor_work_guard();
  51. /// Obtain the associated executor.
  52. executor_type get_executor() const ASIO_NOEXCEPT;
  53. /// Whether the executor_work_guard object owns some outstanding work.
  54. bool owns_work() const ASIO_NOEXCEPT;
  55. /// Indicate that the work is no longer outstanding.
  56. /**
  57. * Unless the object has already been reset, or is in a moved-from state,
  58. * calls <tt>on_work_finished()</tt> on the stored executor.
  59. */
  60. void reset() ASIO_NOEXCEPT;
  61. };
  62. #endif // defined(GENERATING_DOCUMENTATION)
  63. #if !defined(GENERATING_DOCUMENTATION)
  64. #if !defined(ASIO_NO_TS_EXECUTORS)
  65. template <typename Executor>
  66. class executor_work_guard<Executor,
  67. typename enable_if<
  68. is_executor<Executor>::value
  69. >::type>
  70. {
  71. public:
  72. typedef Executor executor_type;
  73. explicit executor_work_guard(const executor_type& e) ASIO_NOEXCEPT
  74. : executor_(e),
  75. owns_(true)
  76. {
  77. executor_.on_work_started();
  78. }
  79. executor_work_guard(const executor_work_guard& other) ASIO_NOEXCEPT
  80. : executor_(other.executor_),
  81. owns_(other.owns_)
  82. {
  83. if (owns_)
  84. executor_.on_work_started();
  85. }
  86. #if defined(ASIO_HAS_MOVE)
  87. executor_work_guard(executor_work_guard&& other) ASIO_NOEXCEPT
  88. : executor_(ASIO_MOVE_CAST(Executor)(other.executor_)),
  89. owns_(other.owns_)
  90. {
  91. other.owns_ = false;
  92. }
  93. #endif // defined(ASIO_HAS_MOVE)
  94. ~executor_work_guard()
  95. {
  96. if (owns_)
  97. executor_.on_work_finished();
  98. }
  99. executor_type get_executor() const ASIO_NOEXCEPT
  100. {
  101. return executor_;
  102. }
  103. bool owns_work() const ASIO_NOEXCEPT
  104. {
  105. return owns_;
  106. }
  107. void reset() ASIO_NOEXCEPT
  108. {
  109. if (owns_)
  110. {
  111. executor_.on_work_finished();
  112. owns_ = false;
  113. }
  114. }
  115. private:
  116. // Disallow assignment.
  117. executor_work_guard& operator=(const executor_work_guard&);
  118. executor_type executor_;
  119. bool owns_;
  120. };
  121. #endif // !defined(ASIO_NO_TS_EXECUTORS)
  122. template <typename Executor>
  123. class executor_work_guard<Executor,
  124. typename enable_if<
  125. !is_executor<Executor>::value
  126. >::type,
  127. typename enable_if<
  128. execution::is_executor<Executor>::value
  129. >::type>
  130. {
  131. public:
  132. typedef Executor executor_type;
  133. explicit executor_work_guard(const executor_type& e) ASIO_NOEXCEPT
  134. : executor_(e),
  135. owns_(true)
  136. {
  137. new (&work_) work_type(asio::prefer(executor_,
  138. execution::outstanding_work.tracked));
  139. }
  140. executor_work_guard(const executor_work_guard& other) ASIO_NOEXCEPT
  141. : executor_(other.executor_),
  142. owns_(other.owns_)
  143. {
  144. if (owns_)
  145. {
  146. new (&work_) work_type(asio::prefer(executor_,
  147. execution::outstanding_work.tracked));
  148. }
  149. }
  150. #if defined(ASIO_HAS_MOVE)
  151. executor_work_guard(executor_work_guard&& other) ASIO_NOEXCEPT
  152. : executor_(ASIO_MOVE_CAST(Executor)(other.executor_)),
  153. owns_(other.owns_)
  154. {
  155. if (owns_)
  156. {
  157. new (&work_) work_type(
  158. ASIO_MOVE_CAST(work_type)(
  159. *static_cast<work_type*>(
  160. static_cast<void*>(&other.work_))));
  161. other.owns_ = false;
  162. }
  163. }
  164. #endif // defined(ASIO_HAS_MOVE)
  165. ~executor_work_guard()
  166. {
  167. if (owns_)
  168. static_cast<work_type*>(static_cast<void*>(&work_))->~work_type();
  169. }
  170. executor_type get_executor() const ASIO_NOEXCEPT
  171. {
  172. return executor_;
  173. }
  174. bool owns_work() const ASIO_NOEXCEPT
  175. {
  176. return owns_;
  177. }
  178. void reset() ASIO_NOEXCEPT
  179. {
  180. if (owns_)
  181. {
  182. static_cast<work_type*>(static_cast<void*>(&work_))->~work_type();
  183. owns_ = false;
  184. }
  185. }
  186. private:
  187. // Disallow assignment.
  188. executor_work_guard& operator=(const executor_work_guard&);
  189. typedef typename decay<
  190. typename prefer_result<
  191. const executor_type&,
  192. execution::outstanding_work_t::tracked_t
  193. >::type
  194. >::type work_type;
  195. executor_type executor_;
  196. typename aligned_storage<sizeof(work_type),
  197. alignment_of<work_type>::value>::type work_;
  198. bool owns_;
  199. };
  200. #endif // !defined(GENERATING_DOCUMENTATION)
  201. /// Create an @ref executor_work_guard object.
  202. template <typename Executor>
  203. ASIO_NODISCARD inline executor_work_guard<Executor>
  204. make_work_guard(const Executor& ex,
  205. typename constraint<
  206. is_executor<Executor>::value || execution::is_executor<Executor>::value
  207. >::type = 0)
  208. {
  209. return executor_work_guard<Executor>(ex);
  210. }
  211. /// Create an @ref executor_work_guard object.
  212. template <typename ExecutionContext>
  213. ASIO_NODISCARD inline
  214. executor_work_guard<typename ExecutionContext::executor_type>
  215. make_work_guard(ExecutionContext& ctx,
  216. typename constraint<
  217. is_convertible<ExecutionContext&, execution_context&>::value
  218. >::type = 0)
  219. {
  220. return executor_work_guard<typename ExecutionContext::executor_type>(
  221. ctx.get_executor());
  222. }
  223. /// Create an @ref executor_work_guard object.
  224. template <typename T>
  225. ASIO_NODISCARD inline
  226. executor_work_guard<typename associated_executor<T>::type>
  227. make_work_guard(const T& t,
  228. typename constraint<
  229. !is_executor<T>::value
  230. >::type = 0,
  231. typename constraint<
  232. !execution::is_executor<T>::value
  233. >::type = 0,
  234. typename constraint<
  235. !is_convertible<T&, execution_context&>::value
  236. >::type = 0)
  237. {
  238. return executor_work_guard<typename associated_executor<T>::type>(
  239. associated_executor<T>::get(t));
  240. }
  241. /// Create an @ref executor_work_guard object.
  242. template <typename T, typename Executor>
  243. ASIO_NODISCARD inline
  244. executor_work_guard<typename associated_executor<T, Executor>::type>
  245. make_work_guard(const T& t, const Executor& ex,
  246. typename constraint<
  247. is_executor<Executor>::value || execution::is_executor<Executor>::value
  248. >::type = 0)
  249. {
  250. return executor_work_guard<typename associated_executor<T, Executor>::type>(
  251. associated_executor<T, Executor>::get(t, ex));
  252. }
  253. /// Create an @ref executor_work_guard object.
  254. template <typename T, typename ExecutionContext>
  255. ASIO_NODISCARD inline executor_work_guard<typename associated_executor<T,
  256. typename ExecutionContext::executor_type>::type>
  257. make_work_guard(const T& t, ExecutionContext& ctx,
  258. typename constraint<
  259. !is_executor<T>::value
  260. >::type = 0,
  261. typename constraint<
  262. !execution::is_executor<T>::value
  263. >::type = 0,
  264. typename constraint<
  265. !is_convertible<T&, execution_context&>::value
  266. >::type = 0,
  267. typename constraint<
  268. is_convertible<ExecutionContext&, execution_context&>::value
  269. >::type = 0)
  270. {
  271. return executor_work_guard<typename associated_executor<T,
  272. typename ExecutionContext::executor_type>::type>(
  273. associated_executor<T, typename ExecutionContext::executor_type>::get(
  274. t, ctx.get_executor()));
  275. }
  276. } // namespace asio
  277. #include "asio/detail/pop_options.hpp"
  278. #endif // ASIO_EXECUTOR_WORK_GUARD_HPP