]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/asio/impl/co_spawn.hpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / boost / asio / impl / co_spawn.hpp
CommitLineData
92f5a8d4
TL
1//
2// impl/co_spawn.hpp
3// ~~~~~~~~~~~~~~~~~
4//
f67539c2 5// Copyright (c) 2003-2020 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>
19#include <boost/asio/awaitable.hpp>
20#include <boost/asio/dispatch.hpp>
20effc67 21#include <boost/asio/execution/outstanding_work.hpp>
92f5a8d4 22#include <boost/asio/post.hpp>
20effc67 23#include <boost/asio/prefer.hpp>
92f5a8d4
TL
24#include <boost/asio/use_awaitable.hpp>
25
26#include <boost/asio/detail/push_options.hpp>
27
28namespace boost {
29namespace asio {
30namespace detail {
31
20effc67
TL
32template <typename Executor, typename = void>
33class co_spawn_work_guard
34{
35public:
36 typedef typename decay<
37 typename prefer_result<Executor,
38 execution::outstanding_work_t::tracked_t
39 >::type
40 >::type executor_type;
41
42 co_spawn_work_guard(const Executor& ex)
43 : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
44 {
45 }
46
47 executor_type get_executor() const BOOST_ASIO_NOEXCEPT
48 {
49 return executor_;
50 }
51
52private:
53 executor_type executor_;
54};
55
56#if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
57
58template <typename Executor>
59struct co_spawn_work_guard<Executor,
60 typename enable_if<
61 !execution::is_executor<Executor>::value
62 >::type> : executor_work_guard<Executor>
63{
64 co_spawn_work_guard(const Executor& ex)
65 : executor_work_guard<Executor>(ex)
66 {
67 }
68};
69
70#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
71
72template <typename Executor>
73inline co_spawn_work_guard<Executor>
74make_co_spawn_work_guard(const Executor& ex)
75{
76 return co_spawn_work_guard<Executor>(ex);
77}
78
92f5a8d4
TL
79template <typename T, typename Executor, typename F, typename Handler>
80awaitable<void, Executor> co_spawn_entry_point(
81 awaitable<T, Executor>*, Executor ex, F f, Handler handler)
82{
20effc67
TL
83 auto spawn_work = make_co_spawn_work_guard(ex);
84 auto handler_work = make_co_spawn_work_guard(
85 boost::asio::get_associated_executor(handler, ex));
92f5a8d4
TL
86
87 (void) co_await (post)(spawn_work.get_executor(),
88 use_awaitable_t<Executor>{});
89
90 bool done = false;
91 try
92 {
93 T t = co_await f();
94
95 done = true;
96
97 (dispatch)(handler_work.get_executor(),
98 [handler = std::move(handler), t = std::move(t)]() mutable
99 {
100 handler(std::exception_ptr(), std::move(t));
101 });
102 }
103 catch (...)
104 {
105 if (done)
106 throw;
107
108 (dispatch)(handler_work.get_executor(),
109 [handler = std::move(handler), e = std::current_exception()]() mutable
110 {
111 handler(e, T());
112 });
113 }
114}
115
116template <typename Executor, typename F, typename Handler>
117awaitable<void, Executor> co_spawn_entry_point(
118 awaitable<void, Executor>*, Executor ex, F f, Handler handler)
119{
20effc67
TL
120 auto spawn_work = make_co_spawn_work_guard(ex);
121 auto handler_work = make_co_spawn_work_guard(
122 boost::asio::get_associated_executor(handler, ex));
92f5a8d4
TL
123
124 (void) co_await (post)(spawn_work.get_executor(),
20effc67 125 use_awaitable_t<Executor>{__FILE__, __LINE__, "co_spawn_entry_point"});
92f5a8d4
TL
126
127 std::exception_ptr e = nullptr;
128 try
129 {
130 co_await f();
131 }
132 catch (...)
133 {
134 e = std::current_exception();
135 }
136
137 (dispatch)(handler_work.get_executor(),
138 [handler = std::move(handler), e]() mutable
139 {
140 handler(e);
141 });
142}
143
20effc67
TL
144template <typename T, typename Executor>
145class awaitable_as_function
146{
147public:
148 explicit awaitable_as_function(awaitable<T, Executor>&& a)
149 : awaitable_(std::move(a))
150 {
151 }
152
153 awaitable<T, Executor> operator()()
154 {
155 return std::move(awaitable_);
156 }
157
158private:
159 awaitable<T, Executor> awaitable_;
160};
161
92f5a8d4
TL
162template <typename Executor>
163class initiate_co_spawn
164{
165public:
166 typedef Executor executor_type;
167
168 template <typename OtherExecutor>
169 explicit initiate_co_spawn(const OtherExecutor& ex)
170 : ex_(ex)
171 {
172 }
173
174 executor_type get_executor() const BOOST_ASIO_NOEXCEPT
175 {
176 return ex_;
177 }
178
179 template <typename Handler, typename F>
180 void operator()(Handler&& handler, F&& f) const
181 {
182 typedef typename result_of<F()>::type awaitable_type;
183
184 auto a = (co_spawn_entry_point)(static_cast<awaitable_type*>(nullptr),
185 ex_, std::forward<F>(f), std::forward<Handler>(handler));
186 awaitable_handler<executor_type, void>(std::move(a), ex_).launch();
187 }
188
189private:
190 Executor ex_;
191};
192
193} // namespace detail
194
20effc67
TL
195template <typename Executor, typename T, typename AwaitableExecutor,
196 BOOST_ASIO_COMPLETION_TOKEN_FOR(
197 void(std::exception_ptr, T)) CompletionToken>
198inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
199 CompletionToken, void(std::exception_ptr, T))
200co_spawn(const Executor& ex,
201 awaitable<T, AwaitableExecutor> a, CompletionToken&& token,
202 typename enable_if<
203 (is_executor<Executor>::value || execution::is_executor<Executor>::value)
204 && is_convertible<Executor, AwaitableExecutor>::value
205 >::type*)
206{
207 return async_initiate<CompletionToken, void(std::exception_ptr, T)>(
208 detail::initiate_co_spawn<AwaitableExecutor>(AwaitableExecutor(ex)),
209 token, detail::awaitable_as_function<T, AwaitableExecutor>(std::move(a)));
210}
211
212template <typename Executor, typename AwaitableExecutor,
213 BOOST_ASIO_COMPLETION_TOKEN_FOR(
214 void(std::exception_ptr)) CompletionToken>
215inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
216 CompletionToken, void(std::exception_ptr))
217co_spawn(const Executor& ex,
218 awaitable<void, AwaitableExecutor> a, CompletionToken&& token,
219 typename enable_if<
220 (is_executor<Executor>::value || execution::is_executor<Executor>::value)
221 && is_convertible<Executor, AwaitableExecutor>::value
222 >::type*)
223{
224 return async_initiate<CompletionToken, void(std::exception_ptr)>(
225 detail::initiate_co_spawn<AwaitableExecutor>(AwaitableExecutor(ex)),
226 token, detail::awaitable_as_function<
227 void, AwaitableExecutor>(std::move(a)));
228}
229
230template <typename ExecutionContext, typename T, typename AwaitableExecutor,
231 BOOST_ASIO_COMPLETION_TOKEN_FOR(
232 void(std::exception_ptr, T)) CompletionToken>
233inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
234 CompletionToken, void(std::exception_ptr, T))
235co_spawn(ExecutionContext& ctx,
236 awaitable<T, AwaitableExecutor> a, CompletionToken&& token,
237 typename enable_if<
238 is_convertible<ExecutionContext&, execution_context&>::value
239 && is_convertible<typename ExecutionContext::executor_type,
240 AwaitableExecutor>::value
241 >::type*)
242{
243 return (co_spawn)(ctx.get_executor(), std::move(a),
244 std::forward<CompletionToken>(token));
245}
246
247template <typename ExecutionContext, typename AwaitableExecutor,
248 BOOST_ASIO_COMPLETION_TOKEN_FOR(
249 void(std::exception_ptr)) CompletionToken>
250inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
251 CompletionToken, void(std::exception_ptr))
252co_spawn(ExecutionContext& ctx,
253 awaitable<void, AwaitableExecutor> a, CompletionToken&& token,
254 typename enable_if<
255 is_convertible<ExecutionContext&, execution_context&>::value
256 && is_convertible<typename ExecutionContext::executor_type,
257 AwaitableExecutor>::value
258 >::type*)
259{
260 return (co_spawn)(ctx.get_executor(), std::move(a),
261 std::forward<CompletionToken>(token));
262}
263
92f5a8d4
TL
264template <typename Executor, typename F,
265 BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<
266 typename result_of<F()>::type>::type) CompletionToken>
267inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
268 typename detail::awaitable_signature<typename result_of<F()>::type>::type)
269co_spawn(const Executor& ex, F&& f, CompletionToken&& token,
270 typename enable_if<
20effc67 271 is_executor<Executor>::value || execution::is_executor<Executor>::value
92f5a8d4
TL
272 >::type*)
273{
274 return async_initiate<CompletionToken,
20effc67 275 typename detail::awaitable_signature<typename result_of<F()>::type>::type>(
92f5a8d4
TL
276 detail::initiate_co_spawn<
277 typename result_of<F()>::type::executor_type>(ex),
278 token, std::forward<F>(f));
279}
280
281template <typename ExecutionContext, typename F,
282 BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<
283 typename result_of<F()>::type>::type) CompletionToken>
284inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
285 typename detail::awaitable_signature<typename result_of<F()>::type>::type)
286co_spawn(ExecutionContext& ctx, F&& f, CompletionToken&& token,
287 typename enable_if<
288 is_convertible<ExecutionContext&, execution_context&>::value
289 >::type*)
290{
291 return (co_spawn)(ctx.get_executor(), std::forward<F>(f),
292 std::forward<CompletionToken>(token));
293}
294
295} // namespace asio
296} // namespace boost
297
298#include <boost/asio/detail/pop_options.hpp>
299
300#endif // BOOST_ASIO_IMPL_CO_SPAWN_HPP