executor.hpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. //
  2. // impl/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_IMPL_EXECUTOR_HPP
  11. #define ASIO_IMPL_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. #if !defined(ASIO_NO_TS_EXECUTORS)
  17. #include <new>
  18. #include "asio/detail/atomic_count.hpp"
  19. #include "asio/detail/global.hpp"
  20. #include "asio/detail/memory.hpp"
  21. #include "asio/executor.hpp"
  22. #include "asio/system_executor.hpp"
  23. #include "asio/detail/push_options.hpp"
  24. namespace asio {
  25. #if !defined(GENERATING_DOCUMENTATION)
  26. // Default polymorphic executor implementation.
  27. template <typename Executor, typename Allocator>
  28. class executor::impl
  29. : public executor::impl_base
  30. {
  31. public:
  32. typedef ASIO_REBIND_ALLOC(Allocator, impl) allocator_type;
  33. static impl_base* create(const Executor& e, Allocator a = Allocator())
  34. {
  35. raw_mem mem(a);
  36. impl* p = new (mem.ptr_) impl(e, a);
  37. mem.ptr_ = 0;
  38. return p;
  39. }
  40. static impl_base* create(std::nothrow_t, const Executor& e) noexcept
  41. {
  42. return new (std::nothrow) impl(e, std::allocator<void>());
  43. }
  44. impl(const Executor& e, const Allocator& a) noexcept
  45. : impl_base(false),
  46. ref_count_(1),
  47. executor_(e),
  48. allocator_(a)
  49. {
  50. }
  51. impl_base* clone() const noexcept
  52. {
  53. detail::ref_count_up(ref_count_);
  54. return const_cast<impl_base*>(static_cast<const impl_base*>(this));
  55. }
  56. void destroy() noexcept
  57. {
  58. if (detail::ref_count_down(ref_count_))
  59. {
  60. allocator_type alloc(allocator_);
  61. impl* p = this;
  62. p->~impl();
  63. alloc.deallocate(p, 1);
  64. }
  65. }
  66. void on_work_started() noexcept
  67. {
  68. executor_.on_work_started();
  69. }
  70. void on_work_finished() noexcept
  71. {
  72. executor_.on_work_finished();
  73. }
  74. execution_context& context() noexcept
  75. {
  76. return executor_.context();
  77. }
  78. void dispatch(function&& f)
  79. {
  80. executor_.dispatch(static_cast<function&&>(f), allocator_);
  81. }
  82. void post(function&& f)
  83. {
  84. executor_.post(static_cast<function&&>(f), allocator_);
  85. }
  86. void defer(function&& f)
  87. {
  88. executor_.defer(static_cast<function&&>(f), allocator_);
  89. }
  90. type_id_result_type target_type() const noexcept
  91. {
  92. return type_id<Executor>();
  93. }
  94. void* target() noexcept
  95. {
  96. return &executor_;
  97. }
  98. const void* target() const noexcept
  99. {
  100. return &executor_;
  101. }
  102. bool equals(const impl_base* e) const noexcept
  103. {
  104. if (this == e)
  105. return true;
  106. if (target_type() != e->target_type())
  107. return false;
  108. return executor_ == *static_cast<const Executor*>(e->target());
  109. }
  110. private:
  111. mutable detail::atomic_count ref_count_;
  112. Executor executor_;
  113. Allocator allocator_;
  114. struct raw_mem
  115. {
  116. allocator_type allocator_;
  117. impl* ptr_;
  118. explicit raw_mem(const Allocator& a)
  119. : allocator_(a),
  120. ptr_(allocator_.allocate(1))
  121. {
  122. }
  123. ~raw_mem()
  124. {
  125. if (ptr_)
  126. allocator_.deallocate(ptr_, 1);
  127. }
  128. private:
  129. // Disallow copying and assignment.
  130. raw_mem(const raw_mem&);
  131. raw_mem operator=(const raw_mem&);
  132. };
  133. };
  134. // Polymorphic executor specialisation for system_executor.
  135. template <typename Allocator>
  136. class executor::impl<system_executor, Allocator>
  137. : public executor::impl_base
  138. {
  139. public:
  140. static impl_base* create(const system_executor&,
  141. const Allocator& = Allocator())
  142. {
  143. return &detail::global<impl<system_executor, std::allocator<void>> >();
  144. }
  145. static impl_base* create(std::nothrow_t, const system_executor&) noexcept
  146. {
  147. return &detail::global<impl<system_executor, std::allocator<void>> >();
  148. }
  149. impl()
  150. : impl_base(true)
  151. {
  152. }
  153. impl_base* clone() const noexcept
  154. {
  155. return const_cast<impl_base*>(static_cast<const impl_base*>(this));
  156. }
  157. void destroy() noexcept
  158. {
  159. }
  160. void on_work_started() noexcept
  161. {
  162. executor_.on_work_started();
  163. }
  164. void on_work_finished() noexcept
  165. {
  166. executor_.on_work_finished();
  167. }
  168. execution_context& context() noexcept
  169. {
  170. return executor_.context();
  171. }
  172. void dispatch(function&& f)
  173. {
  174. executor_.dispatch(static_cast<function&&>(f),
  175. std::allocator<void>());
  176. }
  177. void post(function&& f)
  178. {
  179. executor_.post(static_cast<function&&>(f),
  180. std::allocator<void>());
  181. }
  182. void defer(function&& f)
  183. {
  184. executor_.defer(static_cast<function&&>(f),
  185. std::allocator<void>());
  186. }
  187. type_id_result_type target_type() const noexcept
  188. {
  189. return type_id<system_executor>();
  190. }
  191. void* target() noexcept
  192. {
  193. return &executor_;
  194. }
  195. const void* target() const noexcept
  196. {
  197. return &executor_;
  198. }
  199. bool equals(const impl_base* e) const noexcept
  200. {
  201. return this == e;
  202. }
  203. private:
  204. system_executor executor_;
  205. };
  206. template <typename Executor>
  207. executor::executor(Executor e)
  208. : impl_(impl<Executor, std::allocator<void>>::create(e))
  209. {
  210. }
  211. template <typename Executor>
  212. executor::executor(std::nothrow_t, Executor e) noexcept
  213. : impl_(impl<Executor, std::allocator<void>>::create(std::nothrow, e))
  214. {
  215. }
  216. template <typename Executor, typename Allocator>
  217. executor::executor(allocator_arg_t, const Allocator& a, Executor e)
  218. : impl_(impl<Executor, Allocator>::create(e, a))
  219. {
  220. }
  221. template <typename Function, typename Allocator>
  222. void executor::dispatch(Function&& f,
  223. const Allocator& a) const
  224. {
  225. impl_base* i = get_impl();
  226. if (i->fast_dispatch_)
  227. system_executor().dispatch(static_cast<Function&&>(f), a);
  228. else
  229. i->dispatch(function(static_cast<Function&&>(f), a));
  230. }
  231. template <typename Function, typename Allocator>
  232. void executor::post(Function&& f,
  233. const Allocator& a) const
  234. {
  235. get_impl()->post(function(static_cast<Function&&>(f), a));
  236. }
  237. template <typename Function, typename Allocator>
  238. void executor::defer(Function&& f,
  239. const Allocator& a) const
  240. {
  241. get_impl()->defer(function(static_cast<Function&&>(f), a));
  242. }
  243. template <typename Executor>
  244. Executor* executor::target() noexcept
  245. {
  246. return impl_ && impl_->target_type() == type_id<Executor>()
  247. ? static_cast<Executor*>(impl_->target()) : 0;
  248. }
  249. template <typename Executor>
  250. const Executor* executor::target() const noexcept
  251. {
  252. return impl_ && impl_->target_type() == type_id<Executor>()
  253. ? static_cast<Executor*>(impl_->target()) : 0;
  254. }
  255. #endif // !defined(GENERATING_DOCUMENTATION)
  256. } // namespace asio
  257. #include "asio/detail/pop_options.hpp"
  258. #endif // !defined(ASIO_NO_TS_EXECUTORS)
  259. #endif // ASIO_IMPL_EXECUTOR_HPP