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.

453 lines
12KB

  1. //
  2. // impl/spawn.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_SPAWN_HPP
  11. #define ASIO_IMPL_SPAWN_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_allocator.hpp"
  17. #include "asio/associated_executor.hpp"
  18. #include "asio/async_result.hpp"
  19. #include "asio/bind_executor.hpp"
  20. #include "asio/detail/atomic_count.hpp"
  21. #include "asio/detail/handler_alloc_helpers.hpp"
  22. #include "asio/detail/handler_cont_helpers.hpp"
  23. #include "asio/detail/handler_invoke_helpers.hpp"
  24. #include "asio/detail/memory.hpp"
  25. #include "asio/detail/noncopyable.hpp"
  26. #include "asio/handler_type.hpp"
  27. #include "asio/system_error.hpp"
  28. #include "asio/detail/push_options.hpp"
  29. namespace asio {
  30. namespace detail {
  31. template <typename Handler, typename T>
  32. class coro_handler
  33. {
  34. public:
  35. coro_handler(basic_yield_context<Handler> ctx)
  36. : coro_(ctx.coro_.lock()),
  37. ca_(ctx.ca_),
  38. handler_(ctx.handler_),
  39. ready_(0),
  40. ec_(ctx.ec_),
  41. value_(0)
  42. {
  43. }
  44. void operator()(T value)
  45. {
  46. *ec_ = asio::error_code();
  47. *value_ = ASIO_MOVE_CAST(T)(value);
  48. if (--*ready_ == 0)
  49. (*coro_)();
  50. }
  51. void operator()(asio::error_code ec, T value)
  52. {
  53. *ec_ = ec;
  54. *value_ = ASIO_MOVE_CAST(T)(value);
  55. if (--*ready_ == 0)
  56. (*coro_)();
  57. }
  58. //private:
  59. shared_ptr<typename basic_yield_context<Handler>::callee_type> coro_;
  60. typename basic_yield_context<Handler>::caller_type& ca_;
  61. Handler handler_;
  62. atomic_count* ready_;
  63. asio::error_code* ec_;
  64. T* value_;
  65. };
  66. template <typename Handler>
  67. class coro_handler<Handler, void>
  68. {
  69. public:
  70. coro_handler(basic_yield_context<Handler> ctx)
  71. : coro_(ctx.coro_.lock()),
  72. ca_(ctx.ca_),
  73. handler_(ctx.handler_),
  74. ready_(0),
  75. ec_(ctx.ec_)
  76. {
  77. }
  78. void operator()()
  79. {
  80. *ec_ = asio::error_code();
  81. if (--*ready_ == 0)
  82. (*coro_)();
  83. }
  84. void operator()(asio::error_code ec)
  85. {
  86. *ec_ = ec;
  87. if (--*ready_ == 0)
  88. (*coro_)();
  89. }
  90. //private:
  91. shared_ptr<typename basic_yield_context<Handler>::callee_type> coro_;
  92. typename basic_yield_context<Handler>::caller_type& ca_;
  93. Handler handler_;
  94. atomic_count* ready_;
  95. asio::error_code* ec_;
  96. };
  97. template <typename Handler, typename T>
  98. inline void* asio_handler_allocate(std::size_t size,
  99. coro_handler<Handler, T>* this_handler)
  100. {
  101. return asio_handler_alloc_helpers::allocate(
  102. size, this_handler->handler_);
  103. }
  104. template <typename Handler, typename T>
  105. inline void asio_handler_deallocate(void* pointer, std::size_t size,
  106. coro_handler<Handler, T>* this_handler)
  107. {
  108. asio_handler_alloc_helpers::deallocate(
  109. pointer, size, this_handler->handler_);
  110. }
  111. template <typename Handler, typename T>
  112. inline bool asio_handler_is_continuation(coro_handler<Handler, T>*)
  113. {
  114. return true;
  115. }
  116. template <typename Function, typename Handler, typename T>
  117. inline void asio_handler_invoke(Function& function,
  118. coro_handler<Handler, T>* this_handler)
  119. {
  120. asio_handler_invoke_helpers::invoke(
  121. function, this_handler->handler_);
  122. }
  123. template <typename Function, typename Handler, typename T>
  124. inline void asio_handler_invoke(const Function& function,
  125. coro_handler<Handler, T>* this_handler)
  126. {
  127. asio_handler_invoke_helpers::invoke(
  128. function, this_handler->handler_);
  129. }
  130. } // namespace detail
  131. #if !defined(GENERATING_DOCUMENTATION)
  132. template <typename Handler, typename ReturnType>
  133. struct handler_type<basic_yield_context<Handler>, ReturnType()>
  134. {
  135. typedef detail::coro_handler<Handler, void> type;
  136. };
  137. template <typename Handler, typename ReturnType, typename Arg1>
  138. struct handler_type<basic_yield_context<Handler>, ReturnType(Arg1)>
  139. {
  140. typedef detail::coro_handler<Handler, Arg1> type;
  141. };
  142. template <typename Handler, typename ReturnType>
  143. struct handler_type<basic_yield_context<Handler>,
  144. ReturnType(asio::error_code)>
  145. {
  146. typedef detail::coro_handler<Handler, void> type;
  147. };
  148. template <typename Handler, typename ReturnType, typename Arg2>
  149. struct handler_type<basic_yield_context<Handler>,
  150. ReturnType(asio::error_code, Arg2)>
  151. {
  152. typedef detail::coro_handler<Handler, Arg2> type;
  153. };
  154. template <typename Handler, typename T>
  155. class async_result<detail::coro_handler<Handler, T> >
  156. {
  157. public:
  158. typedef T type;
  159. explicit async_result(detail::coro_handler<Handler, T>& h)
  160. : handler_(h),
  161. ca_(h.ca_),
  162. ready_(2)
  163. {
  164. h.ready_ = &ready_;
  165. out_ec_ = h.ec_;
  166. if (!out_ec_) h.ec_ = &ec_;
  167. h.value_ = &value_;
  168. }
  169. type get()
  170. {
  171. handler_.coro_.reset(); // Must not hold shared_ptr to coro while suspended.
  172. if (--ready_ != 0)
  173. ca_();
  174. if (!out_ec_ && ec_) throw asio::system_error(ec_);
  175. return ASIO_MOVE_CAST(type)(value_);
  176. }
  177. private:
  178. detail::coro_handler<Handler, T>& handler_;
  179. typename basic_yield_context<Handler>::caller_type& ca_;
  180. detail::atomic_count ready_;
  181. asio::error_code* out_ec_;
  182. asio::error_code ec_;
  183. type value_;
  184. };
  185. template <typename Handler>
  186. class async_result<detail::coro_handler<Handler, void> >
  187. {
  188. public:
  189. typedef void type;
  190. explicit async_result(detail::coro_handler<Handler, void>& h)
  191. : handler_(h),
  192. ca_(h.ca_),
  193. ready_(2)
  194. {
  195. h.ready_ = &ready_;
  196. out_ec_ = h.ec_;
  197. if (!out_ec_) h.ec_ = &ec_;
  198. }
  199. void get()
  200. {
  201. handler_.coro_.reset(); // Must not hold shared_ptr to coro while suspended.
  202. if (--ready_ != 0)
  203. ca_();
  204. if (!out_ec_ && ec_) throw asio::system_error(ec_);
  205. }
  206. private:
  207. detail::coro_handler<Handler, void>& handler_;
  208. typename basic_yield_context<Handler>::caller_type& ca_;
  209. detail::atomic_count ready_;
  210. asio::error_code* out_ec_;
  211. asio::error_code ec_;
  212. };
  213. template <typename Handler, typename T, typename Allocator>
  214. struct associated_allocator<detail::coro_handler<Handler, T>, Allocator>
  215. {
  216. typedef typename associated_allocator<Handler, Allocator>::type type;
  217. static type get(const detail::coro_handler<Handler, T>& h,
  218. const Allocator& a = Allocator()) ASIO_NOEXCEPT
  219. {
  220. return associated_allocator<Handler, Allocator>::get(h.handler_, a);
  221. }
  222. };
  223. template <typename Handler, typename T, typename Executor>
  224. struct associated_executor<detail::coro_handler<Handler, T>, Executor>
  225. {
  226. typedef typename associated_executor<Handler, Executor>::type type;
  227. static type get(const detail::coro_handler<Handler, T>& h,
  228. const Executor& ex = Executor()) ASIO_NOEXCEPT
  229. {
  230. return associated_executor<Handler, Executor>::get(h.handler_, ex);
  231. }
  232. };
  233. namespace detail {
  234. template <typename Handler, typename Function>
  235. struct spawn_data : private noncopyable
  236. {
  237. spawn_data(ASIO_MOVE_ARG(Handler) handler,
  238. bool call_handler, ASIO_MOVE_ARG(Function) function)
  239. : handler_(ASIO_MOVE_CAST(Handler)(handler)),
  240. call_handler_(call_handler),
  241. function_(ASIO_MOVE_CAST(Function)(function))
  242. {
  243. }
  244. weak_ptr<typename basic_yield_context<Handler>::callee_type> coro_;
  245. Handler handler_;
  246. bool call_handler_;
  247. Function function_;
  248. };
  249. template <typename Handler, typename Function>
  250. struct coro_entry_point
  251. {
  252. void operator()(typename basic_yield_context<Handler>::caller_type& ca)
  253. {
  254. shared_ptr<spawn_data<Handler, Function> > data(data_);
  255. #if !defined(BOOST_COROUTINES_UNIDIRECT) && !defined(BOOST_COROUTINES_V2)
  256. ca(); // Yield until coroutine pointer has been initialised.
  257. #endif // !defined(BOOST_COROUTINES_UNIDIRECT) && !defined(BOOST_COROUTINES_V2)
  258. const basic_yield_context<Handler> yield(
  259. data->coro_, ca, data->handler_);
  260. (data->function_)(yield);
  261. if (data->call_handler_)
  262. (data->handler_)();
  263. }
  264. shared_ptr<spawn_data<Handler, Function> > data_;
  265. };
  266. template <typename Handler, typename Function>
  267. struct spawn_helper
  268. {
  269. void operator()()
  270. {
  271. typedef typename basic_yield_context<Handler>::callee_type callee_type;
  272. coro_entry_point<Handler, Function> entry_point = { data_ };
  273. shared_ptr<callee_type> coro(new callee_type(entry_point, attributes_));
  274. data_->coro_ = coro;
  275. (*coro)();
  276. }
  277. shared_ptr<spawn_data<Handler, Function> > data_;
  278. boost::coroutines::attributes attributes_;
  279. };
  280. template <typename Function, typename Handler, typename Function1>
  281. inline void asio_handler_invoke(Function& function,
  282. spawn_helper<Handler, Function1>* this_handler)
  283. {
  284. asio_handler_invoke_helpers::invoke(
  285. function, this_handler->data_->handler_);
  286. }
  287. template <typename Function, typename Handler, typename Function1>
  288. inline void asio_handler_invoke(const Function& function,
  289. spawn_helper<Handler, Function1>* this_handler)
  290. {
  291. asio_handler_invoke_helpers::invoke(
  292. function, this_handler->data_->handler_);
  293. }
  294. inline void default_spawn_handler() {}
  295. } // namespace detail
  296. template <typename Function>
  297. inline void spawn(ASIO_MOVE_ARG(Function) function,
  298. const boost::coroutines::attributes& attributes)
  299. {
  300. typedef typename decay<Function>::type function_type;
  301. typename associated_executor<function_type>::type ex(
  302. (get_associated_executor)(function));
  303. asio::spawn(ex, ASIO_MOVE_CAST(Function)(function), attributes);
  304. }
  305. template <typename Handler, typename Function>
  306. void spawn(ASIO_MOVE_ARG(Handler) handler,
  307. ASIO_MOVE_ARG(Function) function,
  308. const boost::coroutines::attributes& attributes,
  309. typename enable_if<!is_executor<typename decay<Handler>::type>::value &&
  310. !is_convertible<Handler&, execution_context&>::value>::type*)
  311. {
  312. typedef typename decay<Handler>::type handler_type;
  313. typename associated_executor<handler_type>::type ex(
  314. (get_associated_executor)(handler));
  315. typename associated_allocator<handler_type>::type a(
  316. (get_associated_allocator)(handler));
  317. detail::spawn_helper<handler_type, Function> helper;
  318. helper.data_.reset(
  319. new detail::spawn_data<handler_type, Function>(
  320. ASIO_MOVE_CAST(Handler)(handler), true,
  321. ASIO_MOVE_CAST(Function)(function)));
  322. helper.attributes_ = attributes;
  323. ex.dispatch(helper, a);
  324. }
  325. template <typename Handler, typename Function>
  326. void spawn(basic_yield_context<Handler> ctx,
  327. ASIO_MOVE_ARG(Function) function,
  328. const boost::coroutines::attributes& attributes)
  329. {
  330. Handler handler(ctx.handler_); // Explicit copy that might be moved from.
  331. typename associated_executor<Handler>::type ex(
  332. (get_associated_executor)(handler));
  333. typename associated_allocator<Handler>::type a(
  334. (get_associated_allocator)(handler));
  335. detail::spawn_helper<Handler, Function> helper;
  336. helper.data_.reset(
  337. new detail::spawn_data<Handler, Function>(
  338. ASIO_MOVE_CAST(Handler)(handler), false,
  339. ASIO_MOVE_CAST(Function)(function)));
  340. helper.attributes_ = attributes;
  341. ex.dispatch(helper, a);
  342. }
  343. template <typename Function, typename Executor>
  344. inline void spawn(const Executor& ex,
  345. ASIO_MOVE_ARG(Function) function,
  346. const boost::coroutines::attributes& attributes,
  347. typename enable_if<is_executor<Executor>::value>::type*)
  348. {
  349. asio::spawn(asio::strand<Executor>(ex),
  350. ASIO_MOVE_CAST(Function)(function), attributes);
  351. }
  352. template <typename Function, typename Executor>
  353. inline void spawn(const strand<Executor>& ex,
  354. ASIO_MOVE_ARG(Function) function,
  355. const boost::coroutines::attributes& attributes)
  356. {
  357. asio::spawn(asio::bind_executor(
  358. ex, &detail::default_spawn_handler),
  359. ASIO_MOVE_CAST(Function)(function), attributes);
  360. }
  361. template <typename Function>
  362. inline void spawn(const asio::io_context::strand& s,
  363. ASIO_MOVE_ARG(Function) function,
  364. const boost::coroutines::attributes& attributes)
  365. {
  366. asio::spawn(asio::bind_executor(
  367. s, &detail::default_spawn_handler),
  368. ASIO_MOVE_CAST(Function)(function), attributes);
  369. }
  370. template <typename Function, typename ExecutionContext>
  371. inline void spawn(ExecutionContext& ctx,
  372. ASIO_MOVE_ARG(Function) function,
  373. const boost::coroutines::attributes& attributes,
  374. typename enable_if<is_convertible<
  375. ExecutionContext&, execution_context&>::value>::type*)
  376. {
  377. asio::spawn(ctx.get_executor(),
  378. ASIO_MOVE_CAST(Function)(function), attributes);
  379. }
  380. #endif // !defined(GENERATING_DOCUMENTATION)
  381. } // namespace asio
  382. #include "asio/detail/pop_options.hpp"
  383. #endif // ASIO_IMPL_SPAWN_HPP