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