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