]>
Commit | Line | Data |
---|---|---|
b32b8144 FG |
1 | // |
2 | // impl/io_context.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_IO_CONTEXT_HPP | |
12 | #define BOOST_ASIO_IMPL_IO_CONTEXT_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/completion_handler.hpp> | |
19 | #include <boost/asio/detail/executor_op.hpp> | |
20 | #include <boost/asio/detail/fenced_block.hpp> | |
21 | #include <boost/asio/detail/handler_type_requirements.hpp> | |
92f5a8d4 | 22 | #include <boost/asio/detail/non_const_lvalue.hpp> |
b32b8144 FG |
23 | #include <boost/asio/detail/service_registry.hpp> |
24 | #include <boost/asio/detail/throw_error.hpp> | |
25 | #include <boost/asio/detail/type_traits.hpp> | |
26 | ||
27 | #include <boost/asio/detail/push_options.hpp> | |
28 | ||
29 | namespace boost { | |
30 | namespace asio { | |
31 | ||
20effc67 TL |
32 | #if !defined(GENERATING_DOCUMENTATION) |
33 | ||
b32b8144 FG |
34 | template <typename Service> |
35 | inline Service& use_service(io_context& ioc) | |
36 | { | |
37 | // Check that Service meets the necessary type requirements. | |
38 | (void)static_cast<execution_context::service*>(static_cast<Service*>(0)); | |
39 | (void)static_cast<const execution_context::id*>(&Service::id); | |
40 | ||
41 | return ioc.service_registry_->template use_service<Service>(ioc); | |
42 | } | |
43 | ||
44 | template <> | |
45 | inline detail::io_context_impl& use_service<detail::io_context_impl>( | |
46 | io_context& ioc) | |
47 | { | |
48 | return ioc.impl_; | |
49 | } | |
50 | ||
92f5a8d4 TL |
51 | #endif // !defined(GENERATING_DOCUMENTATION) |
52 | ||
b32b8144 FG |
53 | inline io_context::executor_type |
54 | io_context::get_executor() BOOST_ASIO_NOEXCEPT | |
55 | { | |
56 | return executor_type(*this); | |
57 | } | |
58 | ||
59 | #if defined(BOOST_ASIO_HAS_CHRONO) | |
60 | ||
61 | template <typename Rep, typename Period> | |
62 | std::size_t io_context::run_for( | |
63 | const chrono::duration<Rep, Period>& rel_time) | |
64 | { | |
65 | return this->run_until(chrono::steady_clock::now() + rel_time); | |
66 | } | |
67 | ||
68 | template <typename Clock, typename Duration> | |
69 | std::size_t io_context::run_until( | |
70 | const chrono::time_point<Clock, Duration>& abs_time) | |
71 | { | |
72 | std::size_t n = 0; | |
73 | while (this->run_one_until(abs_time)) | |
74 | if (n != (std::numeric_limits<std::size_t>::max)()) | |
75 | ++n; | |
76 | return n; | |
77 | } | |
78 | ||
79 | template <typename Rep, typename Period> | |
80 | std::size_t io_context::run_one_for( | |
81 | const chrono::duration<Rep, Period>& rel_time) | |
82 | { | |
83 | return this->run_one_until(chrono::steady_clock::now() + rel_time); | |
84 | } | |
85 | ||
86 | template <typename Clock, typename Duration> | |
87 | std::size_t io_context::run_one_until( | |
88 | const chrono::time_point<Clock, Duration>& abs_time) | |
89 | { | |
90 | typename Clock::time_point now = Clock::now(); | |
91 | while (now < abs_time) | |
92 | { | |
93 | typename Clock::duration rel_time = abs_time - now; | |
94 | if (rel_time > chrono::seconds(1)) | |
95 | rel_time = chrono::seconds(1); | |
96 | ||
97 | boost::system::error_code ec; | |
98 | std::size_t s = impl_.wait_one( | |
99 | static_cast<long>(chrono::duration_cast< | |
100 | chrono::microseconds>(rel_time).count()), ec); | |
101 | boost::asio::detail::throw_error(ec); | |
102 | ||
103 | if (s || impl_.stopped()) | |
104 | return s; | |
105 | ||
106 | now = Clock::now(); | |
107 | } | |
108 | ||
109 | return 0; | |
110 | } | |
111 | ||
112 | #endif // defined(BOOST_ASIO_HAS_CHRONO) | |
113 | ||
114 | #if !defined(BOOST_ASIO_NO_DEPRECATED) | |
115 | ||
116 | inline void io_context::reset() | |
117 | { | |
118 | restart(); | |
119 | } | |
120 | ||
92f5a8d4 TL |
121 | struct io_context::initiate_dispatch |
122 | { | |
123 | template <typename LegacyCompletionHandler> | |
124 | void operator()(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler, | |
125 | io_context* self) const | |
126 | { | |
127 | // If you get an error on the following line it means that your handler does | |
128 | // not meet the documented type requirements for a LegacyCompletionHandler. | |
129 | BOOST_ASIO_LEGACY_COMPLETION_HANDLER_CHECK( | |
130 | LegacyCompletionHandler, handler) type_check; | |
131 | ||
132 | detail::non_const_lvalue<LegacyCompletionHandler> handler2(handler); | |
133 | if (self->impl_.can_dispatch()) | |
134 | { | |
135 | detail::fenced_block b(detail::fenced_block::full); | |
136 | boost_asio_handler_invoke_helpers::invoke( | |
137 | handler2.value, handler2.value); | |
138 | } | |
139 | else | |
140 | { | |
141 | // Allocate and construct an operation to wrap the handler. | |
142 | typedef detail::completion_handler< | |
20effc67 | 143 | typename decay<LegacyCompletionHandler>::type, executor_type> op; |
92f5a8d4 TL |
144 | typename op::ptr p = { detail::addressof(handler2.value), |
145 | op::ptr::allocate(handler2.value), 0 }; | |
20effc67 | 146 | p.p = new (p.v) op(handler2.value, self->get_executor()); |
92f5a8d4 TL |
147 | |
148 | BOOST_ASIO_HANDLER_CREATION((*self, *p.p, | |
149 | "io_context", self, 0, "dispatch")); | |
150 | ||
151 | self->impl_.do_dispatch(p.p); | |
152 | p.v = p.p = 0; | |
153 | } | |
154 | } | |
155 | }; | |
156 | ||
11fdf7f2 | 157 | template <typename LegacyCompletionHandler> |
92f5a8d4 | 158 | BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(LegacyCompletionHandler, void ()) |
11fdf7f2 | 159 | io_context::dispatch(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler) |
b32b8144 | 160 | { |
92f5a8d4 TL |
161 | return async_initiate<LegacyCompletionHandler, void ()>( |
162 | initiate_dispatch(), handler, this); | |
163 | } | |
b32b8144 | 164 | |
92f5a8d4 TL |
165 | struct io_context::initiate_post |
166 | { | |
167 | template <typename LegacyCompletionHandler> | |
168 | void operator()(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler, | |
169 | io_context* self) const | |
b32b8144 | 170 | { |
92f5a8d4 TL |
171 | // If you get an error on the following line it means that your handler does |
172 | // not meet the documented type requirements for a LegacyCompletionHandler. | |
173 | BOOST_ASIO_LEGACY_COMPLETION_HANDLER_CHECK( | |
174 | LegacyCompletionHandler, handler) type_check; | |
175 | ||
176 | detail::non_const_lvalue<LegacyCompletionHandler> handler2(handler); | |
177 | ||
178 | bool is_continuation = | |
179 | boost_asio_handler_cont_helpers::is_continuation(handler2.value); | |
180 | ||
b32b8144 FG |
181 | // Allocate and construct an operation to wrap the handler. |
182 | typedef detail::completion_handler< | |
20effc67 | 183 | typename decay<LegacyCompletionHandler>::type, executor_type> op; |
92f5a8d4 TL |
184 | typename op::ptr p = { detail::addressof(handler2.value), |
185 | op::ptr::allocate(handler2.value), 0 }; | |
20effc67 | 186 | p.p = new (p.v) op(handler2.value, self->get_executor()); |
b32b8144 | 187 | |
92f5a8d4 TL |
188 | BOOST_ASIO_HANDLER_CREATION((*self, *p.p, |
189 | "io_context", self, 0, "post")); | |
b32b8144 | 190 | |
92f5a8d4 | 191 | self->impl_.post_immediate_completion(p.p, is_continuation); |
b32b8144 FG |
192 | p.v = p.p = 0; |
193 | } | |
92f5a8d4 | 194 | }; |
b32b8144 | 195 | |
11fdf7f2 | 196 | template <typename LegacyCompletionHandler> |
92f5a8d4 | 197 | BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(LegacyCompletionHandler, void ()) |
11fdf7f2 | 198 | io_context::post(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler) |
b32b8144 | 199 | { |
92f5a8d4 TL |
200 | return async_initiate<LegacyCompletionHandler, void ()>( |
201 | initiate_post(), handler, this); | |
b32b8144 FG |
202 | } |
203 | ||
204 | template <typename Handler> | |
205 | #if defined(GENERATING_DOCUMENTATION) | |
206 | unspecified | |
207 | #else | |
208 | inline detail::wrapped_handler<io_context&, Handler> | |
209 | #endif | |
210 | io_context::wrap(Handler handler) | |
211 | { | |
212 | return detail::wrapped_handler<io_context&, Handler>(*this, handler); | |
213 | } | |
214 | ||
215 | #endif // !defined(BOOST_ASIO_NO_DEPRECATED) | |
216 | ||
1e59de90 | 217 | template <typename Allocator, uintptr_t Bits> |
20effc67 TL |
218 | io_context::basic_executor_type<Allocator, Bits>& |
219 | io_context::basic_executor_type<Allocator, Bits>::operator=( | |
220 | const basic_executor_type& other) BOOST_ASIO_NOEXCEPT | |
b32b8144 | 221 | { |
20effc67 TL |
222 | if (this != &other) |
223 | { | |
1e59de90 TL |
224 | static_cast<Allocator&>(*this) = static_cast<const Allocator&>(other); |
225 | io_context* old_io_context = context_ptr(); | |
226 | target_ = other.target_; | |
20effc67 TL |
227 | if (Bits & outstanding_work_tracked) |
228 | { | |
1e59de90 TL |
229 | if (context_ptr()) |
230 | context_ptr()->impl_.work_started(); | |
20effc67 TL |
231 | if (old_io_context) |
232 | old_io_context->impl_.work_finished(); | |
233 | } | |
234 | } | |
235 | return *this; | |
b32b8144 FG |
236 | } |
237 | ||
20effc67 | 238 | #if defined(BOOST_ASIO_HAS_MOVE) |
1e59de90 | 239 | template <typename Allocator, uintptr_t Bits> |
20effc67 TL |
240 | io_context::basic_executor_type<Allocator, Bits>& |
241 | io_context::basic_executor_type<Allocator, Bits>::operator=( | |
242 | basic_executor_type&& other) BOOST_ASIO_NOEXCEPT | |
b32b8144 | 243 | { |
20effc67 TL |
244 | if (this != &other) |
245 | { | |
1e59de90 TL |
246 | static_cast<Allocator&>(*this) = static_cast<Allocator&&>(other); |
247 | io_context* old_io_context = context_ptr(); | |
248 | target_ = other.target_; | |
20effc67 | 249 | if (Bits & outstanding_work_tracked) |
1e59de90 TL |
250 | { |
251 | other.target_ = 0; | |
252 | if (old_io_context) | |
253 | old_io_context->impl_.work_finished(); | |
254 | } | |
20effc67 TL |
255 | } |
256 | return *this; | |
b32b8144 | 257 | } |
20effc67 | 258 | #endif // defined(BOOST_ASIO_HAS_MOVE) |
b32b8144 | 259 | |
1e59de90 | 260 | template <typename Allocator, uintptr_t Bits> |
20effc67 TL |
261 | inline bool io_context::basic_executor_type<Allocator, |
262 | Bits>::running_in_this_thread() const BOOST_ASIO_NOEXCEPT | |
b32b8144 | 263 | { |
1e59de90 | 264 | return context_ptr()->impl_.can_dispatch(); |
b32b8144 FG |
265 | } |
266 | ||
1e59de90 | 267 | template <typename Allocator, uintptr_t Bits> |
20effc67 TL |
268 | template <typename Function> |
269 | void io_context::basic_executor_type<Allocator, Bits>::execute( | |
270 | BOOST_ASIO_MOVE_ARG(Function) f) const | |
271 | { | |
272 | typedef typename decay<Function>::type function_type; | |
273 | ||
274 | // Invoke immediately if the blocking.possibly property is enabled and we are | |
275 | // already inside the thread pool. | |
1e59de90 | 276 | if ((bits() & blocking_never) == 0 && context_ptr()->impl_.can_dispatch()) |
20effc67 TL |
277 | { |
278 | // Make a local, non-const copy of the function. | |
279 | function_type tmp(BOOST_ASIO_MOVE_CAST(Function)(f)); | |
280 | ||
281 | #if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ | |
282 | && !defined(BOOST_ASIO_NO_EXCEPTIONS) | |
283 | try | |
284 | { | |
285 | #endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) | |
286 | // && !defined(BOOST_ASIO_NO_EXCEPTIONS) | |
287 | detail::fenced_block b(detail::fenced_block::full); | |
288 | boost_asio_handler_invoke_helpers::invoke(tmp, tmp); | |
289 | return; | |
290 | #if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ | |
291 | && !defined(BOOST_ASIO_NO_EXCEPTIONS) | |
292 | } | |
293 | catch (...) | |
294 | { | |
1e59de90 | 295 | context_ptr()->impl_.capture_current_exception(); |
20effc67 TL |
296 | return; |
297 | } | |
298 | #endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) | |
299 | // && !defined(BOOST_ASIO_NO_EXCEPTIONS) | |
300 | } | |
301 | ||
302 | // Allocate and construct an operation to wrap the function. | |
303 | typedef detail::executor_op<function_type, Allocator, detail::operation> op; | |
1e59de90 TL |
304 | typename op::ptr p = { |
305 | detail::addressof(static_cast<const Allocator&>(*this)), | |
306 | op::ptr::allocate(static_cast<const Allocator&>(*this)), 0 }; | |
307 | p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), | |
308 | static_cast<const Allocator&>(*this)); | |
20effc67 | 309 | |
1e59de90 TL |
310 | BOOST_ASIO_HANDLER_CREATION((*context_ptr(), *p.p, |
311 | "io_context", context_ptr(), 0, "execute")); | |
20effc67 | 312 | |
1e59de90 TL |
313 | context_ptr()->impl_.post_immediate_completion(p.p, |
314 | (bits() & relationship_continuation) != 0); | |
20effc67 TL |
315 | p.v = p.p = 0; |
316 | } | |
317 | ||
318 | #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) | |
1e59de90 | 319 | template <typename Allocator, uintptr_t Bits> |
20effc67 TL |
320 | inline io_context& io_context::basic_executor_type< |
321 | Allocator, Bits>::context() const BOOST_ASIO_NOEXCEPT | |
322 | { | |
1e59de90 | 323 | return *context_ptr(); |
20effc67 TL |
324 | } |
325 | ||
1e59de90 | 326 | template <typename Allocator, uintptr_t Bits> |
20effc67 TL |
327 | inline void io_context::basic_executor_type<Allocator, |
328 | Bits>::on_work_started() const BOOST_ASIO_NOEXCEPT | |
329 | { | |
1e59de90 | 330 | context_ptr()->impl_.work_started(); |
20effc67 TL |
331 | } |
332 | ||
1e59de90 | 333 | template <typename Allocator, uintptr_t Bits> |
20effc67 TL |
334 | inline void io_context::basic_executor_type<Allocator, |
335 | Bits>::on_work_finished() const BOOST_ASIO_NOEXCEPT | |
336 | { | |
1e59de90 | 337 | context_ptr()->impl_.work_finished(); |
20effc67 TL |
338 | } |
339 | ||
1e59de90 | 340 | template <typename Allocator, uintptr_t Bits> |
20effc67 TL |
341 | template <typename Function, typename OtherAllocator> |
342 | void io_context::basic_executor_type<Allocator, Bits>::dispatch( | |
343 | BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const | |
b32b8144 FG |
344 | { |
345 | typedef typename decay<Function>::type function_type; | |
346 | ||
347 | // Invoke immediately if we are already inside the thread pool. | |
1e59de90 | 348 | if (context_ptr()->impl_.can_dispatch()) |
b32b8144 FG |
349 | { |
350 | // Make a local, non-const copy of the function. | |
351 | function_type tmp(BOOST_ASIO_MOVE_CAST(Function)(f)); | |
352 | ||
353 | detail::fenced_block b(detail::fenced_block::full); | |
354 | boost_asio_handler_invoke_helpers::invoke(tmp, tmp); | |
355 | return; | |
356 | } | |
357 | ||
358 | // Allocate and construct an operation to wrap the function. | |
20effc67 TL |
359 | typedef detail::executor_op<function_type, |
360 | OtherAllocator, detail::operation> op; | |
b32b8144 FG |
361 | typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; |
362 | p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); | |
363 | ||
1e59de90 TL |
364 | BOOST_ASIO_HANDLER_CREATION((*context_ptr(), *p.p, |
365 | "io_context", context_ptr(), 0, "dispatch")); | |
b32b8144 | 366 | |
1e59de90 | 367 | context_ptr()->impl_.post_immediate_completion(p.p, false); |
b32b8144 FG |
368 | p.v = p.p = 0; |
369 | } | |
370 | ||
1e59de90 | 371 | template <typename Allocator, uintptr_t Bits> |
20effc67 TL |
372 | template <typename Function, typename OtherAllocator> |
373 | void io_context::basic_executor_type<Allocator, Bits>::post( | |
374 | BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const | |
b32b8144 FG |
375 | { |
376 | typedef typename decay<Function>::type function_type; | |
377 | ||
378 | // Allocate and construct an operation to wrap the function. | |
20effc67 TL |
379 | typedef detail::executor_op<function_type, |
380 | OtherAllocator, detail::operation> op; | |
b32b8144 FG |
381 | typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; |
382 | p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); | |
383 | ||
1e59de90 TL |
384 | BOOST_ASIO_HANDLER_CREATION((*context_ptr(), *p.p, |
385 | "io_context", context_ptr(), 0, "post")); | |
b32b8144 | 386 | |
1e59de90 | 387 | context_ptr()->impl_.post_immediate_completion(p.p, false); |
b32b8144 FG |
388 | p.v = p.p = 0; |
389 | } | |
390 | ||
1e59de90 | 391 | template <typename Allocator, uintptr_t Bits> |
20effc67 TL |
392 | template <typename Function, typename OtherAllocator> |
393 | void io_context::basic_executor_type<Allocator, Bits>::defer( | |
394 | BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const | |
b32b8144 FG |
395 | { |
396 | typedef typename decay<Function>::type function_type; | |
397 | ||
398 | // Allocate and construct an operation to wrap the function. | |
20effc67 TL |
399 | typedef detail::executor_op<function_type, |
400 | OtherAllocator, detail::operation> op; | |
b32b8144 FG |
401 | typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; |
402 | p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); | |
403 | ||
1e59de90 TL |
404 | BOOST_ASIO_HANDLER_CREATION((*context_ptr(), *p.p, |
405 | "io_context", context_ptr(), 0, "defer")); | |
b32b8144 | 406 | |
1e59de90 | 407 | context_ptr()->impl_.post_immediate_completion(p.p, true); |
b32b8144 FG |
408 | p.v = p.p = 0; |
409 | } | |
20effc67 | 410 | #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) |
b32b8144 FG |
411 | |
412 | #if !defined(BOOST_ASIO_NO_DEPRECATED) | |
413 | inline io_context::work::work(boost::asio::io_context& io_context) | |
414 | : io_context_impl_(io_context.impl_) | |
415 | { | |
416 | io_context_impl_.work_started(); | |
417 | } | |
418 | ||
419 | inline io_context::work::work(const work& other) | |
420 | : io_context_impl_(other.io_context_impl_) | |
421 | { | |
422 | io_context_impl_.work_started(); | |
423 | } | |
424 | ||
425 | inline io_context::work::~work() | |
426 | { | |
427 | io_context_impl_.work_finished(); | |
428 | } | |
429 | ||
430 | inline boost::asio::io_context& io_context::work::get_io_context() | |
431 | { | |
432 | return static_cast<boost::asio::io_context&>(io_context_impl_.context()); | |
433 | } | |
b32b8144 FG |
434 | #endif // !defined(BOOST_ASIO_NO_DEPRECATED) |
435 | ||
436 | inline boost::asio::io_context& io_context::service::get_io_context() | |
437 | { | |
438 | return static_cast<boost::asio::io_context&>(context()); | |
439 | } | |
440 | ||
b32b8144 FG |
441 | } // namespace asio |
442 | } // namespace boost | |
443 | ||
444 | #include <boost/asio/detail/pop_options.hpp> | |
445 | ||
446 | #endif // BOOST_ASIO_IMPL_IO_CONTEXT_HPP |