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.

392 lines
8.1KB

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