]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/asio/impl/co_spawn.hpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / boost / asio / impl / co_spawn.hpp
CommitLineData
92f5a8d4
TL
1//
2// impl/co_spawn.hpp
3// ~~~~~~~~~~~~~~~~~
4//
1e59de90 5// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
92f5a8d4
TL
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_IMPL_CO_SPAWN_HPP
12#define BOOST_ASIO_IMPL_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>
1e59de90 19#include <boost/asio/associated_cancellation_slot.hpp>
92f5a8d4
TL
20#include <boost/asio/awaitable.hpp>
21#include <boost/asio/dispatch.hpp>
20effc67 22#include <boost/asio/execution/outstanding_work.hpp>
92f5a8d4 23#include <boost/asio/post.hpp>
20effc67 24#include <boost/asio/prefer.hpp>
92f5a8d4
TL
25#include <boost/asio/use_awaitable.hpp>
26
27#include <boost/asio/detail/push_options.hpp>
28
29namespace boost {
30namespace asio {
31namespace detail {
32
20effc67
TL
33template <typename Executor, typename = void>
34class co_spawn_work_guard
35{
36public:
37 typedef typename decay<
38 typename prefer_result<Executor,
39 execution::outstanding_work_t::tracked_t
40 >::type
41 >::type executor_type;
42
43 co_spawn_work_guard(const Executor& ex)
44 : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
45 {
46 }
47
48 executor_type get_executor() const BOOST_ASIO_NOEXCEPT
49 {
50 return executor_;
51 }
52
53private:
54 executor_type executor_;
55};
56
57#if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
58
59template <typename Executor>
60struct co_spawn_work_guard<Executor,
61 typename enable_if<
62 !execution::is_executor<Executor>::value
63 >::type> : executor_work_guard<Executor>
64{
65 co_spawn_work_guard(const Executor& ex)
66 : executor_work_guard<Executor>(ex)
67 {
68 }
69};
70
71#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
72
73template <typename Executor>
74inline co_spawn_work_guard<Executor>
75make_co_spawn_work_guard(const Executor& ex)
76{
77 return co_spawn_work_guard<Executor>(ex);
78}
79
92f5a8d4 80template <typename T, typename Executor, typename F, typename Handler>
1e59de90 81awaitable<awaitable_thread_entry_point, Executor> co_spawn_entry_point(
92f5a8d4
TL
82 awaitable<T, Executor>*, Executor ex, F f, Handler handler)
83{
20effc67
TL
84 auto spawn_work = make_co_spawn_work_guard(ex);
85 auto handler_work = make_co_spawn_work_guard(
86 boost::asio::get_associated_executor(handler, ex));
92f5a8d4 87
1e59de90
TL
88 (void) co_await (dispatch)(
89 use_awaitable_t<Executor>{__FILE__, __LINE__, "co_spawn_entry_point"});
92f5a8d4 90
1e59de90
TL
91 (co_await awaitable_thread_has_context_switched{}) = false;
92 std::exception_ptr e = nullptr;
92f5a8d4
TL
93 bool done = false;
94 try
95 {
96 T t = co_await f();
97
98 done = true;
99
1e59de90
TL
100 if (co_await awaitable_thread_has_context_switched{})
101 {
102 (dispatch)(handler_work.get_executor(),
103 [handler = std::move(handler), t = std::move(t)]() mutable
104 {
105 std::move(handler)(std::exception_ptr(), std::move(t));
106 });
107 }
108 else
109 {
110 (post)(handler_work.get_executor(),
111 [handler = std::move(handler), t = std::move(t)]() mutable
112 {
113 std::move(handler)(std::exception_ptr(), std::move(t));
114 });
115 }
116
117 co_return;
92f5a8d4
TL
118 }
119 catch (...)
120 {
121 if (done)
122 throw;
123
1e59de90
TL
124 e = std::current_exception();
125 }
126
127 if (co_await awaitable_thread_has_context_switched{})
128 {
92f5a8d4 129 (dispatch)(handler_work.get_executor(),
1e59de90
TL
130 [handler = std::move(handler), e]() mutable
131 {
132 std::move(handler)(e, T());
133 });
134 }
135 else
136 {
137 (post)(handler_work.get_executor(),
138 [handler = std::move(handler), e]() mutable
92f5a8d4 139 {
1e59de90 140 std::move(handler)(e, T());
92f5a8d4
TL
141 });
142 }
143}
144
145template <typename Executor, typename F, typename Handler>
1e59de90 146awaitable<awaitable_thread_entry_point, Executor> co_spawn_entry_point(
92f5a8d4
TL
147 awaitable<void, Executor>*, Executor ex, F f, Handler handler)
148{
20effc67
TL
149 auto spawn_work = make_co_spawn_work_guard(ex);
150 auto handler_work = make_co_spawn_work_guard(
151 boost::asio::get_associated_executor(handler, ex));
92f5a8d4 152
1e59de90 153 (void) co_await (dispatch)(
20effc67 154 use_awaitable_t<Executor>{__FILE__, __LINE__, "co_spawn_entry_point"});
92f5a8d4 155
1e59de90 156 (co_await awaitable_thread_has_context_switched{}) = false;
92f5a8d4
TL
157 std::exception_ptr e = nullptr;
158 try
159 {
160 co_await f();
161 }
162 catch (...)
163 {
164 e = std::current_exception();
165 }
166
1e59de90
TL
167 if (co_await awaitable_thread_has_context_switched{})
168 {
169 (dispatch)(handler_work.get_executor(),
170 [handler = std::move(handler), e]() mutable
171 {
172 std::move(handler)(e);
173 });
174 }
175 else
176 {
177 (post)(handler_work.get_executor(),
178 [handler = std::move(handler), e]() mutable
179 {
180 std::move(handler)(e);
181 });
182 }
92f5a8d4
TL
183}
184
20effc67
TL
185template <typename T, typename Executor>
186class awaitable_as_function
187{
188public:
189 explicit awaitable_as_function(awaitable<T, Executor>&& a)
190 : awaitable_(std::move(a))
191 {
192 }
193
194 awaitable<T, Executor> operator()()
195 {
196 return std::move(awaitable_);
197 }
198
199private:
200 awaitable<T, Executor> awaitable_;
201};
202
1e59de90
TL
203template <typename Handler, typename Executor, typename = void>
204class co_spawn_cancellation_handler
205{
206public:
207 co_spawn_cancellation_handler(const Handler& handler, const Executor& ex)
208 : ex_(boost::asio::get_associated_executor(handler, ex))
209 {
210 }
211
212 cancellation_slot slot()
213 {
214 return signal_.slot();
215 }
216
217 void operator()(cancellation_type_t type)
218 {
219 cancellation_signal* sig = &signal_;
220 boost::asio::dispatch(ex_, [sig, type]{ sig->emit(type); });
221 }
222
223private:
224 cancellation_signal signal_;
225 typename associated_executor<Handler, Executor>::type ex_;
226};
227
228
229template <typename Handler, typename Executor>
230class co_spawn_cancellation_handler<Handler, Executor,
231 typename enable_if<
232 is_same<
233 typename associated_executor<Handler,
234 Executor>::asio_associated_executor_is_unspecialised,
235 void
236 >::value
237 >::type>
238{
239public:
240 co_spawn_cancellation_handler(const Handler&, const Executor&)
241 {
242 }
243
244 cancellation_slot slot()
245 {
246 return signal_.slot();
247 }
248
249 void operator()(cancellation_type_t type)
250 {
251 signal_.emit(type);
252 }
253
254private:
255 cancellation_signal signal_;
256};
257
92f5a8d4
TL
258template <typename Executor>
259class initiate_co_spawn
260{
261public:
262 typedef Executor executor_type;
263
264 template <typename OtherExecutor>
265 explicit initiate_co_spawn(const OtherExecutor& ex)
266 : ex_(ex)
267 {
268 }
269
270 executor_type get_executor() const BOOST_ASIO_NOEXCEPT
271 {
272 return ex_;
273 }
274
275 template <typename Handler, typename F>
276 void operator()(Handler&& handler, F&& f) const
277 {
278 typedef typename result_of<F()>::type awaitable_type;
1e59de90
TL
279 typedef typename decay<Handler>::type handler_type;
280 typedef co_spawn_cancellation_handler<
281 handler_type, Executor> cancel_handler_type;
282
283 auto slot = boost::asio::get_associated_cancellation_slot(handler);
284 cancel_handler_type* cancel_handler = slot.is_connected()
285 ? &slot.template emplace<cancel_handler_type>(handler, ex_)
286 : nullptr;
287
288 cancellation_slot proxy_slot(
289 cancel_handler
290 ? cancel_handler->slot()
291 : cancellation_slot());
292
293 cancellation_state cancel_state(proxy_slot);
92f5a8d4
TL
294
295 auto a = (co_spawn_entry_point)(static_cast<awaitable_type*>(nullptr),
296 ex_, std::forward<F>(f), std::forward<Handler>(handler));
1e59de90
TL
297 awaitable_handler<executor_type, void>(std::move(a),
298 ex_, proxy_slot, cancel_state).launch();
92f5a8d4
TL
299 }
300
301private:
302 Executor ex_;
303};
304
305} // namespace detail
306
20effc67
TL
307template <typename Executor, typename T, typename AwaitableExecutor,
308 BOOST_ASIO_COMPLETION_TOKEN_FOR(
309 void(std::exception_ptr, T)) CompletionToken>
310inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
311 CompletionToken, void(std::exception_ptr, T))
312co_spawn(const Executor& ex,
313 awaitable<T, AwaitableExecutor> a, CompletionToken&& token,
1e59de90 314 typename constraint<
20effc67
TL
315 (is_executor<Executor>::value || execution::is_executor<Executor>::value)
316 && is_convertible<Executor, AwaitableExecutor>::value
1e59de90 317 >::type)
20effc67
TL
318{
319 return async_initiate<CompletionToken, void(std::exception_ptr, T)>(
320 detail::initiate_co_spawn<AwaitableExecutor>(AwaitableExecutor(ex)),
321 token, detail::awaitable_as_function<T, AwaitableExecutor>(std::move(a)));
322}
323
324template <typename Executor, typename AwaitableExecutor,
325 BOOST_ASIO_COMPLETION_TOKEN_FOR(
326 void(std::exception_ptr)) CompletionToken>
327inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
328 CompletionToken, void(std::exception_ptr))
329co_spawn(const Executor& ex,
330 awaitable<void, AwaitableExecutor> a, CompletionToken&& token,
1e59de90 331 typename constraint<
20effc67
TL
332 (is_executor<Executor>::value || execution::is_executor<Executor>::value)
333 && is_convertible<Executor, AwaitableExecutor>::value
1e59de90 334 >::type)
20effc67
TL
335{
336 return async_initiate<CompletionToken, void(std::exception_ptr)>(
337 detail::initiate_co_spawn<AwaitableExecutor>(AwaitableExecutor(ex)),
338 token, detail::awaitable_as_function<
339 void, AwaitableExecutor>(std::move(a)));
340}
341
342template <typename ExecutionContext, typename T, typename AwaitableExecutor,
343 BOOST_ASIO_COMPLETION_TOKEN_FOR(
344 void(std::exception_ptr, T)) CompletionToken>
345inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
346 CompletionToken, void(std::exception_ptr, T))
347co_spawn(ExecutionContext& ctx,
348 awaitable<T, AwaitableExecutor> a, CompletionToken&& token,
1e59de90 349 typename constraint<
20effc67
TL
350 is_convertible<ExecutionContext&, execution_context&>::value
351 && is_convertible<typename ExecutionContext::executor_type,
352 AwaitableExecutor>::value
1e59de90 353 >::type)
20effc67
TL
354{
355 return (co_spawn)(ctx.get_executor(), std::move(a),
356 std::forward<CompletionToken>(token));
357}
358
359template <typename ExecutionContext, typename AwaitableExecutor,
360 BOOST_ASIO_COMPLETION_TOKEN_FOR(
361 void(std::exception_ptr)) CompletionToken>
362inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
363 CompletionToken, void(std::exception_ptr))
364co_spawn(ExecutionContext& ctx,
365 awaitable<void, AwaitableExecutor> a, CompletionToken&& token,
1e59de90 366 typename constraint<
20effc67
TL
367 is_convertible<ExecutionContext&, execution_context&>::value
368 && is_convertible<typename ExecutionContext::executor_type,
369 AwaitableExecutor>::value
1e59de90 370 >::type)
20effc67
TL
371{
372 return (co_spawn)(ctx.get_executor(), std::move(a),
373 std::forward<CompletionToken>(token));
374}
375
92f5a8d4
TL
376template <typename Executor, typename F,
377 BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<
378 typename result_of<F()>::type>::type) CompletionToken>
379inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
380 typename detail::awaitable_signature<typename result_of<F()>::type>::type)
381co_spawn(const Executor& ex, F&& f, CompletionToken&& token,
1e59de90 382 typename constraint<
20effc67 383 is_executor<Executor>::value || execution::is_executor<Executor>::value
1e59de90 384 >::type)
92f5a8d4
TL
385{
386 return async_initiate<CompletionToken,
20effc67 387 typename detail::awaitable_signature<typename result_of<F()>::type>::type>(
92f5a8d4
TL
388 detail::initiate_co_spawn<
389 typename result_of<F()>::type::executor_type>(ex),
390 token, std::forward<F>(f));
391}
392
393template <typename ExecutionContext, typename F,
394 BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<
395 typename result_of<F()>::type>::type) CompletionToken>
396inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
397 typename detail::awaitable_signature<typename result_of<F()>::type>::type)
398co_spawn(ExecutionContext& ctx, F&& f, CompletionToken&& token,
1e59de90 399 typename constraint<
92f5a8d4 400 is_convertible<ExecutionContext&, execution_context&>::value
1e59de90 401 >::type)
92f5a8d4
TL
402{
403 return (co_spawn)(ctx.get_executor(), std::forward<F>(f),
404 std::forward<CompletionToken>(token));
405}
406
407} // namespace asio
408} // namespace boost
409
410#include <boost/asio/detail/pop_options.hpp>
411
412#endif // BOOST_ASIO_IMPL_CO_SPAWN_HPP