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.

491 lines
14KB

  1. //
  2. // impl/spawn.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_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/detail/type_traits.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. template <typename Handler, typename T>
  131. class coro_async_result
  132. {
  133. public:
  134. typedef coro_handler<Handler, T> completion_handler_type;
  135. typedef T return_type;
  136. explicit coro_async_result(completion_handler_type& h)
  137. : handler_(h),
  138. ca_(h.ca_),
  139. ready_(2)
  140. {
  141. h.ready_ = &ready_;
  142. out_ec_ = h.ec_;
  143. if (!out_ec_) h.ec_ = &ec_;
  144. h.value_ = &value_;
  145. }
  146. return_type get()
  147. {
  148. // Must not hold shared_ptr to coro while suspended.
  149. handler_.coro_.reset();
  150. if (--ready_ != 0)
  151. ca_();
  152. if (!out_ec_ && ec_) throw asio::system_error(ec_);
  153. return ASIO_MOVE_CAST(return_type)(value_);
  154. }
  155. private:
  156. completion_handler_type& handler_;
  157. typename basic_yield_context<Handler>::caller_type& ca_;
  158. atomic_count ready_;
  159. asio::error_code* out_ec_;
  160. asio::error_code ec_;
  161. return_type value_;
  162. };
  163. template <typename Handler>
  164. class coro_async_result<Handler, void>
  165. {
  166. public:
  167. typedef coro_handler<Handler, void> completion_handler_type;
  168. typedef void return_type;
  169. explicit coro_async_result(completion_handler_type& h)
  170. : handler_(h),
  171. ca_(h.ca_),
  172. ready_(2)
  173. {
  174. h.ready_ = &ready_;
  175. out_ec_ = h.ec_;
  176. if (!out_ec_) h.ec_ = &ec_;
  177. }
  178. void get()
  179. {
  180. // Must not hold shared_ptr to coro while suspended.
  181. handler_.coro_.reset();
  182. if (--ready_ != 0)
  183. ca_();
  184. if (!out_ec_ && ec_) throw asio::system_error(ec_);
  185. }
  186. private:
  187. completion_handler_type& handler_;
  188. typename basic_yield_context<Handler>::caller_type& ca_;
  189. atomic_count ready_;
  190. asio::error_code* out_ec_;
  191. asio::error_code ec_;
  192. };
  193. } // namespace detail
  194. #if !defined(GENERATING_DOCUMENTATION)
  195. template <typename Handler, typename ReturnType>
  196. class async_result<basic_yield_context<Handler>, ReturnType()>
  197. : public detail::coro_async_result<Handler, void>
  198. {
  199. public:
  200. explicit async_result(
  201. typename detail::coro_async_result<Handler,
  202. void>::completion_handler_type& h)
  203. : detail::coro_async_result<Handler, void>(h)
  204. {
  205. }
  206. };
  207. template <typename Handler, typename ReturnType, typename Arg1>
  208. class async_result<basic_yield_context<Handler>, ReturnType(Arg1)>
  209. : public detail::coro_async_result<Handler, typename decay<Arg1>::type>
  210. {
  211. public:
  212. explicit async_result(
  213. typename detail::coro_async_result<Handler,
  214. typename decay<Arg1>::type>::completion_handler_type& h)
  215. : detail::coro_async_result<Handler, typename decay<Arg1>::type>(h)
  216. {
  217. }
  218. };
  219. template <typename Handler, typename ReturnType>
  220. class async_result<basic_yield_context<Handler>,
  221. ReturnType(asio::error_code)>
  222. : public detail::coro_async_result<Handler, void>
  223. {
  224. public:
  225. explicit async_result(
  226. typename detail::coro_async_result<Handler,
  227. void>::completion_handler_type& h)
  228. : detail::coro_async_result<Handler, void>(h)
  229. {
  230. }
  231. };
  232. template <typename Handler, typename ReturnType, typename Arg2>
  233. class async_result<basic_yield_context<Handler>,
  234. ReturnType(asio::error_code, Arg2)>
  235. : public detail::coro_async_result<Handler, typename decay<Arg2>::type>
  236. {
  237. public:
  238. explicit async_result(
  239. typename detail::coro_async_result<Handler,
  240. typename decay<Arg2>::type>::completion_handler_type& h)
  241. : detail::coro_async_result<Handler, typename decay<Arg2>::type>(h)
  242. {
  243. }
  244. };
  245. template <typename Handler, typename T, typename Allocator>
  246. struct associated_allocator<detail::coro_handler<Handler, T>, Allocator>
  247. {
  248. typedef typename associated_allocator<Handler, Allocator>::type type;
  249. static type get(const detail::coro_handler<Handler, T>& h,
  250. const Allocator& a = Allocator()) ASIO_NOEXCEPT
  251. {
  252. return associated_allocator<Handler, Allocator>::get(h.handler_, a);
  253. }
  254. };
  255. template <typename Handler, typename T, typename Executor>
  256. struct associated_executor<detail::coro_handler<Handler, T>, Executor>
  257. {
  258. typedef typename associated_executor<Handler, Executor>::type type;
  259. static type get(const detail::coro_handler<Handler, T>& h,
  260. const Executor& ex = Executor()) ASIO_NOEXCEPT
  261. {
  262. return associated_executor<Handler, Executor>::get(h.handler_, ex);
  263. }
  264. };
  265. namespace detail {
  266. template <typename Handler, typename Function>
  267. struct spawn_data : private noncopyable
  268. {
  269. template <typename Hand, typename Func>
  270. spawn_data(ASIO_MOVE_ARG(Hand) handler,
  271. bool call_handler, ASIO_MOVE_ARG(Func) function)
  272. : handler_(ASIO_MOVE_CAST(Hand)(handler)),
  273. call_handler_(call_handler),
  274. function_(ASIO_MOVE_CAST(Func)(function))
  275. {
  276. }
  277. weak_ptr<typename basic_yield_context<Handler>::callee_type> coro_;
  278. Handler handler_;
  279. bool call_handler_;
  280. Function function_;
  281. };
  282. template <typename Handler, typename Function>
  283. struct coro_entry_point
  284. {
  285. void operator()(typename basic_yield_context<Handler>::caller_type& ca)
  286. {
  287. shared_ptr<spawn_data<Handler, Function> > data(data_);
  288. #if !defined(BOOST_COROUTINES_UNIDIRECT) && !defined(BOOST_COROUTINES_V2)
  289. ca(); // Yield until coroutine pointer has been initialised.
  290. #endif // !defined(BOOST_COROUTINES_UNIDIRECT) && !defined(BOOST_COROUTINES_V2)
  291. const basic_yield_context<Handler> yield(
  292. data->coro_, ca, data->handler_);
  293. (data->function_)(yield);
  294. if (data->call_handler_)
  295. (data->handler_)();
  296. }
  297. shared_ptr<spawn_data<Handler, Function> > data_;
  298. };
  299. template <typename Handler, typename Function>
  300. struct spawn_helper
  301. {
  302. void operator()()
  303. {
  304. typedef typename basic_yield_context<Handler>::callee_type callee_type;
  305. coro_entry_point<Handler, Function> entry_point = { data_ };
  306. shared_ptr<callee_type> coro(new callee_type(entry_point, attributes_));
  307. data_->coro_ = coro;
  308. (*coro)();
  309. }
  310. shared_ptr<spawn_data<Handler, Function> > data_;
  311. boost::coroutines::attributes attributes_;
  312. };
  313. template <typename Function, typename Handler, typename Function1>
  314. inline void asio_handler_invoke(Function& function,
  315. spawn_helper<Handler, Function1>* this_handler)
  316. {
  317. asio_handler_invoke_helpers::invoke(
  318. function, this_handler->data_->handler_);
  319. }
  320. template <typename Function, typename Handler, typename Function1>
  321. inline void asio_handler_invoke(const Function& function,
  322. spawn_helper<Handler, Function1>* this_handler)
  323. {
  324. asio_handler_invoke_helpers::invoke(
  325. function, this_handler->data_->handler_);
  326. }
  327. inline void default_spawn_handler() {}
  328. } // namespace detail
  329. template <typename Function>
  330. inline void spawn(ASIO_MOVE_ARG(Function) function,
  331. const boost::coroutines::attributes& attributes)
  332. {
  333. typedef typename decay<Function>::type function_type;
  334. typename associated_executor<function_type>::type ex(
  335. (get_associated_executor)(function));
  336. asio::spawn(ex, ASIO_MOVE_CAST(Function)(function), attributes);
  337. }
  338. template <typename Handler, typename Function>
  339. void spawn(ASIO_MOVE_ARG(Handler) handler,
  340. ASIO_MOVE_ARG(Function) function,
  341. const boost::coroutines::attributes& attributes,
  342. typename enable_if<!is_executor<typename decay<Handler>::type>::value &&
  343. !is_convertible<Handler&, execution_context&>::value>::type*)
  344. {
  345. typedef typename decay<Handler>::type handler_type;
  346. typedef typename decay<Function>::type function_type;
  347. typename associated_executor<handler_type>::type ex(
  348. (get_associated_executor)(handler));
  349. typename associated_allocator<handler_type>::type a(
  350. (get_associated_allocator)(handler));
  351. detail::spawn_helper<handler_type, function_type> helper;
  352. helper.data_.reset(
  353. new detail::spawn_data<handler_type, function_type>(
  354. ASIO_MOVE_CAST(Handler)(handler), true,
  355. ASIO_MOVE_CAST(Function)(function)));
  356. helper.attributes_ = attributes;
  357. ex.dispatch(helper, a);
  358. }
  359. template <typename Handler, typename Function>
  360. void spawn(basic_yield_context<Handler> ctx,
  361. ASIO_MOVE_ARG(Function) function,
  362. const boost::coroutines::attributes& attributes)
  363. {
  364. typedef typename decay<Function>::type function_type;
  365. Handler handler(ctx.handler_); // Explicit copy that might be moved from.
  366. typename associated_executor<Handler>::type ex(
  367. (get_associated_executor)(handler));
  368. typename associated_allocator<Handler>::type a(
  369. (get_associated_allocator)(handler));
  370. detail::spawn_helper<Handler, function_type> helper;
  371. helper.data_.reset(
  372. new detail::spawn_data<Handler, function_type>(
  373. ASIO_MOVE_CAST(Handler)(handler), false,
  374. ASIO_MOVE_CAST(Function)(function)));
  375. helper.attributes_ = attributes;
  376. ex.dispatch(helper, a);
  377. }
  378. template <typename Function, typename Executor>
  379. inline void spawn(const Executor& ex,
  380. ASIO_MOVE_ARG(Function) function,
  381. const boost::coroutines::attributes& attributes,
  382. typename enable_if<is_executor<Executor>::value>::type*)
  383. {
  384. asio::spawn(asio::strand<Executor>(ex),
  385. ASIO_MOVE_CAST(Function)(function), attributes);
  386. }
  387. template <typename Function, typename Executor>
  388. inline void spawn(const strand<Executor>& ex,
  389. ASIO_MOVE_ARG(Function) function,
  390. const boost::coroutines::attributes& attributes)
  391. {
  392. asio::spawn(asio::bind_executor(
  393. ex, &detail::default_spawn_handler),
  394. ASIO_MOVE_CAST(Function)(function), attributes);
  395. }
  396. template <typename Function>
  397. inline void spawn(const asio::io_context::strand& s,
  398. ASIO_MOVE_ARG(Function) function,
  399. const boost::coroutines::attributes& attributes)
  400. {
  401. asio::spawn(asio::bind_executor(
  402. s, &detail::default_spawn_handler),
  403. ASIO_MOVE_CAST(Function)(function), attributes);
  404. }
  405. template <typename Function, typename ExecutionContext>
  406. inline void spawn(ExecutionContext& ctx,
  407. ASIO_MOVE_ARG(Function) function,
  408. const boost::coroutines::attributes& attributes,
  409. typename enable_if<is_convertible<
  410. ExecutionContext&, execution_context&>::value>::type*)
  411. {
  412. asio::spawn(ctx.get_executor(),
  413. ASIO_MOVE_CAST(Function)(function), attributes);
  414. }
  415. #endif // !defined(GENERATING_DOCUMENTATION)
  416. } // namespace asio
  417. #include "asio/detail/pop_options.hpp"
  418. #endif // ASIO_IMPL_SPAWN_HPP