]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/asio/impl/thread_pool.hpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / boost / asio / impl / thread_pool.hpp
CommitLineData
b32b8144
FG
1//
2// impl/thread_pool.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_IMPL_THREAD_POOL_HPP
12#define BOOST_ASIO_IMPL_THREAD_POOL_HPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
20effc67
TL
18#include <boost/asio/detail/blocking_executor_op.hpp>
19#include <boost/asio/detail/bulk_executor_op.hpp>
b32b8144
FG
20#include <boost/asio/detail/executor_op.hpp>
21#include <boost/asio/detail/fenced_block.hpp>
20effc67 22#include <boost/asio/detail/non_const_lvalue.hpp>
b32b8144
FG
23#include <boost/asio/detail/type_traits.hpp>
24#include <boost/asio/execution_context.hpp>
25
26#include <boost/asio/detail/push_options.hpp>
27
28namespace boost {
29namespace asio {
30
31inline thread_pool::executor_type
32thread_pool::get_executor() BOOST_ASIO_NOEXCEPT
33{
34 return executor_type(*this);
35}
36
20effc67
TL
37inline thread_pool::executor_type
38thread_pool::executor() BOOST_ASIO_NOEXCEPT
39{
40 return executor_type(*this);
41}
42
43inline thread_pool::scheduler_type
44thread_pool::scheduler() BOOST_ASIO_NOEXCEPT
45{
46 return scheduler_type(*this);
47}
48
49template <typename Allocator, unsigned int Bits>
50thread_pool::basic_executor_type<Allocator, Bits>&
51thread_pool::basic_executor_type<Allocator, Bits>::operator=(
52 const basic_executor_type& other) BOOST_ASIO_NOEXCEPT
53{
54 if (this != &other)
55 {
56 thread_pool* old_thread_pool = pool_;
57 pool_ = other.pool_;
58 allocator_ = other.allocator_;
59 bits_ = other.bits_;
60 if (Bits & outstanding_work_tracked)
61 {
62 if (pool_)
63 pool_->scheduler_.work_started();
64 if (old_thread_pool)
65 old_thread_pool->scheduler_.work_finished();
66 }
67 }
68 return *this;
69}
70
71#if defined(BOOST_ASIO_HAS_MOVE)
72template <typename Allocator, unsigned int Bits>
73thread_pool::basic_executor_type<Allocator, Bits>&
74thread_pool::basic_executor_type<Allocator, Bits>::operator=(
75 basic_executor_type&& other) BOOST_ASIO_NOEXCEPT
76{
77 if (this != &other)
78 {
1e59de90 79 thread_pool* old_thread_pool = pool_;
20effc67
TL
80 pool_ = other.pool_;
81 allocator_ = std::move(other.allocator_);
82 bits_ = other.bits_;
83 if (Bits & outstanding_work_tracked)
1e59de90 84 {
20effc67 85 other.pool_ = 0;
1e59de90
TL
86 if (old_thread_pool)
87 old_thread_pool->scheduler_.work_finished();
88 }
20effc67
TL
89 }
90 return *this;
91}
92#endif // defined(BOOST_ASIO_HAS_MOVE)
93
94template <typename Allocator, unsigned int Bits>
95inline bool thread_pool::basic_executor_type<Allocator,
96 Bits>::running_in_this_thread() const BOOST_ASIO_NOEXCEPT
97{
98 return pool_->scheduler_.can_dispatch();
99}
100
101template <typename Allocator, unsigned int Bits>
102template <typename Function>
103void thread_pool::basic_executor_type<Allocator,
104 Bits>::do_execute(BOOST_ASIO_MOVE_ARG(Function) f, false_type) const
105{
106 typedef typename decay<Function>::type function_type;
107
108 // Invoke immediately if the blocking.possibly property is enabled and we are
109 // already inside the thread pool.
110 if ((bits_ & blocking_never) == 0 && pool_->scheduler_.can_dispatch())
111 {
112 // Make a local, non-const copy of the function.
113 function_type tmp(BOOST_ASIO_MOVE_CAST(Function)(f));
114
115#if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \
116 && !defined(BOOST_ASIO_NO_EXCEPTIONS)
117 try
118 {
119#endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR)
120 // && !defined(BOOST_ASIO_NO_EXCEPTIONS)
121 detail::fenced_block b(detail::fenced_block::full);
122 boost_asio_handler_invoke_helpers::invoke(tmp, tmp);
123 return;
124#if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \
125 && !defined(BOOST_ASIO_NO_EXCEPTIONS)
126 }
127 catch (...)
128 {
129 pool_->scheduler_.capture_current_exception();
130 return;
131 }
132#endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR)
133 // && !defined(BOOST_ASIO_NO_EXCEPTIONS)
134 }
135
136 // Allocate and construct an operation to wrap the function.
137 typedef detail::executor_op<function_type, Allocator> op;
138 typename op::ptr p = { detail::addressof(allocator_),
139 op::ptr::allocate(allocator_), 0 };
140 p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), allocator_);
141
142 if ((bits_ & relationship_continuation) != 0)
143 {
144 BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p,
145 "thread_pool", pool_, 0, "execute(blk=never,rel=cont)"));
146 }
147 else
148 {
149 BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p,
150 "thread_pool", pool_, 0, "execute(blk=never,rel=fork)"));
151 }
152
153 pool_->scheduler_.post_immediate_completion(p.p,
154 (bits_ & relationship_continuation) != 0);
155 p.v = p.p = 0;
156}
157
158template <typename Allocator, unsigned int Bits>
159template <typename Function>
160void thread_pool::basic_executor_type<Allocator,
161 Bits>::do_execute(BOOST_ASIO_MOVE_ARG(Function) f, true_type) const
b32b8144 162{
20effc67
TL
163 // Obtain a non-const instance of the function.
164 detail::non_const_lvalue<Function> f2(f);
165
166 // Invoke immediately if we are already inside the thread pool.
167 if (pool_->scheduler_.can_dispatch())
168 {
169#if !defined(BOOST_ASIO_NO_EXCEPTIONS)
170 try
171 {
172#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
173 detail::fenced_block b(detail::fenced_block::full);
174 boost_asio_handler_invoke_helpers::invoke(f2.value, f2.value);
175 return;
176#if !defined(BOOST_ASIO_NO_EXCEPTIONS)
177 }
178 catch (...)
179 {
180 std::terminate();
181 }
182#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
183 }
184
185 // Construct an operation to wrap the function.
186 typedef typename decay<Function>::type function_type;
187 detail::blocking_executor_op<function_type> op(f2.value);
188
189 BOOST_ASIO_HANDLER_CREATION((*pool_, op,
190 "thread_pool", pool_, 0, "execute(blk=always)"));
191
192 pool_->scheduler_.post_immediate_completion(&op, false);
193 op.wait();
b32b8144
FG
194}
195
20effc67
TL
196template <typename Allocator, unsigned int Bits>
197template <typename Function>
198void thread_pool::basic_executor_type<Allocator, Bits>::do_bulk_execute(
199 BOOST_ASIO_MOVE_ARG(Function) f, std::size_t n, false_type) const
b32b8144 200{
20effc67
TL
201 typedef typename decay<Function>::type function_type;
202 typedef detail::bulk_executor_op<function_type, Allocator> op;
203
204 // Allocate and construct operations to wrap the function.
205 detail::op_queue<detail::scheduler_operation> ops;
206 for (std::size_t i = 0; i < n; ++i)
207 {
208 typename op::ptr p = { detail::addressof(allocator_),
209 op::ptr::allocate(allocator_), 0 };
210 p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), allocator_, i);
211 ops.push(p.p);
212
213 if ((bits_ & relationship_continuation) != 0)
214 {
215 BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p,
216 "thread_pool", pool_, 0, "bulk_execute(blk=never,rel=cont)"));
217 }
218 else
219 {
220 BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p,
221 "thread_pool", pool_, 0, "bulk)execute(blk=never,rel=fork)"));
222 }
223
224 p.v = p.p = 0;
225 }
226
227 pool_->scheduler_.post_immediate_completions(n,
228 ops, (bits_ & relationship_continuation) != 0);
b32b8144
FG
229}
230
20effc67
TL
231template <typename Function>
232struct thread_pool_always_blocking_function_adapter
b32b8144 233{
20effc67
TL
234 typename decay<Function>::type* f;
235 std::size_t n;
236
237 void operator()()
238 {
239 for (std::size_t i = 0; i < n; ++i)
240 {
241 (*f)(i);
242 }
243 }
244};
245
246template <typename Allocator, unsigned int Bits>
247template <typename Function>
248void thread_pool::basic_executor_type<Allocator, Bits>::do_bulk_execute(
249 BOOST_ASIO_MOVE_ARG(Function) f, std::size_t n, true_type) const
250{
251 // Obtain a non-const instance of the function.
252 detail::non_const_lvalue<Function> f2(f);
253
254 thread_pool_always_blocking_function_adapter<Function>
255 adapter = { detail::addressof(f2.value), n };
256
257 this->do_execute(adapter, true_type());
258}
259
260#if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
261template <typename Allocator, unsigned int Bits>
262inline thread_pool& thread_pool::basic_executor_type<
263 Allocator, Bits>::context() const BOOST_ASIO_NOEXCEPT
264{
265 return *pool_;
266}
267
268template <typename Allocator, unsigned int Bits>
269inline void thread_pool::basic_executor_type<Allocator,
270 Bits>::on_work_started() const BOOST_ASIO_NOEXCEPT
271{
272 pool_->scheduler_.work_started();
b32b8144
FG
273}
274
20effc67
TL
275template <typename Allocator, unsigned int Bits>
276inline void thread_pool::basic_executor_type<Allocator,
277 Bits>::on_work_finished() const BOOST_ASIO_NOEXCEPT
278{
279 pool_->scheduler_.work_finished();
280}
281
282template <typename Allocator, unsigned int Bits>
283template <typename Function, typename OtherAllocator>
284void thread_pool::basic_executor_type<Allocator, Bits>::dispatch(
285 BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const
b32b8144
FG
286{
287 typedef typename decay<Function>::type function_type;
288
289 // Invoke immediately if we are already inside the thread pool.
20effc67 290 if (pool_->scheduler_.can_dispatch())
b32b8144
FG
291 {
292 // Make a local, non-const copy of the function.
293 function_type tmp(BOOST_ASIO_MOVE_CAST(Function)(f));
294
295 detail::fenced_block b(detail::fenced_block::full);
296 boost_asio_handler_invoke_helpers::invoke(tmp, tmp);
297 return;
298 }
299
300 // Allocate and construct an operation to wrap the function.
20effc67 301 typedef detail::executor_op<function_type, OtherAllocator> op;
b32b8144
FG
302 typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
303 p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a);
304
20effc67
TL
305 BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p,
306 "thread_pool", pool_, 0, "dispatch"));
b32b8144 307
20effc67 308 pool_->scheduler_.post_immediate_completion(p.p, false);
b32b8144
FG
309 p.v = p.p = 0;
310}
311
20effc67
TL
312template <typename Allocator, unsigned int Bits>
313template <typename Function, typename OtherAllocator>
314void thread_pool::basic_executor_type<Allocator, Bits>::post(
315 BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const
b32b8144
FG
316{
317 typedef typename decay<Function>::type function_type;
318
319 // Allocate and construct an operation to wrap the function.
20effc67 320 typedef detail::executor_op<function_type, OtherAllocator> op;
b32b8144
FG
321 typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
322 p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a);
323
20effc67
TL
324 BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p,
325 "thread_pool", pool_, 0, "post"));
b32b8144 326
20effc67 327 pool_->scheduler_.post_immediate_completion(p.p, false);
b32b8144
FG
328 p.v = p.p = 0;
329}
330
20effc67
TL
331template <typename Allocator, unsigned int Bits>
332template <typename Function, typename OtherAllocator>
333void thread_pool::basic_executor_type<Allocator, Bits>::defer(
334 BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const
b32b8144
FG
335{
336 typedef typename decay<Function>::type function_type;
337
338 // Allocate and construct an operation to wrap the function.
20effc67 339 typedef detail::executor_op<function_type, OtherAllocator> op;
b32b8144
FG
340 typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
341 p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a);
342
20effc67
TL
343 BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p,
344 "thread_pool", pool_, 0, "defer"));
b32b8144 345
20effc67 346 pool_->scheduler_.post_immediate_completion(p.p, true);
b32b8144
FG
347 p.v = p.p = 0;
348}
20effc67 349#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
b32b8144
FG
350
351} // namespace asio
352} // namespace boost
353
354#include <boost/asio/detail/pop_options.hpp>
355
356#endif // BOOST_ASIO_IMPL_THREAD_POOL_HPP