Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

388 lines
7.9KB

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