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