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

source code of boost/libs/asio/include/boost/asio/impl/io_context.hpp