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.

337 lines
11KB

  1. //
  2. // 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_SPAWN_HPP
  11. #define ASIO_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 <boost/coroutine/all.hpp>
  17. #include "asio/bind_executor.hpp"
  18. #include "asio/detail/memory.hpp"
  19. #include "asio/detail/type_traits.hpp"
  20. #include "asio/detail/wrapped_handler.hpp"
  21. #include "asio/executor.hpp"
  22. #include "asio/io_context.hpp"
  23. #include "asio/is_executor.hpp"
  24. #include "asio/strand.hpp"
  25. #include "asio/detail/push_options.hpp"
  26. namespace asio {
  27. /// Context object the represents the currently executing coroutine.
  28. /**
  29. * The basic_yield_context class is used to represent the currently executing
  30. * stackful coroutine. A basic_yield_context may be passed as a handler to an
  31. * asynchronous operation. For example:
  32. *
  33. * @code template <typename Handler>
  34. * void my_coroutine(basic_yield_context<Handler> yield)
  35. * {
  36. * ...
  37. * std::size_t n = my_socket.async_read_some(buffer, yield);
  38. * ...
  39. * } @endcode
  40. *
  41. * The initiating function (async_read_some in the above example) suspends the
  42. * current coroutine. The coroutine is resumed when the asynchronous operation
  43. * completes, and the result of the operation is returned.
  44. */
  45. template <typename Handler>
  46. class basic_yield_context
  47. {
  48. public:
  49. /// The coroutine callee type, used by the implementation.
  50. /**
  51. * When using Boost.Coroutine v1, this type is:
  52. * @code typename coroutine<void()> @endcode
  53. * When using Boost.Coroutine v2 (unidirectional coroutines), this type is:
  54. * @code push_coroutine<void> @endcode
  55. */
  56. #if defined(GENERATING_DOCUMENTATION)
  57. typedef implementation_defined callee_type;
  58. #elif defined(BOOST_COROUTINES_UNIDIRECT) || defined(BOOST_COROUTINES_V2)
  59. typedef boost::coroutines::push_coroutine<void> callee_type;
  60. #else
  61. typedef boost::coroutines::coroutine<void()> callee_type;
  62. #endif
  63. /// The coroutine caller type, used by the implementation.
  64. /**
  65. * When using Boost.Coroutine v1, this type is:
  66. * @code typename coroutine<void()>::caller_type @endcode
  67. * When using Boost.Coroutine v2 (unidirectional coroutines), this type is:
  68. * @code pull_coroutine<void> @endcode
  69. */
  70. #if defined(GENERATING_DOCUMENTATION)
  71. typedef implementation_defined caller_type;
  72. #elif defined(BOOST_COROUTINES_UNIDIRECT) || defined(BOOST_COROUTINES_V2)
  73. typedef boost::coroutines::pull_coroutine<void> caller_type;
  74. #else
  75. typedef boost::coroutines::coroutine<void()>::caller_type caller_type;
  76. #endif
  77. /// Construct a yield context to represent the specified coroutine.
  78. /**
  79. * Most applications do not need to use this constructor. Instead, the
  80. * spawn() function passes a yield context as an argument to the coroutine
  81. * function.
  82. */
  83. basic_yield_context(
  84. const detail::weak_ptr<callee_type>& coro,
  85. caller_type& ca, Handler& handler)
  86. : coro_(coro),
  87. ca_(ca),
  88. handler_(handler),
  89. ec_(0)
  90. {
  91. }
  92. /// Construct a yield context from another yield context type.
  93. /**
  94. * Requires that OtherHandler be convertible to Handler.
  95. */
  96. template <typename OtherHandler>
  97. basic_yield_context(const basic_yield_context<OtherHandler>& other)
  98. : coro_(other.coro_),
  99. ca_(other.ca_),
  100. handler_(other.handler_),
  101. ec_(other.ec_)
  102. {
  103. }
  104. /// Return a yield context that sets the specified error_code.
  105. /**
  106. * By default, when a yield context is used with an asynchronous operation, a
  107. * non-success error_code is converted to system_error and thrown. This
  108. * operator may be used to specify an error_code object that should instead be
  109. * set with the asynchronous operation's result. For example:
  110. *
  111. * @code template <typename Handler>
  112. * void my_coroutine(basic_yield_context<Handler> yield)
  113. * {
  114. * ...
  115. * std::size_t n = my_socket.async_read_some(buffer, yield[ec]);
  116. * if (ec)
  117. * {
  118. * // An error occurred.
  119. * }
  120. * ...
  121. * } @endcode
  122. */
  123. basic_yield_context operator[](asio::error_code& ec) const
  124. {
  125. basic_yield_context tmp(*this);
  126. tmp.ec_ = &ec;
  127. return tmp;
  128. }
  129. #if defined(GENERATING_DOCUMENTATION)
  130. private:
  131. #endif // defined(GENERATING_DOCUMENTATION)
  132. detail::weak_ptr<callee_type> coro_;
  133. caller_type& ca_;
  134. Handler handler_;
  135. asio::error_code* ec_;
  136. };
  137. #if defined(GENERATING_DOCUMENTATION)
  138. /// Context object that represents the currently executing coroutine.
  139. typedef basic_yield_context<unspecified> yield_context;
  140. #else // defined(GENERATING_DOCUMENTATION)
  141. typedef basic_yield_context<
  142. executor_binder<void(*)(), executor> > yield_context;
  143. #endif // defined(GENERATING_DOCUMENTATION)
  144. /**
  145. * @defgroup spawn asio::spawn
  146. *
  147. * @brief Start a new stackful coroutine.
  148. *
  149. * The spawn() function is a high-level wrapper over the Boost.Coroutine
  150. * library. This function enables programs to implement asynchronous logic in a
  151. * synchronous manner, as illustrated by the following example:
  152. *
  153. * @code asio::spawn(my_strand, do_echo);
  154. *
  155. * // ...
  156. *
  157. * void do_echo(asio::yield_context yield)
  158. * {
  159. * try
  160. * {
  161. * char data[128];
  162. * for (;;)
  163. * {
  164. * std::size_t length =
  165. * my_socket.async_read_some(
  166. * asio::buffer(data), yield);
  167. *
  168. * asio::async_write(my_socket,
  169. * asio::buffer(data, length), yield);
  170. * }
  171. * }
  172. * catch (std::exception& e)
  173. * {
  174. * // ...
  175. * }
  176. * } @endcode
  177. */
  178. /*@{*/
  179. /// Start a new stackful coroutine, calling the specified handler when it
  180. /// completes.
  181. /**
  182. * This function is used to launch a new coroutine.
  183. *
  184. * @param function The coroutine function. The function must have the signature:
  185. * @code void function(basic_yield_context<Handler> yield); @endcode
  186. *
  187. * @param attributes Boost.Coroutine attributes used to customise the coroutine.
  188. */
  189. template <typename Function>
  190. void spawn(ASIO_MOVE_ARG(Function) function,
  191. const boost::coroutines::attributes& attributes
  192. = boost::coroutines::attributes());
  193. /// Start a new stackful coroutine, calling the specified handler when it
  194. /// completes.
  195. /**
  196. * This function is used to launch a new coroutine.
  197. *
  198. * @param handler A handler to be called when the coroutine exits. More
  199. * importantly, the handler provides an execution context (via the the handler
  200. * invocation hook) for the coroutine. The handler must have the signature:
  201. * @code void handler(); @endcode
  202. *
  203. * @param function The coroutine function. The function must have the signature:
  204. * @code void function(basic_yield_context<Handler> yield); @endcode
  205. *
  206. * @param attributes Boost.Coroutine attributes used to customise the coroutine.
  207. */
  208. template <typename Handler, typename Function>
  209. void spawn(ASIO_MOVE_ARG(Handler) handler,
  210. ASIO_MOVE_ARG(Function) function,
  211. const boost::coroutines::attributes& attributes
  212. = boost::coroutines::attributes(),
  213. typename enable_if<!is_executor<typename decay<Handler>::type>::value &&
  214. !is_convertible<Handler&, execution_context&>::value>::type* = 0);
  215. /// Start a new stackful coroutine, inheriting the execution context of another.
  216. /**
  217. * This function is used to launch a new coroutine.
  218. *
  219. * @param ctx Identifies the current coroutine as a parent of the new
  220. * coroutine. This specifies that the new coroutine should inherit the
  221. * execution context of the parent. For example, if the parent coroutine is
  222. * executing in a particular strand, then the new coroutine will execute in the
  223. * same strand.
  224. *
  225. * @param function The coroutine function. The function must have the signature:
  226. * @code void function(basic_yield_context<Handler> yield); @endcode
  227. *
  228. * @param attributes Boost.Coroutine attributes used to customise the coroutine.
  229. */
  230. template <typename Handler, typename Function>
  231. void spawn(basic_yield_context<Handler> ctx,
  232. ASIO_MOVE_ARG(Function) function,
  233. const boost::coroutines::attributes& attributes
  234. = boost::coroutines::attributes());
  235. /// Start a new stackful coroutine that executes on a given executor.
  236. /**
  237. * This function is used to launch a new coroutine.
  238. *
  239. * @param ex Identifies the executor that will run the coroutine. The new
  240. * coroutine is implicitly given its own strand within this executor.
  241. *
  242. * @param function The coroutine function. The function must have the signature:
  243. * @code void function(yield_context yield); @endcode
  244. *
  245. * @param attributes Boost.Coroutine attributes used to customise the coroutine.
  246. */
  247. template <typename Function, typename Executor>
  248. void spawn(const Executor& ex,
  249. ASIO_MOVE_ARG(Function) function,
  250. const boost::coroutines::attributes& attributes
  251. = boost::coroutines::attributes(),
  252. typename enable_if<is_executor<Executor>::value>::type* = 0);
  253. /// Start a new stackful coroutine that executes on a given strand.
  254. /**
  255. * This function is used to launch a new coroutine.
  256. *
  257. * @param ex Identifies the strand that will run the coroutine.
  258. *
  259. * @param function The coroutine function. The function must have the signature:
  260. * @code void function(yield_context yield); @endcode
  261. *
  262. * @param attributes Boost.Coroutine attributes used to customise the coroutine.
  263. */
  264. template <typename Function, typename Executor>
  265. void spawn(const strand<Executor>& ex,
  266. ASIO_MOVE_ARG(Function) function,
  267. const boost::coroutines::attributes& attributes
  268. = boost::coroutines::attributes());
  269. /// Start a new stackful coroutine that executes in the context of a strand.
  270. /**
  271. * This function is used to launch a new coroutine.
  272. *
  273. * @param s Identifies a strand. By starting multiple coroutines on the same
  274. * strand, the implementation ensures that none of those coroutines can execute
  275. * simultaneously.
  276. *
  277. * @param function The coroutine function. The function must have the signature:
  278. * @code void function(yield_context yield); @endcode
  279. *
  280. * @param attributes Boost.Coroutine attributes used to customise the coroutine.
  281. */
  282. template <typename Function>
  283. void spawn(const asio::io_context::strand& s,
  284. ASIO_MOVE_ARG(Function) function,
  285. const boost::coroutines::attributes& attributes
  286. = boost::coroutines::attributes());
  287. /// Start a new stackful coroutine that executes on a given execution context.
  288. /**
  289. * This function is used to launch a new coroutine.
  290. *
  291. * @param ctx Identifies the execution context that will run the coroutine. The
  292. * new coroutine is implicitly given its own strand within this execution
  293. * context.
  294. *
  295. * @param function The coroutine function. The function must have the signature:
  296. * @code void function(yield_context yield); @endcode
  297. *
  298. * @param attributes Boost.Coroutine attributes used to customise the coroutine.
  299. */
  300. template <typename Function, typename ExecutionContext>
  301. void spawn(ExecutionContext& ctx,
  302. ASIO_MOVE_ARG(Function) function,
  303. const boost::coroutines::attributes& attributes
  304. = boost::coroutines::attributes(),
  305. typename enable_if<is_convertible<
  306. ExecutionContext&, execution_context&>::value>::type* = 0);
  307. /*@}*/
  308. } // namespace asio
  309. #include "asio/detail/pop_options.hpp"
  310. #include "asio/impl/spawn.hpp"
  311. #endif // ASIO_SPAWN_HPP