]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/asio/detail/impl/strand_executor_service.hpp
bump version to 18.2.2-pve1
[ceph.git] / ceph / src / boost / boost / asio / detail / impl / strand_executor_service.hpp
CommitLineData
b32b8144
FG
1//
2// detail/impl/strand_executor_service.hpp
3// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4//
1e59de90 5// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
b32b8144
FG
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_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP
12#define BOOST_ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
b32b8144
FG
18#include <boost/asio/detail/fenced_block.hpp>
19#include <boost/asio/detail/handler_invoke_helpers.hpp>
20#include <boost/asio/detail/recycling_allocator.hpp>
21#include <boost/asio/executor_work_guard.hpp>
20effc67
TL
22#include <boost/asio/defer.hpp>
23#include <boost/asio/dispatch.hpp>
24#include <boost/asio/post.hpp>
b32b8144
FG
25
26#include <boost/asio/detail/push_options.hpp>
27
28namespace boost {
29namespace asio {
30namespace detail {
31
20effc67
TL
32template <typename F, typename Allocator>
33class strand_executor_service::allocator_binder
34{
35public:
36 typedef Allocator allocator_type;
37
38 allocator_binder(BOOST_ASIO_MOVE_ARG(F) f, const Allocator& a)
39 : f_(BOOST_ASIO_MOVE_CAST(F)(f)),
40 allocator_(a)
41 {
42 }
43
44 allocator_binder(const allocator_binder& other)
45 : f_(other.f_),
46 allocator_(other.allocator_)
47 {
48 }
49
50#if defined(BOOST_ASIO_HAS_MOVE)
51 allocator_binder(allocator_binder&& other)
52 : f_(BOOST_ASIO_MOVE_CAST(F)(other.f_)),
53 allocator_(BOOST_ASIO_MOVE_CAST(allocator_type)(other.allocator_))
54 {
55 }
56#endif // defined(BOOST_ASIO_HAS_MOVE)
57
58 allocator_type get_allocator() const BOOST_ASIO_NOEXCEPT
59 {
60 return allocator_;
61 }
62
63 void operator()()
64 {
65 f_();
66 }
67
68private:
69 F f_;
70 allocator_type allocator_;
71};
72
73template <typename Executor>
74class strand_executor_service::invoker<Executor,
75 typename enable_if<
76 execution::is_executor<Executor>::value
77 >::type>
78{
79public:
80 invoker(const implementation_type& impl, Executor& ex)
81 : impl_(impl),
82 executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked))
83 {
84 }
85
86 invoker(const invoker& other)
87 : impl_(other.impl_),
88 executor_(other.executor_)
89 {
90 }
91
92#if defined(BOOST_ASIO_HAS_MOVE)
93 invoker(invoker&& other)
94 : impl_(BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_)),
95 executor_(BOOST_ASIO_MOVE_CAST(executor_type)(other.executor_))
96 {
97 }
98#endif // defined(BOOST_ASIO_HAS_MOVE)
99
100 struct on_invoker_exit
101 {
102 invoker* this_;
103
104 ~on_invoker_exit()
105 {
1e59de90 106 if (push_waiting_to_ready(this_->impl_))
20effc67
TL
107 {
108 recycling_allocator<void> allocator;
1e59de90 109 executor_type ex = this_->executor_;
20effc67
TL
110 execution::execute(
111 boost::asio::prefer(
1e59de90
TL
112 boost::asio::require(
113 BOOST_ASIO_MOVE_CAST(executor_type)(ex),
20effc67
TL
114 execution::blocking.never),
115 execution::allocator(allocator)),
116 BOOST_ASIO_MOVE_CAST(invoker)(*this_));
117 }
118 }
119 };
120
121 void operator()()
122 {
20effc67
TL
123 // Ensure the next handler, if any, is scheduled on block exit.
124 on_invoker_exit on_exit = { this };
125 (void)on_exit;
126
1e59de90 127 run_ready_handlers(impl_);
20effc67
TL
128 }
129
130private:
131 typedef typename decay<
132 typename prefer_result<
133 Executor,
134 execution::outstanding_work_t::tracked_t
135 >::type
136 >::type executor_type;
137
138 implementation_type impl_;
139 executor_type executor_;
140};
141
142#if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
143
b32b8144 144template <typename Executor>
20effc67
TL
145class strand_executor_service::invoker<Executor,
146 typename enable_if<
147 !execution::is_executor<Executor>::value
148 >::type>
b32b8144
FG
149{
150public:
151 invoker(const implementation_type& impl, Executor& ex)
152 : impl_(impl),
153 work_(ex)
154 {
155 }
156
157 invoker(const invoker& other)
158 : impl_(other.impl_),
159 work_(other.work_)
160 {
161 }
162
163#if defined(BOOST_ASIO_HAS_MOVE)
164 invoker(invoker&& other)
165 : impl_(BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_)),
166 work_(BOOST_ASIO_MOVE_CAST(executor_work_guard<Executor>)(other.work_))
167 {
168 }
169#endif // defined(BOOST_ASIO_HAS_MOVE)
170
171 struct on_invoker_exit
172 {
173 invoker* this_;
174
175 ~on_invoker_exit()
176 {
1e59de90 177 if (push_waiting_to_ready(this_->impl_))
b32b8144
FG
178 {
179 Executor ex(this_->work_.get_executor());
180 recycling_allocator<void> allocator;
181 ex.post(BOOST_ASIO_MOVE_CAST(invoker)(*this_), allocator);
182 }
183 }
184 };
185
186 void operator()()
187 {
b32b8144
FG
188 // Ensure the next handler, if any, is scheduled on block exit.
189 on_invoker_exit on_exit = { this };
190 (void)on_exit;
191
1e59de90 192 run_ready_handlers(impl_);
b32b8144
FG
193 }
194
195private:
196 implementation_type impl_;
197 executor_work_guard<Executor> work_;
198};
199
20effc67
TL
200#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
201
202template <typename Executor, typename Function>
203inline void strand_executor_service::execute(const implementation_type& impl,
204 Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function,
205 typename enable_if<
206 can_query<Executor, execution::allocator_t<void> >::value
207 >::type*)
208{
209 return strand_executor_service::do_execute(impl, ex,
210 BOOST_ASIO_MOVE_CAST(Function)(function),
211 boost::asio::query(ex, execution::allocator));
212}
213
214template <typename Executor, typename Function>
215inline void strand_executor_service::execute(const implementation_type& impl,
216 Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function,
217 typename enable_if<
218 !can_query<Executor, execution::allocator_t<void> >::value
219 >::type*)
220{
221 return strand_executor_service::do_execute(impl, ex,
222 BOOST_ASIO_MOVE_CAST(Function)(function),
223 std::allocator<void>());
224}
225
226template <typename Executor, typename Function, typename Allocator>
227void strand_executor_service::do_execute(const implementation_type& impl,
228 Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a)
229{
230 typedef typename decay<Function>::type function_type;
231
232 // If the executor is not never-blocking, and we are already in the strand,
233 // then the function can run immediately.
234 if (boost::asio::query(ex, execution::blocking) != execution::blocking.never
1e59de90 235 && running_in_this_thread(impl))
20effc67
TL
236 {
237 // Make a local, non-const copy of the function.
238 function_type tmp(BOOST_ASIO_MOVE_CAST(Function)(function));
239
240 fenced_block b(fenced_block::full);
241 boost_asio_handler_invoke_helpers::invoke(tmp, tmp);
242 return;
243 }
244
245 // Allocate and construct an operation to wrap the function.
246 typedef executor_op<function_type, Allocator> op;
247 typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
248 p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(function), a);
249
250 BOOST_ASIO_HANDLER_CREATION((impl->service_->context(), *p.p,
251 "strand_executor", impl.get(), 0, "execute"));
252
253 // Add the function to the strand and schedule the strand if required.
254 bool first = enqueue(impl, p.p);
255 p.v = p.p = 0;
256 if (first)
257 {
258 execution::execute(ex, invoker<Executor>(impl, ex));
259 }
260}
261
b32b8144
FG
262template <typename Executor, typename Function, typename Allocator>
263void strand_executor_service::dispatch(const implementation_type& impl,
264 Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a)
265{
266 typedef typename decay<Function>::type function_type;
267
268 // If we are already in the strand then the function can run immediately.
1e59de90 269 if (running_in_this_thread(impl))
b32b8144
FG
270 {
271 // Make a local, non-const copy of the function.
272 function_type tmp(BOOST_ASIO_MOVE_CAST(Function)(function));
273
274 fenced_block b(fenced_block::full);
275 boost_asio_handler_invoke_helpers::invoke(tmp, tmp);
276 return;
277 }
278
279 // Allocate and construct an operation to wrap the function.
280 typedef executor_op<function_type, Allocator> op;
281 typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
282 p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(function), a);
283
284 BOOST_ASIO_HANDLER_CREATION((impl->service_->context(), *p.p,
285 "strand_executor", impl.get(), 0, "dispatch"));
286
287 // Add the function to the strand and schedule the strand if required.
288 bool first = enqueue(impl, p.p);
289 p.v = p.p = 0;
290 if (first)
20effc67
TL
291 {
292 boost::asio::dispatch(ex,
293 allocator_binder<invoker<Executor>, Allocator>(
294 invoker<Executor>(impl, ex), a));
295 }
b32b8144
FG
296}
297
298// Request invocation of the given function and return immediately.
299template <typename Executor, typename Function, typename Allocator>
300void strand_executor_service::post(const implementation_type& impl,
301 Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a)
302{
303 typedef typename decay<Function>::type function_type;
304
305 // Allocate and construct an operation to wrap the function.
306 typedef executor_op<function_type, Allocator> op;
307 typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
308 p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(function), a);
309
310 BOOST_ASIO_HANDLER_CREATION((impl->service_->context(), *p.p,
311 "strand_executor", impl.get(), 0, "post"));
312
313 // Add the function to the strand and schedule the strand if required.
314 bool first = enqueue(impl, p.p);
315 p.v = p.p = 0;
316 if (first)
20effc67
TL
317 {
318 boost::asio::post(ex,
319 allocator_binder<invoker<Executor>, Allocator>(
320 invoker<Executor>(impl, ex), a));
321 }
b32b8144
FG
322}
323
324// Request invocation of the given function and return immediately.
325template <typename Executor, typename Function, typename Allocator>
326void strand_executor_service::defer(const implementation_type& impl,
327 Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a)
328{
329 typedef typename decay<Function>::type function_type;
330
331 // Allocate and construct an operation to wrap the function.
332 typedef executor_op<function_type, Allocator> op;
333 typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
334 p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(function), a);
335
336 BOOST_ASIO_HANDLER_CREATION((impl->service_->context(), *p.p,
337 "strand_executor", impl.get(), 0, "defer"));
338
339 // Add the function to the strand and schedule the strand if required.
340 bool first = enqueue(impl, p.p);
341 p.v = p.p = 0;
342 if (first)
20effc67
TL
343 {
344 boost::asio::defer(ex,
345 allocator_binder<invoker<Executor>, Allocator>(
346 invoker<Executor>(impl, ex), a));
347 }
b32b8144
FG
348}
349
350} // namespace detail
351} // namespace asio
352} // namespace boost
353
354#include <boost/asio/detail/pop_options.hpp>
355
356#endif // BOOST_ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP