Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:29:10

0001 //
0002 // io_context.hpp
0003 // ~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 //
0010 
0011 #ifndef BOOST_ASIO_IO_CONTEXT_HPP
0012 #define BOOST_ASIO_IO_CONTEXT_HPP
0013 
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0017 
0018 #include <boost/asio/detail/config.hpp>
0019 #include <cstddef>
0020 #include <stdexcept>
0021 #include <typeinfo>
0022 #include <boost/asio/async_result.hpp>
0023 #include <boost/asio/detail/chrono.hpp>
0024 #include <boost/asio/detail/concurrency_hint.hpp>
0025 #include <boost/asio/detail/cstdint.hpp>
0026 #include <boost/asio/detail/wrapped_handler.hpp>
0027 #include <boost/system/error_code.hpp>
0028 #include <boost/asio/execution.hpp>
0029 #include <boost/asio/execution_context.hpp>
0030 
0031 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
0032 # include <boost/asio/detail/winsock_init.hpp>
0033 #elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \
0034   || defined(__osf__)
0035 # include <boost/asio/detail/signal_init.hpp>
0036 #endif
0037 
0038 #if defined(BOOST_ASIO_HAS_IOCP)
0039 # include <boost/asio/detail/win_iocp_io_context.hpp>
0040 #else
0041 # include <boost/asio/detail/scheduler.hpp>
0042 #endif
0043 
0044 #include <boost/asio/detail/push_options.hpp>
0045 
0046 namespace boost {
0047 namespace asio {
0048 
0049 namespace detail {
0050 #if defined(BOOST_ASIO_HAS_IOCP)
0051   typedef win_iocp_io_context io_context_impl;
0052   class win_iocp_overlapped_ptr;
0053 #else
0054   typedef scheduler io_context_impl;
0055 #endif
0056 
0057   struct io_context_bits
0058   {
0059     static constexpr uintptr_t blocking_never = 1;
0060     static constexpr uintptr_t relationship_continuation = 2;
0061     static constexpr uintptr_t outstanding_work_tracked = 4;
0062     static constexpr uintptr_t runtime_bits = 3;
0063   };
0064 } // namespace detail
0065 
0066 /// Provides core I/O functionality.
0067 /**
0068  * The io_context class provides the core I/O functionality for users of the
0069  * asynchronous I/O objects, including:
0070  *
0071  * @li boost::asio::ip::tcp::socket
0072  * @li boost::asio::ip::tcp::acceptor
0073  * @li boost::asio::ip::udp::socket
0074  * @li boost::asio::deadline_timer.
0075  *
0076  * The io_context class also includes facilities intended for developers of
0077  * custom asynchronous services.
0078  *
0079  * @par Thread Safety
0080  * @e Distinct @e objects: Safe.@n
0081  * @e Shared @e objects: Safe, with the specific exceptions of the restart()
0082  * and notify_fork() functions. Calling restart() while there are unfinished
0083  * run(), run_one(), run_for(), run_until(), poll() or poll_one() calls results
0084  * in undefined behaviour. The notify_fork() function should not be called
0085  * while any io_context function, or any function on an I/O object that is
0086  * associated with the io_context, is being called in another thread.
0087  *
0088  * @par Concepts:
0089  * Dispatcher.
0090  *
0091  * @par Synchronous and asynchronous operations
0092  *
0093  * Synchronous operations on I/O objects implicitly run the io_context object
0094  * for an individual operation. The io_context functions run(), run_one(),
0095  * run_for(), run_until(), poll() or poll_one() must be called for the
0096  * io_context to perform asynchronous operations on behalf of a C++ program.
0097  * Notification that an asynchronous operation has completed is delivered by
0098  * invocation of the associated handler. Handlers are invoked only by a thread
0099  * that is currently calling any overload of run(), run_one(), run_for(),
0100  * run_until(), poll() or poll_one() for the io_context.
0101  *
0102  * @par Effect of exceptions thrown from handlers
0103  *
0104  * If an exception is thrown from a handler, the exception is allowed to
0105  * propagate through the throwing thread's invocation of run(), run_one(),
0106  * run_for(), run_until(), poll() or poll_one(). No other threads that are
0107  * calling any of these functions are affected. It is then the responsibility
0108  * of the application to catch the exception.
0109  *
0110  * After the exception has been caught, the run(), run_one(), run_for(),
0111  * run_until(), poll() or poll_one() call may be restarted @em without the need
0112  * for an intervening call to restart(). This allows the thread to rejoin the
0113  * io_context object's thread pool without impacting any other threads in the
0114  * pool.
0115  *
0116  * For example:
0117  *
0118  * @code
0119  * boost::asio::io_context io_context;
0120  * ...
0121  * for (;;)
0122  * {
0123  *   try
0124  *   {
0125  *     io_context.run();
0126  *     break; // run() exited normally
0127  *   }
0128  *   catch (my_exception& e)
0129  *   {
0130  *     // Deal with exception as appropriate.
0131  *   }
0132  * }
0133  * @endcode
0134  *
0135  * @par Submitting arbitrary tasks to the io_context
0136  *
0137  * To submit functions to the io_context, use the @ref boost::asio::dispatch,
0138  * @ref boost::asio::post or @ref boost::asio::defer free functions.
0139  *
0140  * For example:
0141  *
0142  * @code void my_task()
0143  * {
0144  *   ...
0145  * }
0146  *
0147  * ...
0148  *
0149  * boost::asio::io_context io_context;
0150  *
0151  * // Submit a function to the io_context.
0152  * boost::asio::post(io_context, my_task);
0153  *
0154  * // Submit a lambda object to the io_context.
0155  * boost::asio::post(io_context,
0156  *     []()
0157  *     {
0158  *       ...
0159  *     });
0160  *
0161  * // Run the io_context until it runs out of work.
0162  * io_context.run(); @endcode
0163  *
0164  * @par Stopping the io_context from running out of work
0165  *
0166  * Some applications may need to prevent an io_context object's run() call from
0167  * returning when there is no more work to do. For example, the io_context may
0168  * be being run in a background thread that is launched prior to the
0169  * application's asynchronous operations. The run() call may be kept running by
0170  * using the @ref make_work_guard function to create an object of type
0171  * boost::asio::executor_work_guard<io_context::executor_type>:
0172  *
0173  * @code boost::asio::io_context io_context;
0174  * boost::asio::executor_work_guard<boost::asio::io_context::executor_type>
0175  *   = boost::asio::make_work_guard(io_context);
0176  * ... @endcode
0177  *
0178  * To effect a shutdown, the application will then need to call the io_context
0179  * object's stop() member function. This will cause the io_context run() call
0180  * to return as soon as possible, abandoning unfinished operations and without
0181  * permitting ready handlers to be dispatched.
0182  *
0183  * Alternatively, if the application requires that all operations and handlers
0184  * be allowed to finish normally, the work object may be explicitly reset.
0185  *
0186  * @code boost::asio::io_context io_context;
0187  * boost::asio::executor_work_guard<boost::asio::io_context::executor_type>
0188  *   = boost::asio::make_work_guard(io_context);
0189  * ...
0190  * work.reset(); // Allow run() to exit. @endcode
0191  */
0192 class io_context
0193   : public execution_context
0194 {
0195 private:
0196   typedef detail::io_context_impl impl_type;
0197 #if defined(BOOST_ASIO_HAS_IOCP)
0198   friend class detail::win_iocp_overlapped_ptr;
0199 #endif
0200 
0201 #if !defined(BOOST_ASIO_NO_DEPRECATED)
0202   struct initiate_dispatch;
0203   struct initiate_post;
0204 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
0205 
0206 public:
0207   template <typename Allocator, uintptr_t Bits>
0208   class basic_executor_type;
0209 
0210   template <typename Allocator, uintptr_t Bits>
0211   friend class basic_executor_type;
0212 
0213   /// Executor used to submit functions to an io_context.
0214   typedef basic_executor_type<std::allocator<void>, 0> executor_type;
0215 
0216 #if !defined(BOOST_ASIO_NO_DEPRECATED)
0217   class work;
0218   friend class work;
0219 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
0220 
0221   class service;
0222 
0223 #if !defined(BOOST_ASIO_NO_EXTENSIONS) \
0224   && !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0225   class strand;
0226 #endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
0227        //   && !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0228 
0229   /// The type used to count the number of handlers executed by the context.
0230   typedef std::size_t count_type;
0231 
0232   /// Constructor.
0233   BOOST_ASIO_DECL io_context();
0234 
0235   /// Constructor.
0236   /**
0237    * Construct with a hint about the required level of concurrency.
0238    *
0239    * @param concurrency_hint A suggestion to the implementation on how many
0240    * threads it should allow to run simultaneously.
0241    */
0242   BOOST_ASIO_DECL explicit io_context(int concurrency_hint);
0243 
0244   /// Destructor.
0245   /**
0246    * On destruction, the io_context performs the following sequence of
0247    * operations:
0248    *
0249    * @li For each service object @c svc in the io_context set, in reverse order
0250    * of the beginning of service object lifetime, performs
0251    * @c svc->shutdown().
0252    *
0253    * @li Uninvoked handler objects that were scheduled for deferred invocation
0254    * on the io_context, or any associated strand, are destroyed.
0255    *
0256    * @li For each service object @c svc in the io_context set, in reverse order
0257    * of the beginning of service object lifetime, performs
0258    * <tt>delete static_cast<io_context::service*>(svc)</tt>.
0259    *
0260    * @note The destruction sequence described above permits programs to
0261    * simplify their resource management by using @c shared_ptr<>. Where an
0262    * object's lifetime is tied to the lifetime of a connection (or some other
0263    * sequence of asynchronous operations), a @c shared_ptr to the object would
0264    * be bound into the handlers for all asynchronous operations associated with
0265    * it. This works as follows:
0266    *
0267    * @li When a single connection ends, all associated asynchronous operations
0268    * complete. The corresponding handler objects are destroyed, and all
0269    * @c shared_ptr references to the objects are destroyed.
0270    *
0271    * @li To shut down the whole program, the io_context function stop() is
0272    * called to terminate any run() calls as soon as possible. The io_context
0273    * destructor defined above destroys all handlers, causing all @c shared_ptr
0274    * references to all connection objects to be destroyed.
0275    */
0276   BOOST_ASIO_DECL ~io_context();
0277 
0278   /// Obtains the executor associated with the io_context.
0279   executor_type get_executor() noexcept;
0280 
0281   /// Run the io_context object's event processing loop.
0282   /**
0283    * The run() function blocks until all work has finished and there are no
0284    * more handlers to be dispatched, or until the io_context has been stopped.
0285    *
0286    * Multiple threads may call the run() function to set up a pool of threads
0287    * from which the io_context may execute handlers. All threads that are
0288    * waiting in the pool are equivalent and the io_context may choose any one
0289    * of them to invoke a handler.
0290    *
0291    * A normal exit from the run() function implies that the io_context object
0292    * is stopped (the stopped() function returns @c true). Subsequent calls to
0293    * run(), run_one(), poll() or poll_one() will return immediately unless there
0294    * is a prior call to restart().
0295    *
0296    * @return The number of handlers that were executed.
0297    *
0298    * @note Calling the run() function from a thread that is currently calling
0299    * one of run(), run_one(), run_for(), run_until(), poll() or poll_one() on
0300    * the same io_context object may introduce the potential for deadlock. It is
0301    * the caller's reponsibility to avoid this.
0302    *
0303    * The poll() function may also be used to dispatch ready handlers, but
0304    * without blocking.
0305    */
0306   BOOST_ASIO_DECL count_type run();
0307 
0308 #if !defined(BOOST_ASIO_NO_DEPRECATED)
0309   /// (Deprecated: Use non-error_code overload.) Run the io_context object's
0310   /// event processing loop.
0311   /**
0312    * The run() function blocks until all work has finished and there are no
0313    * more handlers to be dispatched, or until the io_context has been stopped.
0314    *
0315    * Multiple threads may call the run() function to set up a pool of threads
0316    * from which the io_context may execute handlers. All threads that are
0317    * waiting in the pool are equivalent and the io_context may choose any one
0318    * of them to invoke a handler.
0319    *
0320    * A normal exit from the run() function implies that the io_context object
0321    * is stopped (the stopped() function returns @c true). Subsequent calls to
0322    * run(), run_one(), poll() or poll_one() will return immediately unless there
0323    * is a prior call to restart().
0324    *
0325    * @param ec Set to indicate what error occurred, if any.
0326    *
0327    * @return The number of handlers that were executed.
0328    *
0329    * @note Calling the run() function from a thread that is currently calling
0330    * one of run(), run_one(), run_for(), run_until(), poll() or poll_one() on
0331    * the same io_context object may introduce the potential for deadlock. It is
0332    * the caller's reponsibility to avoid this.
0333    *
0334    * The poll() function may also be used to dispatch ready handlers, but
0335    * without blocking.
0336    */
0337   BOOST_ASIO_DECL count_type run(boost::system::error_code& ec);
0338 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
0339 
0340   /// Run the io_context object's event processing loop for a specified
0341   /// duration.
0342   /**
0343    * The run_for() function blocks until all work has finished and there are no
0344    * more handlers to be dispatched, until the io_context has been stopped, or
0345    * until the specified duration has elapsed.
0346    *
0347    * @param rel_time The duration for which the call may block.
0348    *
0349    * @return The number of handlers that were executed.
0350    */
0351   template <typename Rep, typename Period>
0352   std::size_t run_for(const chrono::duration<Rep, Period>& rel_time);
0353 
0354   /// Run the io_context object's event processing loop until a specified time.
0355   /**
0356    * The run_until() function blocks until all work has finished and there are
0357    * no more handlers to be dispatched, until the io_context has been stopped,
0358    * or until the specified time has been reached.
0359    *
0360    * @param abs_time The time point until which the call may block.
0361    *
0362    * @return The number of handlers that were executed.
0363    */
0364   template <typename Clock, typename Duration>
0365   std::size_t run_until(const chrono::time_point<Clock, Duration>& abs_time);
0366 
0367   /// Run the io_context object's event processing loop to execute at most one
0368   /// handler.
0369   /**
0370    * The run_one() function blocks until one handler has been dispatched, or
0371    * until the io_context has been stopped.
0372    *
0373    * @return The number of handlers that were executed. A zero return value
0374    * implies that the io_context object is stopped (the stopped() function
0375    * returns @c true). Subsequent calls to run(), run_one(), poll() or
0376    * poll_one() will return immediately unless there is a prior call to
0377    * restart().
0378    *
0379    * @note Calling the run_one() function from a thread that is currently
0380    * calling one of run(), run_one(), run_for(), run_until(), poll() or
0381    * poll_one() on the same io_context object may introduce the potential for
0382    * deadlock. It is the caller's reponsibility to avoid this.
0383    */
0384   BOOST_ASIO_DECL count_type run_one();
0385 
0386 #if !defined(BOOST_ASIO_NO_DEPRECATED)
0387   /// (Deprecated: Use non-error_code overload.) Run the io_context object's
0388   /// event processing loop to execute at most one handler.
0389   /**
0390    * The run_one() function blocks until one handler has been dispatched, or
0391    * until the io_context has been stopped.
0392    *
0393    * @return The number of handlers that were executed. A zero return value
0394    * implies that the io_context object is stopped (the stopped() function
0395    * returns @c true). Subsequent calls to run(), run_one(), poll() or
0396    * poll_one() will return immediately unless there is a prior call to
0397    * restart().
0398    *
0399    * @return The number of handlers that were executed.
0400    *
0401    * @note Calling the run_one() function from a thread that is currently
0402    * calling one of run(), run_one(), run_for(), run_until(), poll() or
0403    * poll_one() on the same io_context object may introduce the potential for
0404    * deadlock. It is the caller's reponsibility to avoid this.
0405    */
0406   BOOST_ASIO_DECL count_type run_one(boost::system::error_code& ec);
0407 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
0408 
0409   /// Run the io_context object's event processing loop for a specified duration
0410   /// to execute at most one handler.
0411   /**
0412    * The run_one_for() function blocks until one handler has been dispatched,
0413    * until the io_context has been stopped, or until the specified duration has
0414    * elapsed.
0415    *
0416    * @param rel_time The duration for which the call may block.
0417    *
0418    * @return The number of handlers that were executed.
0419    */
0420   template <typename Rep, typename Period>
0421   std::size_t run_one_for(const chrono::duration<Rep, Period>& rel_time);
0422 
0423   /// Run the io_context object's event processing loop until a specified time
0424   /// to execute at most one handler.
0425   /**
0426    * The run_one_until() function blocks until one handler has been dispatched,
0427    * until the io_context has been stopped, or until the specified time has
0428    * been reached.
0429    *
0430    * @param abs_time The time point until which the call may block.
0431    *
0432    * @return The number of handlers that were executed.
0433    */
0434   template <typename Clock, typename Duration>
0435   std::size_t run_one_until(
0436       const chrono::time_point<Clock, Duration>& abs_time);
0437 
0438   /// Run the io_context object's event processing loop to execute ready
0439   /// handlers.
0440   /**
0441    * The poll() function runs handlers that are ready to run, without blocking,
0442    * until the io_context has been stopped or there are no more ready handlers.
0443    *
0444    * @return The number of handlers that were executed.
0445    */
0446   BOOST_ASIO_DECL count_type poll();
0447 
0448 #if !defined(BOOST_ASIO_NO_DEPRECATED)
0449   /// (Deprecated: Use non-error_code overload.) Run the io_context object's
0450   /// event processing loop to execute ready handlers.
0451   /**
0452    * The poll() function runs handlers that are ready to run, without blocking,
0453    * until the io_context has been stopped or there are no more ready handlers.
0454    *
0455    * @param ec Set to indicate what error occurred, if any.
0456    *
0457    * @return The number of handlers that were executed.
0458    */
0459   BOOST_ASIO_DECL count_type poll(boost::system::error_code& ec);
0460 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
0461 
0462   /// Run the io_context object's event processing loop to execute one ready
0463   /// handler.
0464   /**
0465    * The poll_one() function runs at most one handler that is ready to run,
0466    * without blocking.
0467    *
0468    * @return The number of handlers that were executed.
0469    */
0470   BOOST_ASIO_DECL count_type poll_one();
0471 
0472 #if !defined(BOOST_ASIO_NO_DEPRECATED)
0473   /// (Deprecated: Use non-error_code overload.) Run the io_context object's
0474   /// event processing loop to execute one ready handler.
0475   /**
0476    * The poll_one() function runs at most one handler that is ready to run,
0477    * without blocking.
0478    *
0479    * @param ec Set to indicate what error occurred, if any.
0480    *
0481    * @return The number of handlers that were executed.
0482    */
0483   BOOST_ASIO_DECL count_type poll_one(boost::system::error_code& ec);
0484 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
0485 
0486   /// Stop the io_context object's event processing loop.
0487   /**
0488    * This function does not block, but instead simply signals the io_context to
0489    * stop. All invocations of its run() or run_one() member functions should
0490    * return as soon as possible. Subsequent calls to run(), run_one(), poll()
0491    * or poll_one() will return immediately until restart() is called.
0492    */
0493   BOOST_ASIO_DECL void stop();
0494 
0495   /// Determine whether the io_context object has been stopped.
0496   /**
0497    * This function is used to determine whether an io_context object has been
0498    * stopped, either through an explicit call to stop(), or due to running out
0499    * of work. When an io_context object is stopped, calls to run(), run_one(),
0500    * poll() or poll_one() will return immediately without invoking any
0501    * handlers.
0502    *
0503    * @return @c true if the io_context object is stopped, otherwise @c false.
0504    */
0505   BOOST_ASIO_DECL bool stopped() const;
0506 
0507   /// Restart the io_context in preparation for a subsequent run() invocation.
0508   /**
0509    * This function must be called prior to any second or later set of
0510    * invocations of the run(), run_one(), poll() or poll_one() functions when a
0511    * previous invocation of these functions returned due to the io_context
0512    * being stopped or running out of work. After a call to restart(), the
0513    * io_context object's stopped() function will return @c false.
0514    *
0515    * This function must not be called while there are any unfinished calls to
0516    * the run(), run_one(), poll() or poll_one() functions.
0517    */
0518   BOOST_ASIO_DECL void restart();
0519 
0520 #if !defined(BOOST_ASIO_NO_DEPRECATED)
0521   /// (Deprecated: Use restart().) Reset the io_context in preparation for a
0522   /// subsequent run() invocation.
0523   /**
0524    * This function must be called prior to any second or later set of
0525    * invocations of the run(), run_one(), poll() or poll_one() functions when a
0526    * previous invocation of these functions returned due to the io_context
0527    * being stopped or running out of work. After a call to restart(), the
0528    * io_context object's stopped() function will return @c false.
0529    *
0530    * This function must not be called while there are any unfinished calls to
0531    * the run(), run_one(), poll() or poll_one() functions.
0532    */
0533   void reset();
0534 
0535   /// (Deprecated: Use boost::asio::dispatch().) Request the io_context to
0536   /// invoke the given handler.
0537   /**
0538    * This function is used to ask the io_context to execute the given handler.
0539    *
0540    * The io_context guarantees that the handler will only be called in a thread
0541    * in which the run(), run_one(), poll() or poll_one() member functions is
0542    * currently being invoked. The handler may be executed inside this function
0543    * if the guarantee can be met.
0544    *
0545    * @param handler The handler to be called. The io_context will make
0546    * a copy of the handler object as required. The function signature of the
0547    * handler must be: @code void handler(); @endcode
0548    *
0549    * @note This function throws an exception only if:
0550    *
0551    * @li the handler's associated allocator; or
0552    *
0553    * @li the handler's copy constructor
0554    *
0555    * throws an exception.
0556    */
0557   template <typename LegacyCompletionHandler>
0558   auto dispatch(LegacyCompletionHandler&& handler)
0559     -> decltype(
0560       async_initiate<LegacyCompletionHandler, void ()>(
0561         declval<initiate_dispatch>(), handler, this));
0562 
0563   /// (Deprecated: Use boost::asio::post().) Request the io_context to invoke
0564   /// the given handler and return immediately.
0565   /**
0566    * This function is used to ask the io_context to execute the given handler,
0567    * but without allowing the io_context to call the handler from inside this
0568    * function.
0569    *
0570    * The io_context guarantees that the handler will only be called in a thread
0571    * in which the run(), run_one(), poll() or poll_one() member functions is
0572    * currently being invoked.
0573    *
0574    * @param handler The handler to be called. The io_context will make
0575    * a copy of the handler object as required. The function signature of the
0576    * handler must be: @code void handler(); @endcode
0577    *
0578    * @note This function throws an exception only if:
0579    *
0580    * @li the handler's associated allocator; or
0581    *
0582    * @li the handler's copy constructor
0583    *
0584    * throws an exception.
0585    */
0586   template <typename LegacyCompletionHandler>
0587   auto post(LegacyCompletionHandler&& handler)
0588     -> decltype(
0589       async_initiate<LegacyCompletionHandler, void ()>(
0590         declval<initiate_post>(), handler, this));
0591 
0592   /// (Deprecated: Use boost::asio::bind_executor().) Create a new handler that
0593   /// automatically dispatches the wrapped handler on the io_context.
0594   /**
0595    * This function is used to create a new handler function object that, when
0596    * invoked, will automatically pass the wrapped handler to the io_context
0597    * object's dispatch function.
0598    *
0599    * @param handler The handler to be wrapped. The io_context will make a copy
0600    * of the handler object as required. The function signature of the handler
0601    * must be: @code void handler(A1 a1, ... An an); @endcode
0602    *
0603    * @return A function object that, when invoked, passes the wrapped handler to
0604    * the io_context object's dispatch function. Given a function object with the
0605    * signature:
0606    * @code R f(A1 a1, ... An an); @endcode
0607    * If this function object is passed to the wrap function like so:
0608    * @code io_context.wrap(f); @endcode
0609    * then the return value is a function object with the signature
0610    * @code void g(A1 a1, ... An an); @endcode
0611    * that, when invoked, executes code equivalent to:
0612    * @code io_context.dispatch(boost::bind(f, a1, ... an)); @endcode
0613    */
0614   template <typename Handler>
0615 #if defined(GENERATING_DOCUMENTATION)
0616   unspecified
0617 #else
0618   detail::wrapped_handler<io_context&, Handler>
0619 #endif
0620   wrap(Handler handler);
0621 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
0622 
0623 private:
0624   io_context(const io_context&) = delete;
0625   io_context& operator=(const io_context&) = delete;
0626 
0627   // Helper function to add the implementation.
0628   BOOST_ASIO_DECL impl_type& add_impl(impl_type* impl);
0629 
0630   // Backwards compatible overload for use with services derived from
0631   // io_context::service.
0632   template <typename Service>
0633   friend Service& use_service(io_context& ioc);
0634 
0635 #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
0636   detail::winsock_init<> init_;
0637 #elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \
0638   || defined(__osf__)
0639   detail::signal_init<> init_;
0640 #endif
0641 
0642   // The implementation.
0643   impl_type& impl_;
0644 };
0645 
0646 namespace detail {
0647 
0648 } // namespace detail
0649 
0650 /// Executor implementation type used to submit functions to an io_context.
0651 template <typename Allocator, uintptr_t Bits>
0652 class io_context::basic_executor_type :
0653   detail::io_context_bits, Allocator
0654 {
0655 public:
0656   /// Copy constructor.
0657   basic_executor_type(const basic_executor_type& other) noexcept
0658     : Allocator(static_cast<const Allocator&>(other)),
0659       target_(other.target_)
0660   {
0661     if (Bits & outstanding_work_tracked)
0662       if (context_ptr())
0663         context_ptr()->impl_.work_started();
0664   }
0665 
0666   /// Move constructor.
0667   basic_executor_type(basic_executor_type&& other) noexcept
0668     : Allocator(static_cast<Allocator&&>(other)),
0669       target_(other.target_)
0670   {
0671     if (Bits & outstanding_work_tracked)
0672       other.target_ = 0;
0673   }
0674 
0675   /// Destructor.
0676   ~basic_executor_type() noexcept
0677   {
0678     if (Bits & outstanding_work_tracked)
0679       if (context_ptr())
0680         context_ptr()->impl_.work_finished();
0681   }
0682 
0683   /// Assignment operator.
0684   basic_executor_type& operator=(const basic_executor_type& other) noexcept;
0685 
0686   /// Move assignment operator.
0687   basic_executor_type& operator=(basic_executor_type&& other) noexcept;
0688 
0689 #if !defined(GENERATING_DOCUMENTATION)
0690 private:
0691   friend struct boost_asio_require_fn::impl;
0692   friend struct boost_asio_prefer_fn::impl;
0693 #endif // !defined(GENERATING_DOCUMENTATION)
0694 
0695   /// Obtain an executor with the @c blocking.possibly property.
0696   /**
0697    * Do not call this function directly. It is intended for use with the
0698    * boost::asio::require customisation point.
0699    *
0700    * For example:
0701    * @code auto ex1 = my_io_context.get_executor();
0702    * auto ex2 = boost::asio::require(ex1,
0703    *     boost::asio::execution::blocking.possibly); @endcode
0704    */
0705   constexpr basic_executor_type require(execution::blocking_t::possibly_t) const
0706   {
0707     return basic_executor_type(context_ptr(),
0708         *this, bits() & ~blocking_never);
0709   }
0710 
0711   /// Obtain an executor with the @c blocking.never property.
0712   /**
0713    * Do not call this function directly. It is intended for use with the
0714    * boost::asio::require customisation point.
0715    *
0716    * For example:
0717    * @code auto ex1 = my_io_context.get_executor();
0718    * auto ex2 = boost::asio::require(ex1,
0719    *     boost::asio::execution::blocking.never); @endcode
0720    */
0721   constexpr basic_executor_type require(execution::blocking_t::never_t) const
0722   {
0723     return basic_executor_type(context_ptr(),
0724         *this, bits() | blocking_never);
0725   }
0726 
0727   /// Obtain an executor with the @c relationship.fork property.
0728   /**
0729    * Do not call this function directly. It is intended for use with the
0730    * boost::asio::require customisation point.
0731    *
0732    * For example:
0733    * @code auto ex1 = my_io_context.get_executor();
0734    * auto ex2 = boost::asio::require(ex1,
0735    *     boost::asio::execution::relationship.fork); @endcode
0736    */
0737   constexpr basic_executor_type require(execution::relationship_t::fork_t) const
0738   {
0739     return basic_executor_type(context_ptr(),
0740         *this, bits() & ~relationship_continuation);
0741   }
0742 
0743   /// Obtain an executor with the @c relationship.continuation property.
0744   /**
0745    * Do not call this function directly. It is intended for use with the
0746    * boost::asio::require customisation point.
0747    *
0748    * For example:
0749    * @code auto ex1 = my_io_context.get_executor();
0750    * auto ex2 = boost::asio::require(ex1,
0751    *     boost::asio::execution::relationship.continuation); @endcode
0752    */
0753   constexpr basic_executor_type require(
0754       execution::relationship_t::continuation_t) const
0755   {
0756     return basic_executor_type(context_ptr(),
0757         *this, bits() | relationship_continuation);
0758   }
0759 
0760   /// Obtain an executor with the @c outstanding_work.tracked property.
0761   /**
0762    * Do not call this function directly. It is intended for use with the
0763    * boost::asio::require customisation point.
0764    *
0765    * For example:
0766    * @code auto ex1 = my_io_context.get_executor();
0767    * auto ex2 = boost::asio::require(ex1,
0768    *     boost::asio::execution::outstanding_work.tracked); @endcode
0769    */
0770   constexpr basic_executor_type<Allocator,
0771       BOOST_ASIO_UNSPECIFIED(Bits | outstanding_work_tracked)>
0772   require(execution::outstanding_work_t::tracked_t) const
0773   {
0774     return basic_executor_type<Allocator, Bits | outstanding_work_tracked>(
0775         context_ptr(), *this, bits());
0776   }
0777 
0778   /// Obtain an executor with the @c outstanding_work.untracked property.
0779   /**
0780    * Do not call this function directly. It is intended for use with the
0781    * boost::asio::require customisation point.
0782    *
0783    * For example:
0784    * @code auto ex1 = my_io_context.get_executor();
0785    * auto ex2 = boost::asio::require(ex1,
0786    *     boost::asio::execution::outstanding_work.untracked); @endcode
0787    */
0788   constexpr basic_executor_type<Allocator,
0789       BOOST_ASIO_UNSPECIFIED(Bits & ~outstanding_work_tracked)>
0790   require(execution::outstanding_work_t::untracked_t) const
0791   {
0792     return basic_executor_type<Allocator, Bits & ~outstanding_work_tracked>(
0793         context_ptr(), *this, bits());
0794   }
0795 
0796   /// Obtain an executor with the specified @c allocator property.
0797   /**
0798    * Do not call this function directly. It is intended for use with the
0799    * boost::asio::require customisation point.
0800    *
0801    * For example:
0802    * @code auto ex1 = my_io_context.get_executor();
0803    * auto ex2 = boost::asio::require(ex1,
0804    *     boost::asio::execution::allocator(my_allocator)); @endcode
0805    */
0806   template <typename OtherAllocator>
0807   constexpr basic_executor_type<OtherAllocator, Bits>
0808   require(execution::allocator_t<OtherAllocator> a) const
0809   {
0810     return basic_executor_type<OtherAllocator, Bits>(
0811         context_ptr(), a.value(), bits());
0812   }
0813 
0814   /// Obtain an executor with the default @c allocator property.
0815   /**
0816    * Do not call this function directly. It is intended for use with the
0817    * boost::asio::require customisation point.
0818    *
0819    * For example:
0820    * @code auto ex1 = my_io_context.get_executor();
0821    * auto ex2 = boost::asio::require(ex1,
0822    *     boost::asio::execution::allocator); @endcode
0823    */
0824   constexpr basic_executor_type<std::allocator<void>, Bits>
0825   require(execution::allocator_t<void>) const
0826   {
0827     return basic_executor_type<std::allocator<void>, Bits>(
0828         context_ptr(), std::allocator<void>(), bits());
0829   }
0830 
0831 #if !defined(GENERATING_DOCUMENTATION)
0832 private:
0833   friend struct boost_asio_query_fn::impl;
0834   friend struct boost::asio::execution::detail::mapping_t<0>;
0835   friend struct boost::asio::execution::detail::outstanding_work_t<0>;
0836 #endif // !defined(GENERATING_DOCUMENTATION)
0837 
0838   /// Query the current value of the @c mapping property.
0839   /**
0840    * Do not call this function directly. It is intended for use with the
0841    * boost::asio::query customisation point.
0842    *
0843    * For example:
0844    * @code auto ex = my_io_context.get_executor();
0845    * if (boost::asio::query(ex, boost::asio::execution::mapping)
0846    *       == boost::asio::execution::mapping.thread)
0847    *   ... @endcode
0848    */
0849   static constexpr execution::mapping_t query(execution::mapping_t) noexcept
0850   {
0851     return execution::mapping.thread;
0852   }
0853 
0854   /// Query the current value of the @c context property.
0855   /**
0856    * Do not call this function directly. It is intended for use with the
0857    * boost::asio::query customisation point.
0858    *
0859    * For example:
0860    * @code auto ex = my_io_context.get_executor();
0861    * boost::asio::io_context& ctx = boost::asio::query(
0862    *     ex, boost::asio::execution::context); @endcode
0863    */
0864   io_context& query(execution::context_t) const noexcept
0865   {
0866     return *context_ptr();
0867   }
0868 
0869   /// Query the current value of the @c blocking property.
0870   /**
0871    * Do not call this function directly. It is intended for use with the
0872    * boost::asio::query customisation point.
0873    *
0874    * For example:
0875    * @code auto ex = my_io_context.get_executor();
0876    * if (boost::asio::query(ex, boost::asio::execution::blocking)
0877    *       == boost::asio::execution::blocking.always)
0878    *   ... @endcode
0879    */
0880   constexpr execution::blocking_t query(execution::blocking_t) const noexcept
0881   {
0882     return (bits() & blocking_never)
0883       ? execution::blocking_t(execution::blocking.never)
0884       : execution::blocking_t(execution::blocking.possibly);
0885   }
0886 
0887   /// Query the current value of the @c relationship property.
0888   /**
0889    * Do not call this function directly. It is intended for use with the
0890    * boost::asio::query customisation point.
0891    *
0892    * For example:
0893    * @code auto ex = my_io_context.get_executor();
0894    * if (boost::asio::query(ex, boost::asio::execution::relationship)
0895    *       == boost::asio::execution::relationship.continuation)
0896    *   ... @endcode
0897    */
0898   constexpr execution::relationship_t query(
0899       execution::relationship_t) const noexcept
0900   {
0901     return (bits() & relationship_continuation)
0902       ? execution::relationship_t(execution::relationship.continuation)
0903       : execution::relationship_t(execution::relationship.fork);
0904   }
0905 
0906   /// Query the current value of the @c outstanding_work property.
0907   /**
0908    * Do not call this function directly. It is intended for use with the
0909    * boost::asio::query customisation point.
0910    *
0911    * For example:
0912    * @code auto ex = my_io_context.get_executor();
0913    * if (boost::asio::query(ex, boost::asio::execution::outstanding_work)
0914    *       == boost::asio::execution::outstanding_work.tracked)
0915    *   ... @endcode
0916    */
0917   static constexpr execution::outstanding_work_t query(
0918       execution::outstanding_work_t) noexcept
0919   {
0920     return (Bits & outstanding_work_tracked)
0921       ? execution::outstanding_work_t(execution::outstanding_work.tracked)
0922       : execution::outstanding_work_t(execution::outstanding_work.untracked);
0923   }
0924 
0925   /// Query the current value of the @c allocator property.
0926   /**
0927    * Do not call this function directly. It is intended for use with the
0928    * boost::asio::query customisation point.
0929    *
0930    * For example:
0931    * @code auto ex = my_io_context.get_executor();
0932    * auto alloc = boost::asio::query(ex,
0933    *     boost::asio::execution::allocator); @endcode
0934    */
0935   template <typename OtherAllocator>
0936   constexpr Allocator query(
0937       execution::allocator_t<OtherAllocator>) const noexcept
0938   {
0939     return static_cast<const Allocator&>(*this);
0940   }
0941 
0942   /// Query the current value of the @c allocator property.
0943   /**
0944    * Do not call this function directly. It is intended for use with the
0945    * boost::asio::query customisation point.
0946    *
0947    * For example:
0948    * @code auto ex = my_io_context.get_executor();
0949    * auto alloc = boost::asio::query(ex,
0950    *     boost::asio::execution::allocator); @endcode
0951    */
0952   constexpr Allocator query(execution::allocator_t<void>) const noexcept
0953   {
0954     return static_cast<const Allocator&>(*this);
0955   }
0956 
0957 public:
0958   /// Determine whether the io_context is running in the current thread.
0959   /**
0960    * @return @c true if the current thread is running the io_context. Otherwise
0961    * returns @c false.
0962    */
0963   bool running_in_this_thread() const noexcept;
0964 
0965   /// Compare two executors for equality.
0966   /**
0967    * Two executors are equal if they refer to the same underlying io_context.
0968    */
0969   friend bool operator==(const basic_executor_type& a,
0970       const basic_executor_type& b) noexcept
0971   {
0972     return a.target_ == b.target_
0973       && static_cast<const Allocator&>(a) == static_cast<const Allocator&>(b);
0974   }
0975 
0976   /// Compare two executors for inequality.
0977   /**
0978    * Two executors are equal if they refer to the same underlying io_context.
0979    */
0980   friend bool operator!=(const basic_executor_type& a,
0981       const basic_executor_type& b) noexcept
0982   {
0983     return a.target_ != b.target_
0984       || static_cast<const Allocator&>(a) != static_cast<const Allocator&>(b);
0985   }
0986 
0987   /// Execution function.
0988   template <typename Function>
0989   void execute(Function&& f) const;
0990 
0991 #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0992 public:
0993   /// Obtain the underlying execution context.
0994   io_context& context() const noexcept;
0995 
0996   /// Inform the io_context that it has some outstanding work to do.
0997   /**
0998    * This function is used to inform the io_context that some work has begun.
0999    * This ensures that the io_context's run() and run_one() functions do not
1000    * exit while the work is underway.
1001    */
1002   void on_work_started() const noexcept;
1003 
1004   /// Inform the io_context that some work is no longer outstanding.
1005   /**
1006    * This function is used to inform the io_context that some work has
1007    * finished. Once the count of unfinished work reaches zero, the io_context
1008    * is stopped and the run() and run_one() functions may exit.
1009    */
1010   void on_work_finished() const noexcept;
1011 
1012   /// Request the io_context to invoke the given function object.
1013   /**
1014    * This function is used to ask the io_context to execute the given function
1015    * object. If the current thread is running the io_context, @c dispatch()
1016    * executes the function before returning. Otherwise, the function will be
1017    * scheduled to run on the io_context.
1018    *
1019    * @param f The function object to be called. The executor will make a copy
1020    * of the handler object as required. The function signature of the function
1021    * object must be: @code void function(); @endcode
1022    *
1023    * @param a An allocator that may be used by the executor to allocate the
1024    * internal storage needed for function invocation.
1025    */
1026   template <typename Function, typename OtherAllocator>
1027   void dispatch(Function&& f, const OtherAllocator& a) const;
1028 
1029   /// Request the io_context to invoke the given function object.
1030   /**
1031    * This function is used to ask the io_context to execute the given function
1032    * object. The function object will never be executed inside @c post().
1033    * Instead, it will be scheduled to run on the io_context.
1034    *
1035    * @param f The function object to be called. The executor will make a copy
1036    * of the handler object as required. The function signature of the function
1037    * object must be: @code void function(); @endcode
1038    *
1039    * @param a An allocator that may be used by the executor to allocate the
1040    * internal storage needed for function invocation.
1041    */
1042   template <typename Function, typename OtherAllocator>
1043   void post(Function&& f, const OtherAllocator& a) const;
1044 
1045   /// Request the io_context to invoke the given function object.
1046   /**
1047    * This function is used to ask the io_context to execute the given function
1048    * object. The function object will never be executed inside @c defer().
1049    * Instead, it will be scheduled to run on the io_context.
1050    *
1051    * If the current thread belongs to the io_context, @c defer() will delay
1052    * scheduling the function object until the current thread returns control to
1053    * the pool.
1054    *
1055    * @param f The function object to be called. The executor will make a copy
1056    * of the handler object as required. The function signature of the function
1057    * object must be: @code void function(); @endcode
1058    *
1059    * @param a An allocator that may be used by the executor to allocate the
1060    * internal storage needed for function invocation.
1061    */
1062   template <typename Function, typename OtherAllocator>
1063   void defer(Function&& f, const OtherAllocator& a) const;
1064 #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
1065 
1066 private:
1067   friend class io_context;
1068   template <typename, uintptr_t> friend class basic_executor_type;
1069 
1070   // Constructor used by io_context::get_executor().
1071   explicit basic_executor_type(io_context& i) noexcept
1072     : Allocator(),
1073       target_(reinterpret_cast<uintptr_t>(&i))
1074   {
1075     if (Bits & outstanding_work_tracked)
1076       context_ptr()->impl_.work_started();
1077   }
1078 
1079   // Constructor used by require().
1080   basic_executor_type(io_context* i,
1081       const Allocator& a, uintptr_t bits) noexcept
1082     : Allocator(a),
1083       target_(reinterpret_cast<uintptr_t>(i) | bits)
1084   {
1085     if (Bits & outstanding_work_tracked)
1086       if (context_ptr())
1087         context_ptr()->impl_.work_started();
1088   }
1089 
1090   io_context* context_ptr() const noexcept
1091   {
1092     return reinterpret_cast<io_context*>(target_ & ~runtime_bits);
1093   }
1094 
1095   uintptr_t bits() const noexcept
1096   {
1097     return target_ & runtime_bits;
1098   }
1099 
1100   // The underlying io_context and runtime bits.
1101   uintptr_t target_;
1102 };
1103 
1104 #if !defined(BOOST_ASIO_NO_DEPRECATED)
1105 /// (Deprecated: Use executor_work_guard.) Class to inform the io_context when
1106 /// it has work to do.
1107 /**
1108  * The work class is used to inform the io_context when work starts and
1109  * finishes. This ensures that the io_context object's run() function will not
1110  * exit while work is underway, and that it does exit when there is no
1111  * unfinished work remaining.
1112  *
1113  * The work class is copy-constructible so that it may be used as a data member
1114  * in a handler class. It is not assignable.
1115  */
1116 class io_context::work
1117 {
1118 public:
1119   /// Constructor notifies the io_context that work is starting.
1120   /**
1121    * The constructor is used to inform the io_context that some work has begun.
1122    * This ensures that the io_context object's run() function will not exit
1123    * while the work is underway.
1124    */
1125   explicit work(boost::asio::io_context& io_context);
1126 
1127   /// Copy constructor notifies the io_context that work is starting.
1128   /**
1129    * The constructor is used to inform the io_context that some work has begun.
1130    * This ensures that the io_context object's run() function will not exit
1131    * while the work is underway.
1132    */
1133   work(const work& other);
1134 
1135   /// Destructor notifies the io_context that the work is complete.
1136   /**
1137    * The destructor is used to inform the io_context that some work has
1138    * finished. Once the count of unfinished work reaches zero, the io_context
1139    * object's run() function is permitted to exit.
1140    */
1141   ~work();
1142 
1143   /// Get the io_context associated with the work.
1144   boost::asio::io_context& get_io_context();
1145 
1146 private:
1147   // Prevent assignment.
1148   void operator=(const work& other);
1149 
1150   // The io_context implementation.
1151   detail::io_context_impl& io_context_impl_;
1152 };
1153 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
1154 
1155 /// Base class for all io_context services.
1156 class io_context::service
1157   : public execution_context::service
1158 {
1159 public:
1160   /// Get the io_context object that owns the service.
1161   boost::asio::io_context& get_io_context();
1162 
1163 private:
1164   /// Destroy all user-defined handler objects owned by the service.
1165   BOOST_ASIO_DECL virtual void shutdown();
1166 
1167 #if !defined(BOOST_ASIO_NO_DEPRECATED)
1168   /// (Deprecated: Use shutdown().) Destroy all user-defined handler objects
1169   /// owned by the service.
1170   BOOST_ASIO_DECL virtual void shutdown_service();
1171 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
1172 
1173   /// Handle notification of a fork-related event to perform any necessary
1174   /// housekeeping.
1175   /**
1176    * This function is not a pure virtual so that services only have to
1177    * implement it if necessary. The default implementation does nothing.
1178    */
1179   BOOST_ASIO_DECL virtual void notify_fork(
1180       execution_context::fork_event event);
1181 
1182 #if !defined(BOOST_ASIO_NO_DEPRECATED)
1183   /// (Deprecated: Use notify_fork().) Handle notification of a fork-related
1184   /// event to perform any necessary housekeeping.
1185   /**
1186    * This function is not a pure virtual so that services only have to
1187    * implement it if necessary. The default implementation does nothing.
1188    */
1189   BOOST_ASIO_DECL virtual void fork_service(
1190       execution_context::fork_event event);
1191 #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
1192 
1193 protected:
1194   /// Constructor.
1195   /**
1196    * @param owner The io_context object that owns the service.
1197    */
1198   BOOST_ASIO_DECL service(boost::asio::io_context& owner);
1199 
1200   /// Destructor.
1201   BOOST_ASIO_DECL virtual ~service();
1202 };
1203 
1204 namespace detail {
1205 
1206 // Special service base class to keep classes header-file only.
1207 template <typename Type>
1208 class service_base
1209   : public boost::asio::io_context::service
1210 {
1211 public:
1212   static boost::asio::detail::service_id<Type> id;
1213 
1214   // Constructor.
1215   service_base(boost::asio::io_context& io_context)
1216     : boost::asio::io_context::service(io_context)
1217   {
1218   }
1219 };
1220 
1221 template <typename Type>
1222 boost::asio::detail::service_id<Type> service_base<Type>::id;
1223 
1224 } // namespace detail
1225 
1226 #if !defined(GENERATING_DOCUMENTATION)
1227 
1228 namespace traits {
1229 
1230 #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
1231 
1232 template <typename Allocator, uintptr_t Bits>
1233 struct equality_comparable<
1234     boost::asio::io_context::basic_executor_type<Allocator, Bits>
1235   >
1236 {
1237   static constexpr bool is_valid = true;
1238   static constexpr bool is_noexcept = true;
1239 };
1240 
1241 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
1242 
1243 #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
1244 
1245 template <typename Allocator, uintptr_t Bits, typename Function>
1246 struct execute_member<
1247     boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1248     Function
1249   >
1250 {
1251   static constexpr bool is_valid = true;
1252   static constexpr bool is_noexcept = false;
1253   typedef void result_type;
1254 };
1255 
1256 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
1257 
1258 #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
1259 
1260 template <typename Allocator, uintptr_t Bits>
1261 struct require_member<
1262     boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1263     boost::asio::execution::blocking_t::possibly_t
1264   >
1265 {
1266   static constexpr bool is_valid = true;
1267   static constexpr bool is_noexcept = false;
1268   typedef boost::asio::io_context::basic_executor_type<
1269       Allocator, Bits> result_type;
1270 };
1271 
1272 template <typename Allocator, uintptr_t Bits>
1273 struct require_member<
1274     boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1275     boost::asio::execution::blocking_t::never_t
1276   >
1277 {
1278   static constexpr bool is_valid = true;
1279   static constexpr bool is_noexcept = false;
1280   typedef boost::asio::io_context::basic_executor_type<
1281       Allocator, Bits> result_type;
1282 };
1283 
1284 template <typename Allocator, uintptr_t Bits>
1285 struct require_member<
1286     boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1287     boost::asio::execution::relationship_t::fork_t
1288   >
1289 {
1290   static constexpr bool is_valid = true;
1291   static constexpr bool is_noexcept = false;
1292   typedef boost::asio::io_context::basic_executor_type<
1293       Allocator, Bits> result_type;
1294 };
1295 
1296 template <typename Allocator, uintptr_t Bits>
1297 struct require_member<
1298     boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1299     boost::asio::execution::relationship_t::continuation_t
1300   >
1301 {
1302   static constexpr bool is_valid = true;
1303   static constexpr bool is_noexcept = false;
1304   typedef boost::asio::io_context::basic_executor_type<
1305       Allocator, Bits> result_type;
1306 };
1307 
1308 template <typename Allocator, uintptr_t Bits>
1309 struct require_member<
1310     boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1311     boost::asio::execution::outstanding_work_t::tracked_t
1312   > : boost::asio::detail::io_context_bits
1313 {
1314   static constexpr bool is_valid = true;
1315   static constexpr bool is_noexcept = false;
1316   typedef boost::asio::io_context::basic_executor_type<
1317       Allocator, Bits | outstanding_work_tracked> result_type;
1318 };
1319 
1320 template <typename Allocator, uintptr_t Bits>
1321 struct require_member<
1322     boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1323     boost::asio::execution::outstanding_work_t::untracked_t
1324   > : boost::asio::detail::io_context_bits
1325 {
1326   static constexpr bool is_valid = true;
1327   static constexpr bool is_noexcept = false;
1328   typedef boost::asio::io_context::basic_executor_type<
1329       Allocator, Bits & ~outstanding_work_tracked> result_type;
1330 };
1331 
1332 template <typename Allocator, uintptr_t Bits>
1333 struct require_member<
1334     boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1335     boost::asio::execution::allocator_t<void>
1336   >
1337 {
1338   static constexpr bool is_valid = true;
1339   static constexpr bool is_noexcept = false;
1340   typedef boost::asio::io_context::basic_executor_type<
1341       std::allocator<void>, Bits> result_type;
1342 };
1343 
1344 template <uintptr_t Bits,
1345     typename Allocator, typename OtherAllocator>
1346 struct require_member<
1347     boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1348     boost::asio::execution::allocator_t<OtherAllocator>
1349   >
1350 {
1351   static constexpr bool is_valid = true;
1352   static constexpr bool is_noexcept = false;
1353   typedef boost::asio::io_context::basic_executor_type<
1354       OtherAllocator, Bits> result_type;
1355 };
1356 
1357 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
1358 
1359 #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
1360 
1361 template <typename Allocator, uintptr_t Bits, typename Property>
1362 struct query_static_constexpr_member<
1363     boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1364     Property,
1365     typename boost::asio::enable_if<
1366       boost::asio::is_convertible<
1367         Property,
1368         boost::asio::execution::outstanding_work_t
1369       >::value
1370     >::type
1371   > : boost::asio::detail::io_context_bits
1372 {
1373   static constexpr bool is_valid = true;
1374   static constexpr bool is_noexcept = true;
1375   typedef boost::asio::execution::outstanding_work_t result_type;
1376 
1377   static constexpr result_type value() noexcept
1378   {
1379     return (Bits & outstanding_work_tracked)
1380       ? execution::outstanding_work_t(execution::outstanding_work.tracked)
1381       : execution::outstanding_work_t(execution::outstanding_work.untracked);
1382   }
1383 };
1384 
1385 template <typename Allocator, uintptr_t Bits, typename Property>
1386 struct query_static_constexpr_member<
1387     boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1388     Property,
1389     typename boost::asio::enable_if<
1390       boost::asio::is_convertible<
1391         Property,
1392         boost::asio::execution::mapping_t
1393       >::value
1394     >::type
1395   >
1396 {
1397   static constexpr bool is_valid = true;
1398   static constexpr bool is_noexcept = true;
1399   typedef boost::asio::execution::mapping_t::thread_t result_type;
1400 
1401   static constexpr result_type value() noexcept
1402   {
1403     return result_type();
1404   }
1405 };
1406 
1407 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
1408 
1409 #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
1410 
1411 template <typename Allocator, uintptr_t Bits, typename Property>
1412 struct query_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::blocking_t
1419       >::value
1420     >::type
1421   >
1422 {
1423   static constexpr bool is_valid = true;
1424   static constexpr bool is_noexcept = true;
1425   typedef boost::asio::execution::blocking_t result_type;
1426 };
1427 
1428 template <typename Allocator, uintptr_t Bits, typename Property>
1429 struct query_member<
1430     boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1431     Property,
1432     typename boost::asio::enable_if<
1433       boost::asio::is_convertible<
1434         Property,
1435         boost::asio::execution::relationship_t
1436       >::value
1437     >::type
1438   >
1439 {
1440   static constexpr bool is_valid = true;
1441   static constexpr bool is_noexcept = true;
1442   typedef boost::asio::execution::relationship_t result_type;
1443 };
1444 
1445 template <typename Allocator, uintptr_t Bits>
1446 struct query_member<
1447     boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1448     boost::asio::execution::context_t
1449   >
1450 {
1451   static constexpr bool is_valid = true;
1452   static constexpr bool is_noexcept = true;
1453   typedef boost::asio::io_context& result_type;
1454 };
1455 
1456 template <typename Allocator, uintptr_t Bits>
1457 struct query_member<
1458     boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1459     boost::asio::execution::allocator_t<void>
1460   >
1461 {
1462   static constexpr bool is_valid = true;
1463   static constexpr bool is_noexcept = true;
1464   typedef Allocator result_type;
1465 };
1466 
1467 template <typename Allocator, uintptr_t Bits, typename OtherAllocator>
1468 struct query_member<
1469     boost::asio::io_context::basic_executor_type<Allocator, Bits>,
1470     boost::asio::execution::allocator_t<OtherAllocator>
1471   >
1472 {
1473   static constexpr bool is_valid = true;
1474   static constexpr bool is_noexcept = true;
1475   typedef Allocator result_type;
1476 };
1477 
1478 #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
1479 
1480 } // namespace traits
1481 
1482 namespace execution {
1483 
1484 template <>
1485 struct is_executor<io_context> : false_type
1486 {
1487 };
1488 
1489 } // namespace execution
1490 
1491 #endif // !defined(GENERATING_DOCUMENTATION)
1492 
1493 } // namespace asio
1494 } // namespace boost
1495 
1496 #include <boost/asio/detail/pop_options.hpp>
1497 
1498 #include <boost/asio/impl/io_context.hpp>
1499 #if defined(BOOST_ASIO_HEADER_ONLY)
1500 # include <boost/asio/impl/io_context.ipp>
1501 #endif // defined(BOOST_ASIO_HEADER_ONLY)
1502 
1503 // If both io_context.hpp and strand.hpp have been included, automatically
1504 // include the header file needed for the io_context::strand class.
1505 #if !defined(BOOST_ASIO_NO_EXTENSIONS)
1506 # if defined(BOOST_ASIO_STRAND_HPP)
1507 #  include <boost/asio/io_context_strand.hpp>
1508 # endif // defined(BOOST_ASIO_STRAND_HPP)
1509 #endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
1510 
1511 #endif // BOOST_ASIO_IO_CONTEXT_HPP