spawn.hpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. //
  2. // impl/spawn.hpp
  3. // ~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2013 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 BOOST_ASIO_IMPL_SPAWN_HPP
  11. #define BOOST_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 <boost/asio/detail/config.hpp>
  16. #include <boost/asio/async_result.hpp>
  17. #include <boost/asio/detail/handler_alloc_helpers.hpp>
  18. #include <boost/asio/detail/handler_cont_helpers.hpp>
  19. #include <boost/asio/detail/handler_invoke_helpers.hpp>
  20. #include <boost/asio/detail/noncopyable.hpp>
  21. #include <boost/asio/detail/shared_ptr.hpp>
  22. #include <boost/asio/handler_type.hpp>
  23. #include <boost/asio/detail/push_options.hpp>
  24. namespace boost {
  25. namespace asio {
  26. namespace detail {
  27. template <typename Handler, typename T>
  28. class coro_handler
  29. {
  30. public:
  31. coro_handler(basic_yield_context<Handler> ctx)
  32. : coro_(ctx.coro_.lock()),
  33. ca_(ctx.ca_),
  34. handler_(ctx.handler_),
  35. ec_(ctx.ec_),
  36. value_(0)
  37. {
  38. }
  39. void operator()(T value)
  40. {
  41. *ec_ = boost::system::error_code();
  42. *value_ = value;
  43. (*coro_)();
  44. }
  45. void operator()(boost::system::error_code ec, T value)
  46. {
  47. *ec_ = ec;
  48. *value_ = value;
  49. (*coro_)();
  50. }
  51. //private:
  52. shared_ptr<typename basic_yield_context<Handler>::callee_type> coro_;
  53. typename basic_yield_context<Handler>::caller_type& ca_;
  54. Handler& handler_;
  55. boost::system::error_code* ec_;
  56. T* value_;
  57. };
  58. template <typename Handler>
  59. class coro_handler<Handler, void>
  60. {
  61. public:
  62. coro_handler(basic_yield_context<Handler> ctx)
  63. : coro_(ctx.coro_.lock()),
  64. ca_(ctx.ca_),
  65. handler_(ctx.handler_),
  66. ec_(ctx.ec_)
  67. {
  68. }
  69. void operator()()
  70. {
  71. *ec_ = boost::system::error_code();
  72. (*coro_)();
  73. }
  74. void operator()(boost::system::error_code ec)
  75. {
  76. *ec_ = ec;
  77. (*coro_)();
  78. }
  79. //private:
  80. shared_ptr<typename basic_yield_context<Handler>::callee_type> coro_;
  81. typename basic_yield_context<Handler>::caller_type& ca_;
  82. Handler& handler_;
  83. boost::system::error_code* ec_;
  84. };
  85. template <typename Handler, typename T>
  86. inline void* asio_handler_allocate(std::size_t size,
  87. coro_handler<Handler, T>* this_handler)
  88. {
  89. return boost_asio_handler_alloc_helpers::allocate(
  90. size, this_handler->handler_);
  91. }
  92. template <typename Handler, typename T>
  93. inline void asio_handler_deallocate(void* pointer, std::size_t size,
  94. coro_handler<Handler, T>* this_handler)
  95. {
  96. boost_asio_handler_alloc_helpers::deallocate(
  97. pointer, size, this_handler->handler_);
  98. }
  99. template <typename Handler, typename T>
  100. inline bool asio_handler_is_continuation(coro_handler<Handler, T>*)
  101. {
  102. return true;
  103. }
  104. template <typename Function, typename Handler, typename T>
  105. inline void asio_handler_invoke(Function& function,
  106. coro_handler<Handler, T>* this_handler)
  107. {
  108. boost_asio_handler_invoke_helpers::invoke(
  109. function, this_handler->handler_);
  110. }
  111. template <typename Function, typename Handler, typename T>
  112. inline void asio_handler_invoke(const Function& function,
  113. coro_handler<Handler, T>* this_handler)
  114. {
  115. boost_asio_handler_invoke_helpers::invoke(
  116. function, this_handler->handler_);
  117. }
  118. } // namespace detail
  119. #if !defined(GENERATING_DOCUMENTATION)
  120. template <typename Handler, typename ReturnType>
  121. struct handler_type<basic_yield_context<Handler>, ReturnType()>
  122. {
  123. typedef detail::coro_handler<Handler, void> type;
  124. };
  125. template <typename Handler, typename ReturnType, typename Arg1>
  126. struct handler_type<basic_yield_context<Handler>, ReturnType(Arg1)>
  127. {
  128. typedef detail::coro_handler<Handler, Arg1> type;
  129. };
  130. template <typename Handler, typename ReturnType>
  131. struct handler_type<basic_yield_context<Handler>,
  132. ReturnType(boost::system::error_code)>
  133. {
  134. typedef detail::coro_handler<Handler, void> type;
  135. };
  136. template <typename Handler, typename ReturnType, typename Arg2>
  137. struct handler_type<basic_yield_context<Handler>,
  138. ReturnType(boost::system::error_code, Arg2)>
  139. {
  140. typedef detail::coro_handler<Handler, Arg2> type;
  141. };
  142. template <typename Handler, typename T>
  143. class async_result<detail::coro_handler<Handler, T> >
  144. {
  145. public:
  146. typedef T type;
  147. explicit async_result(detail::coro_handler<Handler, T>& h)
  148. : ca_(h.ca_)
  149. {
  150. out_ec_ = h.ec_;
  151. if (!out_ec_) h.ec_ = &ec_;
  152. h.value_ = &value_;
  153. }
  154. type get()
  155. {
  156. ca_();
  157. if (!out_ec_ && ec_) throw boost::system::system_error(ec_);
  158. return value_;
  159. }
  160. private:
  161. typename basic_yield_context<Handler>::caller_type& ca_;
  162. boost::system::error_code* out_ec_;
  163. boost::system::error_code ec_;
  164. type value_;
  165. };
  166. template <typename Handler>
  167. class async_result<detail::coro_handler<Handler, void> >
  168. {
  169. public:
  170. typedef void type;
  171. explicit async_result(detail::coro_handler<Handler, void>& h)
  172. : ca_(h.ca_)
  173. {
  174. out_ec_ = h.ec_;
  175. if (!out_ec_) h.ec_ = &ec_;
  176. }
  177. void get()
  178. {
  179. ca_();
  180. if (!out_ec_ && ec_) throw boost::system::system_error(ec_);
  181. }
  182. private:
  183. typename basic_yield_context<Handler>::caller_type& ca_;
  184. boost::system::error_code* out_ec_;
  185. boost::system::error_code ec_;
  186. };
  187. namespace detail {
  188. template <typename Handler, typename Function>
  189. struct spawn_data : private noncopyable
  190. {
  191. spawn_data(BOOST_ASIO_MOVE_ARG(Handler) handler,
  192. bool call_handler, BOOST_ASIO_MOVE_ARG(Function) function)
  193. : handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)),
  194. call_handler_(call_handler),
  195. function_(BOOST_ASIO_MOVE_CAST(Function)(function))
  196. {
  197. }
  198. weak_ptr<typename basic_yield_context<Handler>::callee_type> coro_;
  199. Handler handler_;
  200. bool call_handler_;
  201. Function function_;
  202. };
  203. template <typename Handler, typename Function>
  204. struct coro_entry_point
  205. {
  206. void operator()(typename basic_yield_context<Handler>::caller_type& ca)
  207. {
  208. shared_ptr<spawn_data<Handler, Function> > data(data_);
  209. ca(); // Yield until coroutine pointer has been initialised.
  210. const basic_yield_context<Handler> yield(
  211. data->coro_, ca, data->handler_);
  212. (data->function_)(yield);
  213. if (data->call_handler_)
  214. (data->handler_)();
  215. }
  216. shared_ptr<spawn_data<Handler, Function> > data_;
  217. };
  218. template <typename Handler, typename Function>
  219. struct spawn_helper
  220. {
  221. void operator()()
  222. {
  223. typedef typename basic_yield_context<Handler>::callee_type callee_type;
  224. coro_entry_point<Handler, Function> entry_point = { data_ };
  225. shared_ptr<callee_type> coro(new callee_type(entry_point, attributes_));
  226. data_->coro_ = coro;
  227. (*coro)();
  228. }
  229. shared_ptr<spawn_data<Handler, Function> > data_;
  230. boost::coroutines::attributes attributes_;
  231. };
  232. inline void default_spawn_handler() {}
  233. } // namespace detail
  234. template <typename Handler, typename Function>
  235. void spawn(BOOST_ASIO_MOVE_ARG(Handler) handler,
  236. BOOST_ASIO_MOVE_ARG(Function) function,
  237. const boost::coroutines::attributes& attributes)
  238. {
  239. detail::spawn_helper<Handler, Function> helper;
  240. helper.data_.reset(
  241. new detail::spawn_data<Handler, Function>(
  242. BOOST_ASIO_MOVE_CAST(Handler)(handler), true,
  243. BOOST_ASIO_MOVE_CAST(Function)(function)));
  244. helper.attributes_ = attributes;
  245. boost_asio_handler_invoke_helpers::invoke(helper, helper.data_->handler_);
  246. }
  247. template <typename Handler, typename Function>
  248. void spawn(basic_yield_context<Handler> ctx,
  249. BOOST_ASIO_MOVE_ARG(Function) function,
  250. const boost::coroutines::attributes& attributes)
  251. {
  252. Handler handler(ctx.handler_); // Explicit copy that might be moved from.
  253. detail::spawn_helper<Handler, Function> helper;
  254. helper.data_.reset(
  255. new detail::spawn_data<Handler, Function>(
  256. BOOST_ASIO_MOVE_CAST(Handler)(handler), false,
  257. BOOST_ASIO_MOVE_CAST(Function)(function)));
  258. helper.attributes_ = attributes;
  259. boost_asio_handler_invoke_helpers::invoke(helper, helper.data_->handler_);
  260. }
  261. template <typename Function>
  262. void spawn(boost::asio::io_service::strand strand,
  263. BOOST_ASIO_MOVE_ARG(Function) function,
  264. const boost::coroutines::attributes& attributes)
  265. {
  266. boost::asio::spawn(strand.wrap(&detail::default_spawn_handler),
  267. BOOST_ASIO_MOVE_CAST(Function)(function), attributes);
  268. }
  269. template <typename Function>
  270. void spawn(boost::asio::io_service& io_service,
  271. BOOST_ASIO_MOVE_ARG(Function) function,
  272. const boost::coroutines::attributes& attributes)
  273. {
  274. boost::asio::spawn(boost::asio::io_service::strand(io_service),
  275. BOOST_ASIO_MOVE_CAST(Function)(function), attributes);
  276. }
  277. #endif // !defined(GENERATING_DOCUMENTATION)
  278. } // namespace asio
  279. } // namespace boost
  280. #include <boost/asio/detail/pop_options.hpp>
  281. #endif // BOOST_ASIO_IMPL_SPAWN_HPP