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