1//
2// co_spawn.hpp
3// ~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2024 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
11#ifndef BOOST_ASIO_CO_SPAWN_HPP
12#define BOOST_ASIO_CO_SPAWN_HPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <boost/asio/detail/config.hpp>
19
20#if defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
21
22#include <boost/asio/awaitable.hpp>
23#include <boost/asio/execution/executor.hpp>
24#include <boost/asio/execution_context.hpp>
25#include <boost/asio/is_executor.hpp>
26
27#include <boost/asio/detail/push_options.hpp>
28
29namespace boost {
30namespace asio {
31namespace detail {
32
33template <typename T>
34struct awaitable_signature;
35
36template <typename T, typename Executor>
37struct awaitable_signature<awaitable<T, Executor>>
38{
39 typedef void type(std::exception_ptr, T);
40};
41
42template <typename Executor>
43struct awaitable_signature<awaitable<void, Executor>>
44{
45 typedef void type(std::exception_ptr);
46};
47
48} // namespace detail
49
50/// Spawn a new coroutined-based thread of execution.
51/**
52 * @param ex The executor that will be used to schedule the new thread of
53 * execution.
54 *
55 * @param a The boost::asio::awaitable object that is the result of calling the
56 * coroutine's entry point function.
57 *
58 * @param token The @ref completion_token that will handle the notification that
59 * the thread of execution has completed. The function signature of the
60 * completion handler must be:
61 * @code void handler(std::exception_ptr, T); @endcode
62 *
63 * @par Completion Signature
64 * @code void(std::exception_ptr, T) @endcode
65 *
66 * @par Example
67 * @code
68 * boost::asio::awaitable<std::size_t> echo(tcp::socket socket)
69 * {
70 * std::size_t bytes_transferred = 0;
71 *
72 * try
73 * {
74 * char data[1024];
75 * for (;;)
76 * {
77 * std::size_t n = co_await socket.async_read_some(
78 * boost::asio::buffer(data), boost::asio::use_awaitable);
79 *
80 * co_await boost::asio::async_write(socket,
81 * boost::asio::buffer(data, n), boost::asio::use_awaitable);
82 *
83 * bytes_transferred += n;
84 * }
85 * }
86 * catch (const std::exception&)
87 * {
88 * }
89 *
90 * co_return bytes_transferred;
91 * }
92 *
93 * // ...
94 *
95 * boost::asio::co_spawn(my_executor,
96 * echo(std::move(my_tcp_socket)),
97 * [](std::exception_ptr e, std::size_t n)
98 * {
99 * std::cout << "transferred " << n << "\n";
100 * });
101 * @endcode
102 *
103 * @par Per-Operation Cancellation
104 * The new thread of execution is created with a cancellation state that
105 * supports @c cancellation_type::terminal values only. To change the
106 * cancellation state, call boost::asio::this_coro::reset_cancellation_state.
107 */
108template <typename Executor, typename T, typename AwaitableExecutor,
109 BOOST_ASIO_COMPLETION_TOKEN_FOR(
110 void(std::exception_ptr, T)) CompletionToken
111 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
112inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
113 CompletionToken, void(std::exception_ptr, T))
114co_spawn(const Executor& ex, awaitable<T, AwaitableExecutor> a,
115 CompletionToken&& token
116 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
117 constraint_t<
118 (is_executor<Executor>::value || execution::is_executor<Executor>::value)
119 && is_convertible<Executor, AwaitableExecutor>::value
120 > = 0);
121
122/// Spawn a new coroutined-based thread of execution.
123/**
124 * @param ex The executor that will be used to schedule the new thread of
125 * execution.
126 *
127 * @param a The boost::asio::awaitable object that is the result of calling the
128 * coroutine's entry point function.
129 *
130 * @param token The @ref completion_token that will handle the notification that
131 * the thread of execution has completed. The function signature of the
132 * completion handler must be:
133 * @code void handler(std::exception_ptr); @endcode
134 *
135 * @par Completion Signature
136 * @code void(std::exception_ptr) @endcode
137 *
138 * @par Example
139 * @code
140 * boost::asio::awaitable<void> echo(tcp::socket socket)
141 * {
142 * try
143 * {
144 * char data[1024];
145 * for (;;)
146 * {
147 * std::size_t n = co_await socket.async_read_some(
148 * boost::asio::buffer(data), boost::asio::use_awaitable);
149 *
150 * co_await boost::asio::async_write(socket,
151 * boost::asio::buffer(data, n), boost::asio::use_awaitable);
152 * }
153 * }
154 * catch (const std::exception& e)
155 * {
156 * std::cerr << "Exception: " << e.what() << "\n";
157 * }
158 * }
159 *
160 * // ...
161 *
162 * boost::asio::co_spawn(my_executor,
163 * echo(std::move(my_tcp_socket)),
164 * boost::asio::detached);
165 * @endcode
166 *
167 * @par Per-Operation Cancellation
168 * The new thread of execution is created with a cancellation state that
169 * supports @c cancellation_type::terminal values only. To change the
170 * cancellation state, call boost::asio::this_coro::reset_cancellation_state.
171 */
172template <typename Executor, typename AwaitableExecutor,
173 BOOST_ASIO_COMPLETION_TOKEN_FOR(
174 void(std::exception_ptr)) CompletionToken
175 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
176inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
177 CompletionToken, void(std::exception_ptr))
178co_spawn(const Executor& ex, awaitable<void, AwaitableExecutor> a,
179 CompletionToken&& token
180 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
181 constraint_t<
182 (is_executor<Executor>::value || execution::is_executor<Executor>::value)
183 && is_convertible<Executor, AwaitableExecutor>::value
184 > = 0);
185
186/// Spawn a new coroutined-based thread of execution.
187/**
188 * @param ctx An execution context that will provide the executor to be used to
189 * schedule the new thread of execution.
190 *
191 * @param a The boost::asio::awaitable object that is the result of calling the
192 * coroutine's entry point function.
193 *
194 * @param token The @ref completion_token that will handle the notification that
195 * the thread of execution has completed. The function signature of the
196 * completion handler must be:
197 * @code void handler(std::exception_ptr); @endcode
198 *
199 * @par Completion Signature
200 * @code void(std::exception_ptr, T) @endcode
201 *
202 * @par Example
203 * @code
204 * boost::asio::awaitable<std::size_t> echo(tcp::socket socket)
205 * {
206 * std::size_t bytes_transferred = 0;
207 *
208 * try
209 * {
210 * char data[1024];
211 * for (;;)
212 * {
213 * std::size_t n = co_await socket.async_read_some(
214 * boost::asio::buffer(data), boost::asio::use_awaitable);
215 *
216 * co_await boost::asio::async_write(socket,
217 * boost::asio::buffer(data, n), boost::asio::use_awaitable);
218 *
219 * bytes_transferred += n;
220 * }
221 * }
222 * catch (const std::exception&)
223 * {
224 * }
225 *
226 * co_return bytes_transferred;
227 * }
228 *
229 * // ...
230 *
231 * boost::asio::co_spawn(my_io_context,
232 * echo(std::move(my_tcp_socket)),
233 * [](std::exception_ptr e, std::size_t n)
234 * {
235 * std::cout << "transferred " << n << "\n";
236 * });
237 * @endcode
238 *
239 * @par Per-Operation Cancellation
240 * The new thread of execution is created with a cancellation state that
241 * supports @c cancellation_type::terminal values only. To change the
242 * cancellation state, call boost::asio::this_coro::reset_cancellation_state.
243 */
244template <typename ExecutionContext, typename T, typename AwaitableExecutor,
245 BOOST_ASIO_COMPLETION_TOKEN_FOR(
246 void(std::exception_ptr, T)) CompletionToken
247 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
248 typename ExecutionContext::executor_type)>
249inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
250 CompletionToken, void(std::exception_ptr, T))
251co_spawn(ExecutionContext& ctx, awaitable<T, AwaitableExecutor> a,
252 CompletionToken&& token
253 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(
254 typename ExecutionContext::executor_type),
255 constraint_t<
256 is_convertible<ExecutionContext&, execution_context&>::value
257 && is_convertible<typename ExecutionContext::executor_type,
258 AwaitableExecutor>::value
259 > = 0);
260
261/// Spawn a new coroutined-based thread of execution.
262/**
263 * @param ctx An execution context that will provide the executor to be used to
264 * schedule the new thread of execution.
265 *
266 * @param a The boost::asio::awaitable object that is the result of calling the
267 * coroutine's entry point function.
268 *
269 * @param token The @ref completion_token that will handle the notification that
270 * the thread of execution has completed. The function signature of the
271 * completion handler must be:
272 * @code void handler(std::exception_ptr); @endcode
273 *
274 * @par Completion Signature
275 * @code void(std::exception_ptr) @endcode
276 *
277 * @par Example
278 * @code
279 * boost::asio::awaitable<void> echo(tcp::socket socket)
280 * {
281 * try
282 * {
283 * char data[1024];
284 * for (;;)
285 * {
286 * std::size_t n = co_await socket.async_read_some(
287 * boost::asio::buffer(data), boost::asio::use_awaitable);
288 *
289 * co_await boost::asio::async_write(socket,
290 * boost::asio::buffer(data, n), boost::asio::use_awaitable);
291 * }
292 * }
293 * catch (const std::exception& e)
294 * {
295 * std::cerr << "Exception: " << e.what() << "\n";
296 * }
297 * }
298 *
299 * // ...
300 *
301 * boost::asio::co_spawn(my_io_context,
302 * echo(std::move(my_tcp_socket)),
303 * boost::asio::detached);
304 * @endcode
305 *
306 * @par Per-Operation Cancellation
307 * The new thread of execution is created with a cancellation state that
308 * supports @c cancellation_type::terminal values only. To change the
309 * cancellation state, call boost::asio::this_coro::reset_cancellation_state.
310 */
311template <typename ExecutionContext, typename AwaitableExecutor,
312 BOOST_ASIO_COMPLETION_TOKEN_FOR(
313 void(std::exception_ptr)) CompletionToken
314 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
315 typename ExecutionContext::executor_type)>
316inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
317 CompletionToken, void(std::exception_ptr))
318co_spawn(ExecutionContext& ctx, awaitable<void, AwaitableExecutor> a,
319 CompletionToken&& token
320 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(
321 typename ExecutionContext::executor_type),
322 constraint_t<
323 is_convertible<ExecutionContext&, execution_context&>::value
324 && is_convertible<typename ExecutionContext::executor_type,
325 AwaitableExecutor>::value
326 > = 0);
327
328/// Spawn a new coroutined-based thread of execution.
329/**
330 * @param ex The executor that will be used to schedule the new thread of
331 * execution.
332 *
333 * @param f A nullary function object with a return type of the form
334 * @c boost::asio::awaitable<R,E> that will be used as the coroutine's entry
335 * point.
336 *
337 * @param token The @ref completion_token that will handle the notification
338 * that the thread of execution has completed. If @c R is @c void, the function
339 * signature of the completion handler must be:
340 *
341 * @code void handler(std::exception_ptr); @endcode
342 * Otherwise, the function signature of the completion handler must be:
343 * @code void handler(std::exception_ptr, R); @endcode
344 *
345 * @par Completion Signature
346 * @code void(std::exception_ptr, R) @endcode
347 * where @c R is the first template argument to the @c awaitable returned by the
348 * supplied function object @c F:
349 * @code boost::asio::awaitable<R, AwaitableExecutor> F() @endcode
350 *
351 * @par Example
352 * @code
353 * boost::asio::awaitable<std::size_t> echo(tcp::socket socket)
354 * {
355 * std::size_t bytes_transferred = 0;
356 *
357 * try
358 * {
359 * char data[1024];
360 * for (;;)
361 * {
362 * std::size_t n = co_await socket.async_read_some(
363 * boost::asio::buffer(data), boost::asio::use_awaitable);
364 *
365 * co_await boost::asio::async_write(socket,
366 * boost::asio::buffer(data, n), boost::asio::use_awaitable);
367 *
368 * bytes_transferred += n;
369 * }
370 * }
371 * catch (const std::exception&)
372 * {
373 * }
374 *
375 * co_return bytes_transferred;
376 * }
377 *
378 * // ...
379 *
380 * boost::asio::co_spawn(my_executor,
381 * [socket = std::move(my_tcp_socket)]() mutable
382 * -> boost::asio::awaitable<void>
383 * {
384 * try
385 * {
386 * char data[1024];
387 * for (;;)
388 * {
389 * std::size_t n = co_await socket.async_read_some(
390 * boost::asio::buffer(data), boost::asio::use_awaitable);
391 *
392 * co_await boost::asio::async_write(socket,
393 * boost::asio::buffer(data, n), boost::asio::use_awaitable);
394 * }
395 * }
396 * catch (const std::exception& e)
397 * {
398 * std::cerr << "Exception: " << e.what() << "\n";
399 * }
400 * }, boost::asio::detached);
401 * @endcode
402 *
403 * @par Per-Operation Cancellation
404 * The new thread of execution is created with a cancellation state that
405 * supports @c cancellation_type::terminal values only. To change the
406 * cancellation state, call boost::asio::this_coro::reset_cancellation_state.
407 */
408template <typename Executor, typename F,
409 BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<
410 result_of_t<F()>>::type) CompletionToken
411 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
412BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
413 typename detail::awaitable_signature<result_of_t<F()>>::type)
414co_spawn(const Executor& ex, F&& f,
415 CompletionToken&& token
416 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
417 constraint_t<
418 is_executor<Executor>::value || execution::is_executor<Executor>::value
419 > = 0);
420
421/// Spawn a new coroutined-based thread of execution.
422/**
423 * @param ctx An execution context that will provide the executor to be used to
424 * schedule the new thread of execution.
425 *
426 * @param f A nullary function object with a return type of the form
427 * @c boost::asio::awaitable<R,E> that will be used as the coroutine's entry
428 * point.
429 *
430 * @param token The @ref completion_token that will handle the notification
431 * that the thread of execution has completed. If @c R is @c void, the function
432 * signature of the completion handler must be:
433 *
434 * @code void handler(std::exception_ptr); @endcode
435 * Otherwise, the function signature of the completion handler must be:
436 * @code void handler(std::exception_ptr, R); @endcode
437 *
438 * @par Completion Signature
439 * @code void(std::exception_ptr, R) @endcode
440 * where @c R is the first template argument to the @c awaitable returned by the
441 * supplied function object @c F:
442 * @code boost::asio::awaitable<R, AwaitableExecutor> F() @endcode
443 *
444 * @par Example
445 * @code
446 * boost::asio::awaitable<std::size_t> echo(tcp::socket socket)
447 * {
448 * std::size_t bytes_transferred = 0;
449 *
450 * try
451 * {
452 * char data[1024];
453 * for (;;)
454 * {
455 * std::size_t n = co_await socket.async_read_some(
456 * boost::asio::buffer(data), boost::asio::use_awaitable);
457 *
458 * co_await boost::asio::async_write(socket,
459 * boost::asio::buffer(data, n), boost::asio::use_awaitable);
460 *
461 * bytes_transferred += n;
462 * }
463 * }
464 * catch (const std::exception&)
465 * {
466 * }
467 *
468 * co_return bytes_transferred;
469 * }
470 *
471 * // ...
472 *
473 * boost::asio::co_spawn(my_io_context,
474 * [socket = std::move(my_tcp_socket)]() mutable
475 * -> boost::asio::awaitable<void>
476 * {
477 * try
478 * {
479 * char data[1024];
480 * for (;;)
481 * {
482 * std::size_t n = co_await socket.async_read_some(
483 * boost::asio::buffer(data), boost::asio::use_awaitable);
484 *
485 * co_await boost::asio::async_write(socket,
486 * boost::asio::buffer(data, n), boost::asio::use_awaitable);
487 * }
488 * }
489 * catch (const std::exception& e)
490 * {
491 * std::cerr << "Exception: " << e.what() << "\n";
492 * }
493 * }, boost::asio::detached);
494 * @endcode
495 *
496 * @par Per-Operation Cancellation
497 * The new thread of execution is created with a cancellation state that
498 * supports @c cancellation_type::terminal values only. To change the
499 * cancellation state, call boost::asio::this_coro::reset_cancellation_state.
500 */
501template <typename ExecutionContext, typename F,
502 BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<
503 result_of_t<F()>>::type) CompletionToken
504 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
505 typename ExecutionContext::executor_type)>
506BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
507 typename detail::awaitable_signature<result_of_t<F()>>::type)
508co_spawn(ExecutionContext& ctx, F&& f,
509 CompletionToken&& token
510 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(
511 typename ExecutionContext::executor_type),
512 constraint_t<
513 is_convertible<ExecutionContext&, execution_context&>::value
514 > = 0);
515
516} // namespace asio
517} // namespace boost
518
519#include <boost/asio/detail/pop_options.hpp>
520
521#include <boost/asio/impl/co_spawn.hpp>
522
523#endif // defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
524
525#endif // BOOST_ASIO_CO_SPAWN_HPP
526

source code of boost/libs/asio/include/boost/asio/co_spawn.hpp