1//
2// 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_IO_CONTEXT_HPP
12#define BOOST_ASIO_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/config.hpp>
19#include <cstddef>
20#include <stdexcept>
21#include <typeinfo>
22#include <boost/asio/async_result.hpp>
23#include <boost/asio/detail/chrono.hpp>
24#include <boost/asio/detail/concurrency_hint.hpp>
25#include <boost/asio/detail/cstdint.hpp>
26#include <boost/asio/detail/wrapped_handler.hpp>
27#include <boost/system/error_code.hpp>
28#include <boost/asio/execution.hpp>
29#include <boost/asio/execution_context.hpp>
30
31#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
32# include <boost/asio/detail/winsock_init.hpp>
33#elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \
34 || defined(__osf__)
35# include <boost/asio/detail/signal_init.hpp>
36#endif
37
38#if defined(BOOST_ASIO_HAS_IOCP)
39# include <boost/asio/detail/win_iocp_io_context.hpp>
40#else
41# include <boost/asio/detail/scheduler.hpp>
42#endif
43
44#include <boost/asio/detail/push_options.hpp>
45
46namespace boost {
47namespace asio {
48
49namespace detail {
50#if defined(BOOST_ASIO_HAS_IOCP)
51 typedef win_iocp_io_context io_context_impl;
52 class win_iocp_overlapped_ptr;
53#else
54 typedef scheduler io_context_impl;
55#endif
56
57 struct io_context_bits
58 {
59 static constexpr uintptr_t blocking_never = 1;
60 static constexpr uintptr_t relationship_continuation = 2;
61 static constexpr uintptr_t outstanding_work_tracked = 4;
62 static constexpr uintptr_t runtime_bits = 3;
63 };
64} // namespace detail
65
66/// Provides core I/O functionality.
67/**
68 * The io_context class provides the core I/O functionality for users of the
69 * asynchronous I/O objects, including:
70 *
71 * @li boost::asio::ip::tcp::socket
72 * @li boost::asio::ip::tcp::acceptor
73 * @li boost::asio::ip::udp::socket
74 * @li boost::asio::deadline_timer.
75 *
76 * The io_context class also includes facilities intended for developers of
77 * custom asynchronous services.
78 *
79 * @par Thread Safety
80 * @e Distinct @e objects: Safe.@n
81 * @e Shared @e objects: Safe, with the specific exceptions of the restart()
82 * and notify_fork() functions. Calling restart() while there are unfinished
83 * run(), run_one(), run_for(), run_until(), poll() or poll_one() calls results
84 * in undefined behaviour. The notify_fork() function should not be called
85 * while any io_context function, or any function on an I/O object that is
86 * associated with the io_context, is being called in another thread.
87 *
88 * @par Concepts:
89 * Dispatcher.
90 *
91 * @par Synchronous and asynchronous operations
92 *
93 * Synchronous operations on I/O objects implicitly run the io_context object
94 * for an individual operation. The io_context functions run(), run_one(),
95 * run_for(), run_until(), poll() or poll_one() must be called for the
96 * io_context to perform asynchronous operations on behalf of a C++ program.
97 * Notification that an asynchronous operation has completed is delivered by
98 * invocation of the associated handler. Handlers are invoked only by a thread
99 * that is currently calling any overload of run(), run_one(), run_for(),
100 * run_until(), poll() or poll_one() for the io_context.
101 *
102 * @par Effect of exceptions thrown from handlers
103 *
104 * If an exception is thrown from a handler, the exception is allowed to
105 * propagate through the throwing thread's invocation of run(), run_one(),
106 * run_for(), run_until(), poll() or poll_one(). No other threads that are
107 * calling any of these functions are affected. It is then the responsibility
108 * of the application to catch the exception.
109 *
110 * After the exception has been caught, the run(), run_one(), run_for(),
111 * run_until(), poll() or poll_one() call may be restarted @em without the need
112 * for an intervening call to restart(). This allows the thread to rejoin the
113 * io_context object's thread pool without impacting any other threads in the
114 * pool.
115 *
116 * For example:
117 *
118 * @code
119 * boost::asio::io_context io_context;
120 * ...
121 * for (;;)
122 * {
123 * try
124 * {
125 * io_context.run();
126 * break; // run() exited normally
127 * }
128 * catch (my_exception& e)
129 * {
130 * // Deal with exception as appropriate.
131 * }
132 * }
133 * @endcode
134 *
135 * @par Submitting arbitrary tasks to the io_context
136 *
137 * To submit functions to the io_context, use the @ref boost::asio::dispatch,
138 * @ref boost::asio::post or @ref boost::asio::defer free functions.
139 *
140 * For example:
141 *
142 * @code void my_task()
143 * {
144 * ...
145 * }
146 *
147 * ...
148 *
149 * boost::asio::io_context io_context;
150 *
151 * // Submit a function to the io_context.
152 * boost::asio::post(io_context, my_task);
153 *
154 * // Submit a lambda object to the io_context.
155 * boost::asio::post(io_context,
156 * []()
157 * {
158 * ...
159 * });
160 *
161 * // Run the io_context until it runs out of work.
162 * io_context.run(); @endcode
163 *
164 * @par Stopping the io_context from running out of work
165 *
166 * Some applications may need to prevent an io_context object's run() call from
167 * returning when there is no more work to do. For example, the io_context may
168 * be being run in a background thread that is launched prior to the
169 * application's asynchronous operations. The run() call may be kept running by
170 * using the @ref make_work_guard function to create an object of type
171 * boost::asio::executor_work_guard<io_context::executor_type>:
172 *
173 * @code boost::asio::io_context io_context;
174 * boost::asio::executor_work_guard<boost::asio::io_context::executor_type>
175 * = boost::asio::make_work_guard(io_context);
176 * ... @endcode
177 *
178 * To effect a shutdown, the application will then need to call the io_context
179 * object's stop() member function. This will cause the io_context run() call
180 * to return as soon as possible, abandoning unfinished operations and without
181 * permitting ready handlers to be dispatched.
182 *
183 * Alternatively, if the application requires that all operations and handlers
184 * be allowed to finish normally, the work object may be explicitly reset.
185 *
186 * @code boost::asio::io_context io_context;
187 * boost::asio::executor_work_guard<boost::asio::io_context::executor_type>
188 * = boost::asio::make_work_guard(io_context);
189 * ...
190 * work.reset(); // Allow run() to exit. @endcode
191 */
192class io_context
193 : public execution_context
194{
195private:
196 typedef detail::io_context_impl impl_type;
197#if defined(BOOST_ASIO_HAS_IOCP)
198 friend class detail::win_iocp_overlapped_ptr;
199#endif
200
201#if !defined(BOOST_ASIO_NO_DEPRECATED)
202 struct initiate_dispatch;
203 struct initiate_post;
204#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
205
206public:
207 template <typename Allocator, uintptr_t Bits>
208 class basic_executor_type;
209
210 template <typename Allocator, uintptr_t Bits>
211 friend class basic_executor_type;
212
213 /// Executor used to submit functions to an io_context.
214 typedef basic_executor_type<std::allocator<void>, 0> executor_type;
215
216#if !defined(BOOST_ASIO_NO_DEPRECATED)
217 class work;
218 friend class work;
219#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
220
221 class service;
222
223#if !defined(BOOST_ASIO_NO_EXTENSIONS) \
224 && !defined(BOOST_ASIO_NO_TS_EXECUTORS)
225 class strand;
226#endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
227 // && !defined(BOOST_ASIO_NO_TS_EXECUTORS)
228
229 /// The type used to count the number of handlers executed by the context.
230 typedef std::size_t count_type;
231
232 /// Constructor.
233 BOOST_ASIO_DECL io_context();
234
235 /// Constructor.
236 /**
237 * Construct with a hint about the required level of concurrency.
238 *
239 * @param concurrency_hint A suggestion to the implementation on how many
240 * threads it should allow to run simultaneously.
241 */
242 BOOST_ASIO_DECL explicit io_context(int concurrency_hint);
243
244 /// Destructor.
245 /**
246 * On destruction, the io_context performs the following sequence of
247 * operations:
248 *
249 * @li For each service object @c svc in the io_context set, in reverse order
250 * of the beginning of service object lifetime, performs
251 * @c svc->shutdown().
252 *
253 * @li Uninvoked handler objects that were scheduled for deferred invocation
254 * on the io_context, or any associated strand, are destroyed.
255 *
256 * @li For each service object @c svc in the io_context set, in reverse order
257 * of the beginning of service object lifetime, performs
258 * <tt>delete static_cast<io_context::service*>(svc)</tt>.
259 *
260 * @note The destruction sequence described above permits programs to
261 * simplify their resource management by using @c shared_ptr<>. Where an
262 * object's lifetime is tied to the lifetime of a connection (or some other
263 * sequence of asynchronous operations), a @c shared_ptr to the object would
264 * be bound into the handlers for all asynchronous operations associated with
265 * it. This works as follows:
266 *
267 * @li When a single connection ends, all associated asynchronous operations
268 * complete. The corresponding handler objects are destroyed, and all
269 * @c shared_ptr references to the objects are destroyed.
270 *
271 * @li To shut down the whole program, the io_context function stop() is
272 * called to terminate any run() calls as soon as possible. The io_context
273 * destructor defined above destroys all handlers, causing all @c shared_ptr
274 * references to all connection objects to be destroyed.
275 */
276 BOOST_ASIO_DECL ~io_context();
277
278 /// Obtains the executor associated with the io_context.
279 executor_type get_executor() noexcept;
280
281 /// Run the io_context object's event processing loop.
282 /**
283 * The run() function blocks until all work has finished and there are no
284 * more handlers to be dispatched, or until the io_context has been stopped.
285 *
286 * Multiple threads may call the run() function to set up a pool of threads
287 * from which the io_context may execute handlers. All threads that are
288 * waiting in the pool are equivalent and the io_context may choose any one
289 * of them to invoke a handler.
290 *
291 * A normal exit from the run() function implies that the io_context object
292 * is stopped (the stopped() function returns @c true). Subsequent calls to
293 * run(), run_one(), poll() or poll_one() will return immediately unless there
294 * is a prior call to restart().
295 *
296 * @return The number of handlers that were executed.
297 *
298 * @note Calling the run() function from a thread that is currently calling
299 * one of run(), run_one(), run_for(), run_until(), poll() or poll_one() on
300 * the same io_context object may introduce the potential for deadlock. It is
301 * the caller's reponsibility to avoid this.
302 *
303 * The poll() function may also be used to dispatch ready handlers, but
304 * without blocking.
305 */
306 BOOST_ASIO_DECL count_type run();
307
308#if !defined(BOOST_ASIO_NO_DEPRECATED)
309 /// (Deprecated: Use non-error_code overload.) Run the io_context object's
310 /// event processing loop.
311 /**
312 * The run() function blocks until all work has finished and there are no
313 * more handlers to be dispatched, or until the io_context has been stopped.
314 *
315 * Multiple threads may call the run() function to set up a pool of threads
316 * from which the io_context may execute handlers. All threads that are
317 * waiting in the pool are equivalent and the io_context may choose any one
318 * of them to invoke a handler.
319 *
320 * A normal exit from the run() function implies that the io_context object
321 * is stopped (the stopped() function returns @c true). Subsequent calls to
322 * run(), run_one(), poll() or poll_one() will return immediately unless there
323 * is a prior call to restart().
324 *
325 * @param ec Set to indicate what error occurred, if any.
326 *
327 * @return The number of handlers that were executed.
328 *
329 * @note Calling the run() function from a thread that is currently calling
330 * one of run(), run_one(), run_for(), run_until(), poll() or poll_one() on
331 * the same io_context object may introduce the potential for deadlock. It is
332 * the caller's reponsibility to avoid this.
333 *
334 * The poll() function may also be used to dispatch ready handlers, but
335 * without blocking.
336 */
337 BOOST_ASIO_DECL count_type run(boost::system::error_code& ec);
338#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
339
340 /// Run the io_context object's event processing loop for a specified
341 /// duration.
342 /**
343 * The run_for() function blocks until all work has finished and there are no
344 * more handlers to be dispatched, until the io_context has been stopped, or
345 * until the specified duration has elapsed.
346 *
347 * @param rel_time The duration for which the call may block.
348 *
349 * @return The number of handlers that were executed.
350 */
351 template <typename Rep, typename Period>
352 std::size_t run_for(const chrono::duration<Rep, Period>& rel_time);
353
354 /// Run the io_context object's event processing loop until a specified time.
355 /**
356 * The run_until() function blocks until all work has finished and there are
357 * no more handlers to be dispatched, until the io_context has been stopped,
358 * or until the specified time has been reached.
359 *
360 * @param abs_time The time point until which the call may block.
361 *
362 * @return The number of handlers that were executed.
363 */
364 template <typename Clock, typename Duration>
365 std::size_t run_until(const chrono::time_point<Clock, Duration>& abs_time);
366
367 /// Run the io_context object's event processing loop to execute at most one
368 /// handler.
369 /**
370 * The run_one() function blocks until one handler has been dispatched, or
371 * until the io_context has been stopped.
372 *
373 * @return The number of handlers that were executed. A zero return value
374 * implies that the io_context object is stopped (the stopped() function
375 * returns @c true). Subsequent calls to run(), run_one(), poll() or
376 * poll_one() will return immediately unless there is a prior call to
377 * restart().
378 *
379 * @note Calling the run_one() function from a thread that is currently
380 * calling one of run(), run_one(), run_for(), run_until(), poll() or
381 * poll_one() on the same io_context object may introduce the potential for
382 * deadlock. It is the caller's reponsibility to avoid this.
383 */
384 BOOST_ASIO_DECL count_type run_one();
385
386#if !defined(BOOST_ASIO_NO_DEPRECATED)
387 /// (Deprecated: Use non-error_code overload.) Run the io_context object's
388 /// event processing loop to execute at most one handler.
389 /**
390 * The run_one() function blocks until one handler has been dispatched, or
391 * until the io_context has been stopped.
392 *
393 * @return The number of handlers that were executed. A zero return value
394 * implies that the io_context object is stopped (the stopped() function
395 * returns @c true). Subsequent calls to run(), run_one(), poll() or
396 * poll_one() will return immediately unless there is a prior call to
397 * restart().
398 *
399 * @return The number of handlers that were executed.
400 *
401 * @note Calling the run_one() function from a thread that is currently
402 * calling one of run(), run_one(), run_for(), run_until(), poll() or
403 * poll_one() on the same io_context object may introduce the potential for
404 * deadlock. It is the caller's reponsibility to avoid this.
405 */
406 BOOST_ASIO_DECL count_type run_one(boost::system::error_code& ec);
407#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
408
409 /// Run the io_context object's event processing loop for a specified duration
410 /// to execute at most one handler.
411 /**
412 * The run_one_for() function blocks until one handler has been dispatched,
413 * until the io_context has been stopped, or until the specified duration has
414 * elapsed.
415 *
416 * @param rel_time The duration for which the call may block.
417 *
418 * @return The number of handlers that were executed.
419 */
420 template <typename Rep, typename Period>
421 std::size_t run_one_for(const chrono::duration<Rep, Period>& rel_time);
422
423 /// Run the io_context object's event processing loop until a specified time
424 /// to execute at most one handler.
425 /**
426 * The run_one_until() function blocks until one handler has been dispatched,
427 * until the io_context has been stopped, or until the specified time has
428 * been reached.
429 *
430 * @param abs_time The time point until which the call may block.
431 *
432 * @return The number of handlers that were executed.
433 */
434 template <typename Clock, typename Duration>
435 std::size_t run_one_until(
436 const chrono::time_point<Clock, Duration>& abs_time);
437
438 /// Run the io_context object's event processing loop to execute ready
439 /// handlers.
440 /**
441 * The poll() function runs handlers that are ready to run, without blocking,
442 * until the io_context has been stopped or there are no more ready handlers.
443 *
444 * @return The number of handlers that were executed.
445 */
446 BOOST_ASIO_DECL count_type poll();
447
448#if !defined(BOOST_ASIO_NO_DEPRECATED)
449 /// (Deprecated: Use non-error_code overload.) Run the io_context object's
450 /// event processing loop to execute ready handlers.
451 /**
452 * The poll() function runs handlers that are ready to run, without blocking,
453 * until the io_context has been stopped or there are no more ready handlers.
454 *
455 * @param ec Set to indicate what error occurred, if any.
456 *
457 * @return The number of handlers that were executed.
458 */
459 BOOST_ASIO_DECL count_type poll(boost::system::error_code& ec);
460#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
461
462 /// Run the io_context object's event processing loop to execute one ready
463 /// handler.
464 /**
465 * The poll_one() function runs at most one handler that is ready to run,
466 * without blocking.
467 *
468 * @return The number of handlers that were executed.
469 */
470 BOOST_ASIO_DECL count_type poll_one();
471
472#if !defined(BOOST_ASIO_NO_DEPRECATED)
473 /// (Deprecated: Use non-error_code overload.) Run the io_context object's
474 /// event processing loop to execute one ready handler.
475 /**
476 * The poll_one() function runs at most one handler that is ready to run,
477 * without blocking.
478 *
479 * @param ec Set to indicate what error occurred, if any.
480 *
481 * @return The number of handlers that were executed.
482 */
483 BOOST_ASIO_DECL count_type poll_one(boost::system::error_code& ec);
484#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
485
486 /// Stop the io_context object's event processing loop.
487 /**
488 * This function does not block, but instead simply signals the io_context to
489 * stop. All invocations of its run() or run_one() member functions should
490 * return as soon as possible. Subsequent calls to run(), run_one(), poll()
491 * or poll_one() will return immediately until restart() is called.
492 */
493 BOOST_ASIO_DECL void stop();
494
495 /// Determine whether the io_context object has been stopped.
496 /**
497 * This function is used to determine whether an io_context object has been
498 * stopped, either through an explicit call to stop(), or due to running out
499 * of work. When an io_context object is stopped, calls to run(), run_one(),
500 * poll() or poll_one() will return immediately without invoking any
501 * handlers.
502 *
503 * @return @c true if the io_context object is stopped, otherwise @c false.
504 */
505 BOOST_ASIO_DECL bool stopped() const;
506
507 /// Restart the io_context in preparation for a subsequent run() invocation.
508 /**
509 * This function must be called prior to any second or later set of
510 * invocations of the run(), run_one(), poll() or poll_one() functions when a
511 * previous invocation of these functions returned due to the io_context
512 * being stopped or running out of work. After a call to restart(), the
513 * io_context object's stopped() function will return @c false.
514 *
515 * This function must not be called while there are any unfinished calls to
516 * the run(), run_one(), poll() or poll_one() functions.
517 */
518 BOOST_ASIO_DECL void restart();
519
520#if !defined(BOOST_ASIO_NO_DEPRECATED)
521 /// (Deprecated: Use restart().) Reset the io_context in preparation for a
522 /// subsequent run() invocation.
523 /**
524 * This function must be called prior to any second or later set of
525 * invocations of the run(), run_one(), poll() or poll_one() functions when a
526 * previous invocation of these functions returned due to the io_context
527 * being stopped or running out of work. After a call to restart(), the
528 * io_context object's stopped() function will return @c false.
529 *
530 * This function must not be called while there are any unfinished calls to
531 * the run(), run_one(), poll() or poll_one() functions.
532 */
533 void reset();
534
535 /// (Deprecated: Use boost::asio::dispatch().) Request the io_context to
536 /// invoke the given handler.
537 /**
538 * This function is used to ask the io_context to execute the given handler.
539 *
540 * The io_context guarantees that the handler will only be called in a thread
541 * in which the run(), run_one(), poll() or poll_one() member functions is
542 * currently being invoked. The handler may be executed inside this function
543 * if the guarantee can be met.
544 *
545 * @param handler The handler to be called. The io_context will make
546 * a copy of the handler object as required. The function signature of the
547 * handler must be: @code void handler(); @endcode
548 *
549 * @note This function throws an exception only if:
550 *
551 * @li the handler's associated allocator; or
552 *
553 * @li the handler's copy constructor
554 *
555 * throws an exception.
556 */
557 template <typename LegacyCompletionHandler>
558 auto dispatch(LegacyCompletionHandler&& handler)
559 -> decltype(
560 async_initiate<LegacyCompletionHandler, void ()>(
561 declval<initiate_dispatch>(), handler, this));
562
563 /// (Deprecated: Use boost::asio::post().) Request the io_context to invoke
564 /// the given handler and return immediately.
565 /**
566 * This function is used to ask the io_context to execute the given handler,
567 * but without allowing the io_context to call the handler from inside this
568 * function.
569 *
570 * The io_context guarantees that the handler will only be called in a thread
571 * in which the run(), run_one(), poll() or poll_one() member functions is
572 * currently being invoked.
573 *
574 * @param handler The handler to be called. The io_context will make
575 * a copy of the handler object as required. The function signature of the
576 * handler must be: @code void handler(); @endcode
577 *
578 * @note This function throws an exception only if:
579 *
580 * @li the handler's associated allocator; or
581 *
582 * @li the handler's copy constructor
583 *
584 * throws an exception.
585 */
586 template <typename LegacyCompletionHandler>
587 auto post(LegacyCompletionHandler&& handler)
588 -> decltype(
589 async_initiate<LegacyCompletionHandler, void ()>(
590 declval<initiate_post>(), handler, this));
591
592 /// (Deprecated: Use boost::asio::bind_executor().) Create a new handler that
593 /// automatically dispatches the wrapped handler on the io_context.
594 /**
595 * This function is used to create a new handler function object that, when
596 * invoked, will automatically pass the wrapped handler to the io_context
597 * object's dispatch function.
598 *
599 * @param handler The handler to be wrapped. The io_context will make a copy
600 * of the handler object as required. The function signature of the handler
601 * must be: @code void handler(A1 a1, ... An an); @endcode
602 *
603 * @return A function object that, when invoked, passes the wrapped handler to
604 * the io_context object's dispatch function. Given a function object with the
605 * signature:
606 * @code R f(A1 a1, ... An an); @endcode
607 * If this function object is passed to the wrap function like so:
608 * @code io_context.wrap(f); @endcode
609 * then the return value is a function object with the signature
610 * @code void g(A1 a1, ... An an); @endcode
611 * that, when invoked, executes code equivalent to:
612 * @code io_context.dispatch(boost::bind(f, a1, ... an)); @endcode
613 */
614 template <typename Handler>
615#if defined(GENERATING_DOCUMENTATION)
616 unspecified
617#else
618 detail::wrapped_handler<io_context&, Handler>
619#endif
620 wrap(Handler handler);
621#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
622
623private:
624 io_context(const io_context&) = delete;
625 io_context& operator=(const io_context&) = delete;
626
627 // Helper function to add the implementation.
628 BOOST_ASIO_DECL impl_type& add_impl(impl_type* impl);
629
630 // Backwards compatible overload for use with services derived from
631 // io_context::service.
632 template <typename Service>
633 friend Service& use_service(io_context& ioc);
634
635#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
636 detail::winsock_init<> init_;
637#elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \
638 || defined(__osf__)
639 detail::signal_init<> init_;
640#endif
641
642 // The implementation.
643 impl_type& impl_;
644};
645
646/// Executor implementation type used to submit functions to an io_context.
647template <typename Allocator, uintptr_t Bits>
648class io_context::basic_executor_type :
649 detail::io_context_bits, Allocator
650{
651public:
652 /// Copy constructor.
653 basic_executor_type(const basic_executor_type& other) noexcept
654 : Allocator(static_cast<const Allocator&>(other)),
655 target_(other.target_)
656 {
657 if (Bits & outstanding_work_tracked)
658 if (context_ptr())
659 context_ptr()->impl_.work_started();
660 }
661
662 /// Move constructor.
663 basic_executor_type(basic_executor_type&& other) noexcept
664 : Allocator(static_cast<Allocator&&>(other)),
665 target_(other.target_)
666 {
667 if (Bits & outstanding_work_tracked)
668 other.target_ = 0;
669 }
670
671 /// Destructor.
672 ~basic_executor_type() noexcept
673 {
674 if (Bits & outstanding_work_tracked)
675 if (context_ptr())
676 context_ptr()->impl_.work_finished();
677 }
678
679 /// Assignment operator.
680 basic_executor_type& operator=(const basic_executor_type& other) noexcept;
681
682 /// Move assignment operator.
683 basic_executor_type& operator=(basic_executor_type&& other) noexcept;
684
685#if !defined(GENERATING_DOCUMENTATION)
686private:
687 friend struct boost_asio_require_fn::impl;
688 friend struct boost_asio_prefer_fn::impl;
689#endif // !defined(GENERATING_DOCUMENTATION)
690
691 /// Obtain an executor with the @c blocking.possibly property.
692 /**
693 * Do not call this function directly. It is intended for use with the
694 * boost::asio::require customisation point.
695 *
696 * For example:
697 * @code auto ex1 = my_io_context.get_executor();
698 * auto ex2 = boost::asio::require(ex1,
699 * boost::asio::execution::blocking.possibly); @endcode
700 */
701 constexpr basic_executor_type require(execution::blocking_t::possibly_t) const
702 {
703 return basic_executor_type(context_ptr(),
704 *this, bits() & ~blocking_never);
705 }
706
707 /// Obtain an executor with the @c blocking.never property.
708 /**
709 * Do not call this function directly. It is intended for use with the
710 * boost::asio::require customisation point.
711 *
712 * For example:
713 * @code auto ex1 = my_io_context.get_executor();
714 * auto ex2 = boost::asio::require(ex1,
715 * boost::asio::execution::blocking.never); @endcode
716 */
717 constexpr basic_executor_type require(execution::blocking_t::never_t) const
718 {
719 return basic_executor_type(context_ptr(),
720 *this, bits() | blocking_never);
721 }
722
723 /// Obtain an executor with the @c relationship.fork property.
724 /**
725 * Do not call this function directly. It is intended for use with the
726 * boost::asio::require customisation point.
727 *
728 * For example:
729 * @code auto ex1 = my_io_context.get_executor();
730 * auto ex2 = boost::asio::require(ex1,
731 * boost::asio::execution::relationship.fork); @endcode
732 */
733 constexpr basic_executor_type require(execution::relationship_t::fork_t) const
734 {
735 return basic_executor_type(context_ptr(),
736 *this, bits() & ~relationship_continuation);
737 }
738
739 /// Obtain an executor with the @c relationship.continuation property.
740 /**
741 * Do not call this function directly. It is intended for use with the
742 * boost::asio::require customisation point.
743 *
744 * For example:
745 * @code auto ex1 = my_io_context.get_executor();
746 * auto ex2 = boost::asio::require(ex1,
747 * boost::asio::execution::relationship.continuation); @endcode
748 */
749 constexpr basic_executor_type require(
750 execution::relationship_t::continuation_t) const
751 {
752 return basic_executor_type(context_ptr(),
753 *this, bits() | relationship_continuation);
754 }
755
756 /// Obtain an executor with the @c outstanding_work.tracked property.
757 /**
758 * Do not call this function directly. It is intended for use with the
759 * boost::asio::require customisation point.
760 *
761 * For example:
762 * @code auto ex1 = my_io_context.get_executor();
763 * auto ex2 = boost::asio::require(ex1,
764 * boost::asio::execution::outstanding_work.tracked); @endcode
765 */
766 constexpr basic_executor_type<Allocator,
767 BOOST_ASIO_UNSPECIFIED(Bits | outstanding_work_tracked)>
768 require(execution::outstanding_work_t::tracked_t) const
769 {
770 return basic_executor_type<Allocator, Bits | outstanding_work_tracked>(
771 context_ptr(), *this, bits());
772 }
773
774 /// Obtain an executor with the @c outstanding_work.untracked property.
775 /**
776 * Do not call this function directly. It is intended for use with the
777 * boost::asio::require customisation point.
778 *
779 * For example:
780 * @code auto ex1 = my_io_context.get_executor();
781 * auto ex2 = boost::asio::require(ex1,
782 * boost::asio::execution::outstanding_work.untracked); @endcode
783 */
784 constexpr basic_executor_type<Allocator,
785 BOOST_ASIO_UNSPECIFIED(Bits & ~outstanding_work_tracked)>
786 require(execution::outstanding_work_t::untracked_t) const
787 {
788 return basic_executor_type<Allocator, Bits & ~outstanding_work_tracked>(
789 context_ptr(), *this, bits());
790 }
791
792 /// Obtain an executor with the specified @c allocator property.
793 /**
794 * Do not call this function directly. It is intended for use with the
795 * boost::asio::require customisation point.
796 *
797 * For example:
798 * @code auto ex1 = my_io_context.get_executor();
799 * auto ex2 = boost::asio::require(ex1,
800 * boost::asio::execution::allocator(my_allocator)); @endcode
801 */
802 template <typename OtherAllocator>
803 constexpr basic_executor_type<OtherAllocator, Bits>
804 require(execution::allocator_t<OtherAllocator> a) const
805 {
806 return basic_executor_type<OtherAllocator, Bits>(
807 context_ptr(), a.value(), bits());
808 }
809
810 /// Obtain an executor with the default @c allocator property.
811 /**
812 * Do not call this function directly. It is intended for use with the
813 * boost::asio::require customisation point.
814 *
815 * For example:
816 * @code auto ex1 = my_io_context.get_executor();
817 * auto ex2 = boost::asio::require(ex1,
818 * boost::asio::execution::allocator); @endcode
819 */
820 constexpr basic_executor_type<std::allocator<void>, Bits>
821 require(execution::allocator_t<void>) const
822 {
823 return basic_executor_type<std::allocator<void>, Bits>(
824 context_ptr(), std::allocator<void>(), bits());
825 }
826
827#if !defined(GENERATING_DOCUMENTATION)
828private:
829 friend struct boost_asio_query_fn::impl;
830 friend struct boost::asio::execution::detail::mapping_t<0>;
831 friend struct boost::asio::execution::detail::outstanding_work_t<0>;
832#endif // !defined(GENERATING_DOCUMENTATION)
833
834 /// Query the current value of the @c mapping property.
835 /**
836 * Do not call this function directly. It is intended for use with the
837 * boost::asio::query customisation point.
838 *
839 * For example:
840 * @code auto ex = my_io_context.get_executor();
841 * if (boost::asio::query(ex, boost::asio::execution::mapping)
842 * == boost::asio::execution::mapping.thread)
843 * ... @endcode
844 */
845 static constexpr execution::mapping_t query(execution::mapping_t) noexcept
846 {
847 return execution::mapping.thread;
848 }
849
850 /// Query the current value of the @c context property.
851 /**
852 * Do not call this function directly. It is intended for use with the
853 * boost::asio::query customisation point.
854 *
855 * For example:
856 * @code auto ex = my_io_context.get_executor();
857 * boost::asio::io_context& ctx = boost::asio::query(
858 * ex, boost::asio::execution::context); @endcode
859 */
860 io_context& query(execution::context_t) const noexcept
861 {
862 return *context_ptr();
863 }
864
865 /// Query the current value of the @c blocking property.
866 /**
867 * Do not call this function directly. It is intended for use with the
868 * boost::asio::query customisation point.
869 *
870 * For example:
871 * @code auto ex = my_io_context.get_executor();
872 * if (boost::asio::query(ex, boost::asio::execution::blocking)
873 * == boost::asio::execution::blocking.always)
874 * ... @endcode
875 */
876 constexpr execution::blocking_t query(execution::blocking_t) const noexcept
877 {
878 return (bits() & blocking_never)
879 ? execution::blocking_t(execution::blocking.never)
880 : execution::blocking_t(execution::blocking.possibly);
881 }
882
883 /// Query the current value of the @c relationship property.
884 /**
885 * Do not call this function directly. It is intended for use with the
886 * boost::asio::query customisation point.
887 *
888 * For example:
889 * @code auto ex = my_io_context.get_executor();
890 * if (boost::asio::query(ex, boost::asio::execution::relationship)
891 * == boost::asio::execution::relationship.continuation)
892 * ... @endcode
893 */
894 constexpr execution::relationship_t query(
895 execution::relationship_t) const noexcept
896 {
897 return (bits() & relationship_continuation)
898 ? execution::relationship_t(execution::relationship.continuation)
899 : execution::relationship_t(execution::relationship.fork);
900 }
901
902 /// Query the current value of the @c outstanding_work property.
903 /**
904 * Do not call this function directly. It is intended for use with the
905 * boost::asio::query customisation point.
906 *
907 * For example:
908 * @code auto ex = my_io_context.get_executor();
909 * if (boost::asio::query(ex, boost::asio::execution::outstanding_work)
910 * == boost::asio::execution::outstanding_work.tracked)
911 * ... @endcode
912 */
913 static constexpr execution::outstanding_work_t query(
914 execution::outstanding_work_t) noexcept
915 {
916 return (Bits & outstanding_work_tracked)
917 ? execution::outstanding_work_t(execution::outstanding_work.tracked)
918 : execution::outstanding_work_t(execution::outstanding_work.untracked);
919 }
920
921 /// Query the current value of the @c allocator property.
922 /**
923 * Do not call this function directly. It is intended for use with the
924 * boost::asio::query customisation point.
925 *
926 * For example:
927 * @code auto ex = my_io_context.get_executor();
928 * auto alloc = boost::asio::query(ex,
929 * boost::asio::execution::allocator); @endcode
930 */
931 template <typename OtherAllocator>
932 constexpr Allocator query(
933 execution::allocator_t<OtherAllocator>) const noexcept
934 {
935 return static_cast<const Allocator&>(*this);
936 }
937
938 /// Query the current value of the @c allocator property.
939 /**
940 * Do not call this function directly. It is intended for use with the
941 * boost::asio::query customisation point.
942 *
943 * For example:
944 * @code auto ex = my_io_context.get_executor();
945 * auto alloc = boost::asio::query(ex,
946 * boost::asio::execution::allocator); @endcode
947 */
948 constexpr Allocator query(execution::allocator_t<void>) const noexcept
949 {
950 return static_cast<const Allocator&>(*this);
951 }
952
953public:
954 /// Determine whether the io_context is running in the current thread.
955 /**
956 * @return @c true if the current thread is running the io_context. Otherwise
957 * returns @c false.
958 */
959 bool running_in_this_thread() const noexcept;
960
961 /// Compare two executors for equality.
962 /**
963 * Two executors are equal if they refer to the same underlying io_context.
964 */
965 friend bool operator==(const basic_executor_type& a,
966 const basic_executor_type& b) noexcept
967 {
968 return a.target_ == b.target_
969 && static_cast<const Allocator&>(a) == static_cast<const Allocator&>(b);
970 }
971
972 /// Compare two executors for inequality.
973 /**
974 * Two executors are equal if they refer to the same underlying io_context.
975 */
976 friend bool operator!=(const basic_executor_type& a,
977 const basic_executor_type& b) noexcept
978 {
979 return a.target_ != b.target_
980 || static_cast<const Allocator&>(a) != static_cast<const Allocator&>(b);
981 }
982
983 /// Execution function.
984 template <typename Function>
985 void execute(Function&& f) const;
986
987#if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
988public:
989 /// Obtain the underlying execution context.
990 io_context& context() const noexcept;
991
992 /// Inform the io_context that it has some outstanding work to do.
993 /**
994 * This function is used to inform the io_context that some work has begun.
995 * This ensures that the io_context's run() and run_one() functions do not
996 * exit while the work is underway.
997 */
998 void on_work_started() const noexcept;
999
1000 /// Inform the io_context that some work is no longer outstanding.
1001 /**
1002 * This function is used to inform the io_context that some work has
1003 * finished. Once the count of unfinished work reaches zero, the io_context
1004 * is stopped and the run() and run_one() functions may exit.
1005 */
1006 void on_work_finished() const noexcept;
1007
1008 /// Request the io_context to invoke the given function object.
1009 /**
1010 * This function is used to ask the io_context to execute the given function
1011 * object. If the current thread is running the io_context, @c dispatch()
1012 * executes the function before returning. Otherwise, the function will be
1013 * scheduled to run on the io_context.
1014 *
1015 * @param f The function object to be called. The executor will make a copy
1016 * of the handler object as required. The function signature of the function
1017 * object must be: @code void function(); @endcode
1018 *
1019 * @param a An allocator that may be used by the executor to allocate the
1020 * internal storage needed for function invocation.
1021 */
1022 template <typename Function, typename OtherAllocator>
1023 void dispatch(Function&& f, const OtherAllocator& a) const;
1024
1025 /// Request the io_context to invoke the given function object.
1026 /**
1027 * This function is used to ask the io_context to execute the given function
1028 * object. The function object will never be executed inside @c post().
1029 * Instead, it will be scheduled to run on the io_context.
1030 *
1031 * @param f The function object to be called. The executor will make a copy
1032 * of the handler object as required. The function signature of the function
1033 * object must be: @code void function(); @endcode
1034 *
1035 * @param a An allocator that may be used by the executor to allocate the
1036 * internal storage needed for function invocation.
1037 */
1038 template <typename Function, typename OtherAllocator>
1039 void post(Function&& f, const OtherAllocator& a) const;
1040
1041 /// Request the io_context to invoke the given function object.
1042 /**
1043 * This function is used to ask the io_context to execute the given function
1044 * object. The function object will never be executed inside @c defer().
1045 * Instead, it will be scheduled to run on the io_context.
1046 *
1047 * If the current thread belongs to the io_context, @c defer() will delay
1048 * scheduling the function object until the current thread returns control to
1049 * the pool.
1050 *
1051 * @param f The function object to be called. The executor will make a copy
1052 * of the handler object as required. The function signature of the function
1053 * object must be: @code void function(); @endcode
1054 *
1055 * @param a An allocator that may be used by the executor to allocate the
1056 * internal storage needed for function invocation.
1057 */
1058 template <typename Function, typename OtherAllocator>
1059 void defer(Function&& f, const OtherAllocator& a) const;
1060#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
1061
1062private:
1063 friend class io_context;
1064 template <typename, uintptr_t> friend class basic_executor_type;
1065
1066 // Constructor used by io_context::get_executor().
1067 explicit basic_executor_type(io_context& i) noexcept
1068 : Allocator(),
1069 target_(reinterpret_cast<uintptr_t>(&i))
1070 {
1071 if (Bits & outstanding_work_tracked)
1072 context_ptr()->impl_.work_started();
1073 }
1074
1075 // Constructor used by require().
1076 basic_executor_type(io_context* i,
1077 const Allocator& a, uintptr_t bits) noexcept
1078 : Allocator(a),
1079 target_(reinterpret_cast<uintptr_t>(i) | bits)
1080 {
1081 if (Bits & outstanding_work_tracked)
1082 if (context_ptr())
1083 context_ptr()->impl_.work_started();
1084 }
1085
1086 io_context* context_ptr() const noexcept
1087 {
1088 return reinterpret_cast<io_context*>(target_ & ~runtime_bits);
1089 }
1090
1091 uintptr_t bits() const noexcept
1092 {
1093 return target_ & runtime_bits;
1094 }
1095
1096 // The underlying io_context and runtime bits.
1097 uintptr_t target_;
1098};
1099
1100#if !defined(BOOST_ASIO_NO_DEPRECATED)
1101/// (Deprecated: Use executor_work_guard.) Class to inform the io_context when
1102/// it has work to do.
1103/**
1104 * The work class is used to inform the io_context when work starts and
1105 * finishes. This ensures that the io_context object's run() function will not
1106 * exit while work is underway, and that it does exit when there is no
1107 * unfinished work remaining.
1108 *
1109 * The work class is copy-constructible so that it may be used as a data member
1110 * in a handler class. It is not assignable.
1111 */
1112class io_context::work
1113{
1114public:
1115 /// Constructor notifies the io_context that work is starting.
1116 /**
1117 * The constructor is used to inform the io_context that some work has begun.
1118 * This ensures that the io_context object's run() function will not exit
1119 * while the work is underway.
1120 */
1121 explicit work(boost::asio::io_context& io_context);
1122
1123 /// Copy constructor notifies the io_context that work is starting.
1124 /**
1125 * The constructor is used to inform the io_context that some work has begun.
1126 * This ensures that the io_context object's run() function will not exit
1127 * while the work is underway.
1128 */
1129 work(const work& other);
1130
1131 /// Destructor notifies the io_context that the work is complete.
1132 /**
1133 * The destructor is used to inform the io_context that some work has
1134 * finished. Once the count of unfinished work reaches zero, the io_context
1135 * object's run() function is permitted to exit.
1136 */
1137 ~work();
1138
1139 /// Get the io_context associated with the work.
1140 boost::asio::io_context& get_io_context();
1141
1142private:
1143 // Prevent assignment.
1144 void operator=(const work& other);
1145
1146 // The io_context implementation.
1147 detail::io_context_impl& io_context_impl_;
1148};
1149#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
1150
1151/// Base class for all io_context services.
1152class io_context::service
1153 : public execution_context::service
1154{
1155public:
1156 /// Get the io_context object that owns the service.
1157 boost::asio::io_context& get_io_context();
1158
1159private:
1160 /// Destroy all user-defined handler objects owned by the service.
1161 BOOST_ASIO_DECL virtual void shutdown();
1162
1163#if !defined(BOOST_ASIO_NO_DEPRECATED)
1164 /// (Deprecated: Use shutdown().) Destroy all user-defined handler objects
1165 /// owned by the service.
1166 BOOST_ASIO_DECL virtual void shutdown_service();
1167#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
1168
1169 /// Handle notification of a fork-related event to perform any necessary
1170 /// housekeeping.
1171 /**
1172 * This function is not a pure virtual so that services only have to
1173 * implement it if necessary. The default implementation does nothing.
1174 */
1175 BOOST_ASIO_DECL virtual void notify_fork(
1176 execution_context::fork_event event);
1177
1178#if !defined(BOOST_ASIO_NO_DEPRECATED)
1179 /// (Deprecated: Use notify_fork().) Handle notification of a fork-related
1180 /// event to perform any necessary housekeeping.
1181 /**
1182 * This function is not a pure virtual so that services only have to
1183 * implement it if necessary. The default implementation does nothing.
1184 */
1185 BOOST_ASIO_DECL virtual void fork_service(
1186 execution_context::fork_event event);
1187#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
1188
1189protected:
1190 /// Constructor.
1191 /**
1192 * @param owner The io_context object that owns the service.
1193 */
1194 BOOST_ASIO_DECL service(boost::asio::io_context& owner);
1195
1196 /// Destructor.
1197 BOOST_ASIO_DECL virtual ~service();
1198};
1199
1200namespace detail {
1201
1202// Special service base class to keep classes header-file only.
1203template <typename Type>
1204class service_base
1205 : public boost::asio::io_context::service
1206{
1207public:
1208 static boost::asio::detail::service_id<Type> id;
1209
1210 // Constructor.
1211 service_base(boost::asio::io_context& io_context)
1212 : boost::asio::io_context::service(io_context)
1213 {
1214 }
1215};
1216
1217template <typename Type>
1218boost::asio::detail::service_id<Type> service_base<Type>::id;
1219
1220} // namespace detail
1221
1222#if !defined(GENERATING_DOCUMENTATION)
1223
1224namespace traits {
1225
1226#if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
1227
1228template <typename Allocator, uintptr_t Bits>
1229struct equality_comparable<
1230 boost::asio::io_context::basic_executor_type<Allocator, Bits>
1231 >
1232{
1233 static constexpr bool is_valid = true;
1234 static constexpr bool is_noexcept = true;
1235};
1236
1237#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
1238
1239#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
1240
1241template <typename Allocator, uintptr_t Bits, typename Function>
1242struct execute_member<
1243 boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1244 Function
1245 >
1246{
1247 static constexpr bool is_valid = true;
1248 static constexpr bool is_noexcept = false;
1249 typedef void result_type;
1250};
1251
1252#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
1253
1254#if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
1255
1256template <typename Allocator, uintptr_t Bits>
1257struct require_member<
1258 boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1259 boost::asio::execution::blocking_t::possibly_t
1260 >
1261{
1262 static constexpr bool is_valid = true;
1263 static constexpr bool is_noexcept = false;
1264 typedef boost::asio::io_context::basic_executor_type<
1265 Allocator, Bits> result_type;
1266};
1267
1268template <typename Allocator, uintptr_t Bits>
1269struct require_member<
1270 boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1271 boost::asio::execution::blocking_t::never_t
1272 >
1273{
1274 static constexpr bool is_valid = true;
1275 static constexpr bool is_noexcept = false;
1276 typedef boost::asio::io_context::basic_executor_type<
1277 Allocator, Bits> result_type;
1278};
1279
1280template <typename Allocator, uintptr_t Bits>
1281struct require_member<
1282 boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1283 boost::asio::execution::relationship_t::fork_t
1284 >
1285{
1286 static constexpr bool is_valid = true;
1287 static constexpr bool is_noexcept = false;
1288 typedef boost::asio::io_context::basic_executor_type<
1289 Allocator, Bits> result_type;
1290};
1291
1292template <typename Allocator, uintptr_t Bits>
1293struct require_member<
1294 boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1295 boost::asio::execution::relationship_t::continuation_t
1296 >
1297{
1298 static constexpr bool is_valid = true;
1299 static constexpr bool is_noexcept = false;
1300 typedef boost::asio::io_context::basic_executor_type<
1301 Allocator, Bits> result_type;
1302};
1303
1304template <typename Allocator, uintptr_t Bits>
1305struct require_member<
1306 boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1307 boost::asio::execution::outstanding_work_t::tracked_t
1308 > : boost::asio::detail::io_context_bits
1309{
1310 static constexpr bool is_valid = true;
1311 static constexpr bool is_noexcept = false;
1312 typedef boost::asio::io_context::basic_executor_type<
1313 Allocator, Bits | outstanding_work_tracked> result_type;
1314};
1315
1316template <typename Allocator, uintptr_t Bits>
1317struct require_member<
1318 boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1319 boost::asio::execution::outstanding_work_t::untracked_t
1320 > : boost::asio::detail::io_context_bits
1321{
1322 static constexpr bool is_valid = true;
1323 static constexpr bool is_noexcept = false;
1324 typedef boost::asio::io_context::basic_executor_type<
1325 Allocator, Bits & ~outstanding_work_tracked> result_type;
1326};
1327
1328template <typename Allocator, uintptr_t Bits>
1329struct require_member<
1330 boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1331 boost::asio::execution::allocator_t<void>
1332 >
1333{
1334 static constexpr bool is_valid = true;
1335 static constexpr bool is_noexcept = false;
1336 typedef boost::asio::io_context::basic_executor_type<
1337 std::allocator<void>, Bits> result_type;
1338};
1339
1340template <uintptr_t Bits,
1341 typename Allocator, typename OtherAllocator>
1342struct require_member<
1343 boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1344 boost::asio::execution::allocator_t<OtherAllocator>
1345 >
1346{
1347 static constexpr bool is_valid = true;
1348 static constexpr bool is_noexcept = false;
1349 typedef boost::asio::io_context::basic_executor_type<
1350 OtherAllocator, Bits> result_type;
1351};
1352
1353#endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
1354
1355#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
1356
1357template <typename Allocator, uintptr_t Bits, typename Property>
1358struct query_static_constexpr_member<
1359 boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1360 Property,
1361 typename boost::asio::enable_if<
1362 boost::asio::is_convertible<
1363 Property,
1364 boost::asio::execution::outstanding_work_t
1365 >::value
1366 >::type
1367 > : boost::asio::detail::io_context_bits
1368{
1369 static constexpr bool is_valid = true;
1370 static constexpr bool is_noexcept = true;
1371 typedef boost::asio::execution::outstanding_work_t result_type;
1372
1373 static constexpr result_type value() noexcept
1374 {
1375 return (Bits & outstanding_work_tracked)
1376 ? execution::outstanding_work_t(execution::outstanding_work.tracked)
1377 : execution::outstanding_work_t(execution::outstanding_work.untracked);
1378 }
1379};
1380
1381template <typename Allocator, uintptr_t Bits, typename Property>
1382struct query_static_constexpr_member<
1383 boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1384 Property,
1385 typename boost::asio::enable_if<
1386 boost::asio::is_convertible<
1387 Property,
1388 boost::asio::execution::mapping_t
1389 >::value
1390 >::type
1391 >
1392{
1393 static constexpr bool is_valid = true;
1394 static constexpr bool is_noexcept = true;
1395 typedef boost::asio::execution::mapping_t::thread_t result_type;
1396
1397 static constexpr result_type value() noexcept
1398 {
1399 return result_type();
1400 }
1401};
1402
1403#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
1404
1405#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
1406
1407template <typename Allocator, uintptr_t Bits, typename Property>
1408struct query_member<
1409 boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1410 Property,
1411 typename boost::asio::enable_if<
1412 boost::asio::is_convertible<
1413 Property,
1414 boost::asio::execution::blocking_t
1415 >::value
1416 >::type
1417 >
1418{
1419 static constexpr bool is_valid = true;
1420 static constexpr bool is_noexcept = true;
1421 typedef boost::asio::execution::blocking_t result_type;
1422};
1423
1424template <typename Allocator, uintptr_t Bits, typename Property>
1425struct query_member<
1426 boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1427 Property,
1428 typename boost::asio::enable_if<
1429 boost::asio::is_convertible<
1430 Property,
1431 boost::asio::execution::relationship_t
1432 >::value
1433 >::type
1434 >
1435{
1436 static constexpr bool is_valid = true;
1437 static constexpr bool is_noexcept = true;
1438 typedef boost::asio::execution::relationship_t result_type;
1439};
1440
1441template <typename Allocator, uintptr_t Bits>
1442struct query_member<
1443 boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1444 boost::asio::execution::context_t
1445 >
1446{
1447 static constexpr bool is_valid = true;
1448 static constexpr bool is_noexcept = true;
1449 typedef boost::asio::io_context& result_type;
1450};
1451
1452template <typename Allocator, uintptr_t Bits>
1453struct query_member<
1454 boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1455 boost::asio::execution::allocator_t<void>
1456 >
1457{
1458 static constexpr bool is_valid = true;
1459 static constexpr bool is_noexcept = true;
1460 typedef Allocator result_type;
1461};
1462
1463template <typename Allocator, uintptr_t Bits, typename OtherAllocator>
1464struct query_member<
1465 boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1466 boost::asio::execution::allocator_t<OtherAllocator>
1467 >
1468{
1469 static constexpr bool is_valid = true;
1470 static constexpr bool is_noexcept = true;
1471 typedef Allocator result_type;
1472};
1473
1474#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
1475
1476} // namespace traits
1477
1478namespace execution {
1479
1480template <>
1481struct is_executor<io_context> : false_type
1482{
1483};
1484
1485} // namespace execution
1486
1487#endif // !defined(GENERATING_DOCUMENTATION)
1488
1489} // namespace asio
1490} // namespace boost
1491
1492#include <boost/asio/detail/pop_options.hpp>
1493
1494#include <boost/asio/impl/io_context.hpp>
1495#if defined(BOOST_ASIO_HEADER_ONLY)
1496# include <boost/asio/impl/io_context.ipp>
1497#endif // defined(BOOST_ASIO_HEADER_ONLY)
1498
1499// If both io_context.hpp and strand.hpp have been included, automatically
1500// include the header file needed for the io_context::strand class.
1501#if !defined(BOOST_ASIO_NO_EXTENSIONS)
1502# if defined(BOOST_ASIO_STRAND_HPP)
1503# include <boost/asio/io_context_strand.hpp>
1504# endif // defined(BOOST_ASIO_STRAND_HPP)
1505#endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
1506
1507#endif // BOOST_ASIO_IO_CONTEXT_HPP
1508

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