executor.hpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. //
  2. // impl/executor.hpp
  3. // ~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2019 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_IMPL_EXECUTOR_HPP
  11. #define BOOST_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 <boost/asio/detail/config.hpp>
  16. #include <boost/asio/detail/atomic_count.hpp>
  17. #include <boost/asio/detail/executor_function.hpp>
  18. #include <boost/asio/detail/global.hpp>
  19. #include <boost/asio/detail/memory.hpp>
  20. #include <boost/asio/detail/recycling_allocator.hpp>
  21. #include <boost/asio/executor.hpp>
  22. #include <boost/asio/system_executor.hpp>
  23. #include <boost/asio/detail/push_options.hpp>
  24. namespace boost {
  25. namespace asio {
  26. #if !defined(GENERATING_DOCUMENTATION)
  27. #if defined(BOOST_ASIO_HAS_MOVE)
  28. // Lightweight, move-only function object wrapper.
  29. class executor::function
  30. {
  31. public:
  32. template <typename F, typename Alloc>
  33. explicit function(F f, const Alloc& a)
  34. {
  35. // Allocate and construct an operation to wrap the function.
  36. typedef detail::executor_function<F, Alloc> func_type;
  37. typename func_type::ptr p = {
  38. detail::addressof(a), func_type::ptr::allocate(a), 0 };
  39. func_ = new (p.v) func_type(BOOST_ASIO_MOVE_CAST(F)(f), a);
  40. p.v = 0;
  41. }
  42. function(function&& other) BOOST_ASIO_NOEXCEPT
  43. : func_(other.func_)
  44. {
  45. other.func_ = 0;
  46. }
  47. ~function()
  48. {
  49. if (func_)
  50. func_->destroy();
  51. }
  52. void operator()()
  53. {
  54. if (func_)
  55. {
  56. detail::executor_function_base* func = func_;
  57. func_ = 0;
  58. func->complete();
  59. }
  60. }
  61. private:
  62. detail::executor_function_base* func_;
  63. };
  64. #else // defined(BOOST_ASIO_HAS_MOVE)
  65. // Not so lightweight, copyable function object wrapper.
  66. class executor::function
  67. {
  68. public:
  69. template <typename F, typename Alloc>
  70. explicit function(const F& f, const Alloc&)
  71. : impl_(new impl<F>(f))
  72. {
  73. }
  74. void operator()()
  75. {
  76. impl_->invoke_(impl_.get());
  77. }
  78. private:
  79. // Base class for polymorphic function implementations.
  80. struct impl_base
  81. {
  82. void (*invoke_)(impl_base*);
  83. };
  84. // Polymorphic function implementation.
  85. template <typename F>
  86. struct impl : impl_base
  87. {
  88. impl(const F& f)
  89. : function_(f)
  90. {
  91. invoke_ = &function::invoke<F>;
  92. }
  93. F function_;
  94. };
  95. // Helper to invoke a function.
  96. template <typename F>
  97. static void invoke(impl_base* i)
  98. {
  99. static_cast<impl<F>*>(i)->function_();
  100. }
  101. detail::shared_ptr<impl_base> impl_;
  102. };
  103. #endif // defined(BOOST_ASIO_HAS_MOVE)
  104. // Default polymorphic allocator implementation.
  105. template <typename Executor, typename Allocator>
  106. class executor::impl
  107. : public executor::impl_base
  108. {
  109. public:
  110. typedef BOOST_ASIO_REBIND_ALLOC(Allocator, impl) allocator_type;
  111. static impl_base* create(const Executor& e, Allocator a = Allocator())
  112. {
  113. raw_mem mem(a);
  114. impl* p = new (mem.ptr_) impl(e, a);
  115. mem.ptr_ = 0;
  116. return p;
  117. }
  118. impl(const Executor& e, const Allocator& a) BOOST_ASIO_NOEXCEPT
  119. : impl_base(false),
  120. ref_count_(1),
  121. executor_(e),
  122. allocator_(a)
  123. {
  124. }
  125. impl_base* clone() const BOOST_ASIO_NOEXCEPT
  126. {
  127. ++ref_count_;
  128. return const_cast<impl_base*>(static_cast<const impl_base*>(this));
  129. }
  130. void destroy() BOOST_ASIO_NOEXCEPT
  131. {
  132. if (--ref_count_ == 0)
  133. {
  134. allocator_type alloc(allocator_);
  135. impl* p = this;
  136. p->~impl();
  137. alloc.deallocate(p, 1);
  138. }
  139. }
  140. void on_work_started() BOOST_ASIO_NOEXCEPT
  141. {
  142. executor_.on_work_started();
  143. }
  144. void on_work_finished() BOOST_ASIO_NOEXCEPT
  145. {
  146. executor_.on_work_finished();
  147. }
  148. execution_context& context() BOOST_ASIO_NOEXCEPT
  149. {
  150. return executor_.context();
  151. }
  152. void dispatch(BOOST_ASIO_MOVE_ARG(function) f)
  153. {
  154. executor_.dispatch(BOOST_ASIO_MOVE_CAST(function)(f), allocator_);
  155. }
  156. void post(BOOST_ASIO_MOVE_ARG(function) f)
  157. {
  158. executor_.post(BOOST_ASIO_MOVE_CAST(function)(f), allocator_);
  159. }
  160. void defer(BOOST_ASIO_MOVE_ARG(function) f)
  161. {
  162. executor_.defer(BOOST_ASIO_MOVE_CAST(function)(f), allocator_);
  163. }
  164. type_id_result_type target_type() const BOOST_ASIO_NOEXCEPT
  165. {
  166. return type_id<Executor>();
  167. }
  168. void* target() BOOST_ASIO_NOEXCEPT
  169. {
  170. return &executor_;
  171. }
  172. const void* target() const BOOST_ASIO_NOEXCEPT
  173. {
  174. return &executor_;
  175. }
  176. bool equals(const impl_base* e) const BOOST_ASIO_NOEXCEPT
  177. {
  178. if (this == e)
  179. return true;
  180. if (target_type() != e->target_type())
  181. return false;
  182. return executor_ == *static_cast<const Executor*>(e->target());
  183. }
  184. private:
  185. mutable detail::atomic_count ref_count_;
  186. Executor executor_;
  187. Allocator allocator_;
  188. struct raw_mem
  189. {
  190. allocator_type allocator_;
  191. impl* ptr_;
  192. explicit raw_mem(const Allocator& a)
  193. : allocator_(a),
  194. ptr_(allocator_.allocate(1))
  195. {
  196. }
  197. ~raw_mem()
  198. {
  199. if (ptr_)
  200. allocator_.deallocate(ptr_, 1);
  201. }
  202. private:
  203. // Disallow copying and assignment.
  204. raw_mem(const raw_mem&);
  205. raw_mem operator=(const raw_mem&);
  206. };
  207. };
  208. // Polymorphic allocator specialisation for system_executor.
  209. template <typename Allocator>
  210. class executor::impl<system_executor, Allocator>
  211. : public executor::impl_base
  212. {
  213. public:
  214. static impl_base* create(const system_executor&,
  215. const Allocator& = Allocator())
  216. {
  217. return &detail::global<impl<system_executor, std::allocator<void> > >();
  218. }
  219. impl()
  220. : impl_base(true)
  221. {
  222. }
  223. impl_base* clone() const BOOST_ASIO_NOEXCEPT
  224. {
  225. return const_cast<impl_base*>(static_cast<const impl_base*>(this));
  226. }
  227. void destroy() BOOST_ASIO_NOEXCEPT
  228. {
  229. }
  230. void on_work_started() BOOST_ASIO_NOEXCEPT
  231. {
  232. executor_.on_work_started();
  233. }
  234. void on_work_finished() BOOST_ASIO_NOEXCEPT
  235. {
  236. executor_.on_work_finished();
  237. }
  238. execution_context& context() BOOST_ASIO_NOEXCEPT
  239. {
  240. return executor_.context();
  241. }
  242. void dispatch(BOOST_ASIO_MOVE_ARG(function) f)
  243. {
  244. executor_.dispatch(BOOST_ASIO_MOVE_CAST(function)(f), allocator_);
  245. }
  246. void post(BOOST_ASIO_MOVE_ARG(function) f)
  247. {
  248. executor_.post(BOOST_ASIO_MOVE_CAST(function)(f), allocator_);
  249. }
  250. void defer(BOOST_ASIO_MOVE_ARG(function) f)
  251. {
  252. executor_.defer(BOOST_ASIO_MOVE_CAST(function)(f), allocator_);
  253. }
  254. type_id_result_type target_type() const BOOST_ASIO_NOEXCEPT
  255. {
  256. return type_id<system_executor>();
  257. }
  258. void* target() BOOST_ASIO_NOEXCEPT
  259. {
  260. return &executor_;
  261. }
  262. const void* target() const BOOST_ASIO_NOEXCEPT
  263. {
  264. return &executor_;
  265. }
  266. bool equals(const impl_base* e) const BOOST_ASIO_NOEXCEPT
  267. {
  268. return this == e;
  269. }
  270. private:
  271. system_executor executor_;
  272. Allocator allocator_;
  273. };
  274. template <typename Executor>
  275. executor::executor(Executor e)
  276. : impl_(impl<Executor, std::allocator<void> >::create(e))
  277. {
  278. }
  279. template <typename Executor, typename Allocator>
  280. executor::executor(allocator_arg_t, const Allocator& a, Executor e)
  281. : impl_(impl<Executor, Allocator>::create(e, a))
  282. {
  283. }
  284. template <typename Function, typename Allocator>
  285. void executor::dispatch(BOOST_ASIO_MOVE_ARG(Function) f,
  286. const Allocator& a) const
  287. {
  288. impl_base* i = get_impl();
  289. if (i->fast_dispatch_)
  290. system_executor().dispatch(BOOST_ASIO_MOVE_CAST(Function)(f), a);
  291. else
  292. i->dispatch(function(BOOST_ASIO_MOVE_CAST(Function)(f), a));
  293. }
  294. template <typename Function, typename Allocator>
  295. void executor::post(BOOST_ASIO_MOVE_ARG(Function) f,
  296. const Allocator& a) const
  297. {
  298. get_impl()->post(function(BOOST_ASIO_MOVE_CAST(Function)(f), a));
  299. }
  300. template <typename Function, typename Allocator>
  301. void executor::defer(BOOST_ASIO_MOVE_ARG(Function) f,
  302. const Allocator& a) const
  303. {
  304. get_impl()->defer(function(BOOST_ASIO_MOVE_CAST(Function)(f), a));
  305. }
  306. template <typename Executor>
  307. Executor* executor::target() BOOST_ASIO_NOEXCEPT
  308. {
  309. return impl_ && impl_->target_type() == type_id<Executor>()
  310. ? static_cast<Executor*>(impl_->target()) : 0;
  311. }
  312. template <typename Executor>
  313. const Executor* executor::target() const BOOST_ASIO_NOEXCEPT
  314. {
  315. return impl_ && impl_->target_type() == type_id<Executor>()
  316. ? static_cast<Executor*>(impl_->target()) : 0;
  317. }
  318. #endif // !defined(GENERATING_DOCUMENTATION)
  319. } // namespace asio
  320. } // namespace boost
  321. #include <boost/asio/detail/pop_options.hpp>
  322. #endif // BOOST_ASIO_IMPL_EXECUTOR_HPP