1 | // |
2 | // posix/basic_descriptor.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_POSIX_BASIC_DESCRIPTOR_HPP |
12 | #define BOOST_ASIO_POSIX_BASIC_DESCRIPTOR_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 | |
20 | #if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ |
21 | || defined(GENERATING_DOCUMENTATION) |
22 | |
23 | #include <utility> |
24 | #include <boost/asio/any_io_executor.hpp> |
25 | #include <boost/asio/async_result.hpp> |
26 | #include <boost/asio/detail/handler_type_requirements.hpp> |
27 | #include <boost/asio/detail/io_object_impl.hpp> |
28 | #include <boost/asio/detail/non_const_lvalue.hpp> |
29 | #include <boost/asio/detail/throw_error.hpp> |
30 | #include <boost/asio/error.hpp> |
31 | #include <boost/asio/execution_context.hpp> |
32 | #include <boost/asio/posix/descriptor_base.hpp> |
33 | |
34 | #if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT) |
35 | # include <boost/asio/detail/io_uring_descriptor_service.hpp> |
36 | #else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT) |
37 | # include <boost/asio/detail/reactive_descriptor_service.hpp> |
38 | #endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT) |
39 | |
40 | #include <boost/asio/detail/push_options.hpp> |
41 | |
42 | namespace boost { |
43 | namespace asio { |
44 | namespace posix { |
45 | |
46 | /// Provides POSIX descriptor functionality. |
47 | /** |
48 | * The posix::basic_descriptor class template provides the ability to wrap a |
49 | * POSIX descriptor. |
50 | * |
51 | * @par Thread Safety |
52 | * @e Distinct @e objects: Safe.@n |
53 | * @e Shared @e objects: Unsafe. |
54 | */ |
55 | template <typename Executor = any_io_executor> |
56 | class basic_descriptor |
57 | : public descriptor_base |
58 | { |
59 | private: |
60 | class initiate_async_wait; |
61 | |
62 | public: |
63 | /// The type of the executor associated with the object. |
64 | typedef Executor executor_type; |
65 | |
66 | /// Rebinds the descriptor type to another executor. |
67 | template <typename Executor1> |
68 | struct rebind_executor |
69 | { |
70 | /// The descriptor type when rebound to the specified executor. |
71 | typedef basic_descriptor<Executor1> other; |
72 | }; |
73 | |
74 | /// The native representation of a descriptor. |
75 | #if defined(GENERATING_DOCUMENTATION) |
76 | typedef implementation_defined native_handle_type; |
77 | #elif defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT) |
78 | typedef detail::io_uring_descriptor_service::native_handle_type |
79 | native_handle_type; |
80 | #else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT) |
81 | typedef detail::reactive_descriptor_service::native_handle_type |
82 | native_handle_type; |
83 | #endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT) |
84 | |
85 | /// A descriptor is always the lowest layer. |
86 | typedef basic_descriptor lowest_layer_type; |
87 | |
88 | /// Construct a descriptor without opening it. |
89 | /** |
90 | * This constructor creates a descriptor without opening it. |
91 | * |
92 | * @param ex The I/O executor that the descriptor will use, by default, to |
93 | * dispatch handlers for any asynchronous operations performed on the |
94 | * descriptor. |
95 | */ |
96 | explicit basic_descriptor(const executor_type& ex) |
97 | : impl_(0, ex) |
98 | { |
99 | } |
100 | |
101 | /// Construct a descriptor without opening it. |
102 | /** |
103 | * This constructor creates a descriptor without opening it. |
104 | * |
105 | * @param context An execution context which provides the I/O executor that |
106 | * the descriptor will use, by default, to dispatch handlers for any |
107 | * asynchronous operations performed on the descriptor. |
108 | */ |
109 | template <typename ExecutionContext> |
110 | explicit basic_descriptor(ExecutionContext& context, |
111 | constraint_t< |
112 | is_convertible<ExecutionContext&, execution_context&>::value, |
113 | defaulted_constraint |
114 | > = defaulted_constraint()) |
115 | : impl_(0, 0, context) |
116 | { |
117 | } |
118 | |
119 | /// Construct a descriptor on an existing native descriptor. |
120 | /** |
121 | * This constructor creates a descriptor object to hold an existing native |
122 | * descriptor. |
123 | * |
124 | * @param ex The I/O executor that the descriptor will use, by default, to |
125 | * dispatch handlers for any asynchronous operations performed on the |
126 | * descriptor. |
127 | * |
128 | * @param native_descriptor A native descriptor. |
129 | * |
130 | * @throws boost::system::system_error Thrown on failure. |
131 | */ |
132 | basic_descriptor(const executor_type& ex, |
133 | const native_handle_type& native_descriptor) |
134 | : impl_(0, ex) |
135 | { |
136 | boost::system::error_code ec; |
137 | impl_.get_service().assign(impl_.get_implementation(), |
138 | native_descriptor, ec); |
139 | boost::asio::detail::throw_error(err: ec, location: "assign" ); |
140 | } |
141 | |
142 | /// Construct a descriptor on an existing native descriptor. |
143 | /** |
144 | * This constructor creates a descriptor object to hold an existing native |
145 | * descriptor. |
146 | * |
147 | * @param context An execution context which provides the I/O executor that |
148 | * the descriptor will use, by default, to dispatch handlers for any |
149 | * asynchronous operations performed on the descriptor. |
150 | * |
151 | * @param native_descriptor A native descriptor. |
152 | * |
153 | * @throws boost::system::system_error Thrown on failure. |
154 | */ |
155 | template <typename ExecutionContext> |
156 | basic_descriptor(ExecutionContext& context, |
157 | const native_handle_type& native_descriptor, |
158 | constraint_t< |
159 | is_convertible<ExecutionContext&, execution_context&>::value |
160 | > = 0) |
161 | : impl_(0, 0, context) |
162 | { |
163 | boost::system::error_code ec; |
164 | impl_.get_service().assign(impl_.get_implementation(), |
165 | native_descriptor, ec); |
166 | boost::asio::detail::throw_error(err: ec, location: "assign" ); |
167 | } |
168 | |
169 | /// Move-construct a descriptor from another. |
170 | /** |
171 | * This constructor moves a descriptor from one object to another. |
172 | * |
173 | * @param other The other descriptor object from which the move will |
174 | * occur. |
175 | * |
176 | * @note Following the move, the moved-from object is in the same state as if |
177 | * constructed using the @c basic_descriptor(const executor_type&) |
178 | * constructor. |
179 | */ |
180 | basic_descriptor(basic_descriptor&& other) noexcept |
181 | : impl_(std::move(other.impl_)) |
182 | { |
183 | } |
184 | |
185 | /// Move-assign a descriptor from another. |
186 | /** |
187 | * This assignment operator moves a descriptor from one object to another. |
188 | * |
189 | * @param other The other descriptor object from which the move will |
190 | * occur. |
191 | * |
192 | * @note Following the move, the moved-from object is in the same state as if |
193 | * constructed using the @c basic_descriptor(const executor_type&) |
194 | * constructor. |
195 | */ |
196 | basic_descriptor& operator=(basic_descriptor&& other) |
197 | { |
198 | impl_ = std::move(other.impl_); |
199 | return *this; |
200 | } |
201 | |
202 | // All descriptors have access to each other's implementations. |
203 | template <typename Executor1> |
204 | friend class basic_descriptor; |
205 | |
206 | /// Move-construct a basic_descriptor from a descriptor of another executor |
207 | /// type. |
208 | /** |
209 | * This constructor moves a descriptor from one object to another. |
210 | * |
211 | * @param other The other basic_descriptor object from which the move will |
212 | * occur. |
213 | * |
214 | * @note Following the move, the moved-from object is in the same state as if |
215 | * constructed using the @c basic_descriptor(const executor_type&) |
216 | * constructor. |
217 | */ |
218 | template <typename Executor1> |
219 | basic_descriptor(basic_descriptor<Executor1>&& other, |
220 | constraint_t< |
221 | is_convertible<Executor1, Executor>::value, |
222 | defaulted_constraint |
223 | > = defaulted_constraint()) |
224 | : impl_(std::move(other.impl_)) |
225 | { |
226 | } |
227 | |
228 | /// Move-assign a basic_descriptor from a descriptor of another executor type. |
229 | /** |
230 | * This assignment operator moves a descriptor from one object to another. |
231 | * |
232 | * @param other The other basic_descriptor object from which the move will |
233 | * occur. |
234 | * |
235 | * @note Following the move, the moved-from object is in the same state as if |
236 | * constructed using the @c basic_descriptor(const executor_type&) |
237 | * constructor. |
238 | */ |
239 | template <typename Executor1> |
240 | constraint_t< |
241 | is_convertible<Executor1, Executor>::value, |
242 | basic_descriptor& |
243 | > operator=(basic_descriptor<Executor1> && other) |
244 | { |
245 | basic_descriptor tmp(std::move(other)); |
246 | impl_ = std::move(tmp.impl_); |
247 | return *this; |
248 | } |
249 | |
250 | /// Get the executor associated with the object. |
251 | const executor_type& get_executor() noexcept |
252 | { |
253 | return impl_.get_executor(); |
254 | } |
255 | |
256 | /// Get a reference to the lowest layer. |
257 | /** |
258 | * This function returns a reference to the lowest layer in a stack of |
259 | * layers. Since a descriptor cannot contain any further layers, it |
260 | * simply returns a reference to itself. |
261 | * |
262 | * @return A reference to the lowest layer in the stack of layers. Ownership |
263 | * is not transferred to the caller. |
264 | */ |
265 | lowest_layer_type& lowest_layer() |
266 | { |
267 | return *this; |
268 | } |
269 | |
270 | /// Get a const reference to the lowest layer. |
271 | /** |
272 | * This function returns a const reference to the lowest layer in a stack of |
273 | * layers. Since a descriptor cannot contain any further layers, it |
274 | * simply returns a reference to itself. |
275 | * |
276 | * @return A const reference to the lowest layer in the stack of layers. |
277 | * Ownership is not transferred to the caller. |
278 | */ |
279 | const lowest_layer_type& lowest_layer() const |
280 | { |
281 | return *this; |
282 | } |
283 | |
284 | /// Assign an existing native descriptor to the descriptor. |
285 | /* |
286 | * This function opens the descriptor to hold an existing native descriptor. |
287 | * |
288 | * @param native_descriptor A native descriptor. |
289 | * |
290 | * @throws boost::system::system_error Thrown on failure. |
291 | */ |
292 | void assign(const native_handle_type& native_descriptor) |
293 | { |
294 | boost::system::error_code ec; |
295 | impl_.get_service().assign(impl_.get_implementation(), |
296 | native_descriptor, ec); |
297 | boost::asio::detail::throw_error(err: ec, location: "assign" ); |
298 | } |
299 | |
300 | /// Assign an existing native descriptor to the descriptor. |
301 | /* |
302 | * This function opens the descriptor to hold an existing native descriptor. |
303 | * |
304 | * @param native_descriptor A native descriptor. |
305 | * |
306 | * @param ec Set to indicate what error occurred, if any. |
307 | */ |
308 | BOOST_ASIO_SYNC_OP_VOID assign(const native_handle_type& native_descriptor, |
309 | boost::system::error_code& ec) |
310 | { |
311 | impl_.get_service().assign( |
312 | impl_.get_implementation(), native_descriptor, ec); |
313 | BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); |
314 | } |
315 | |
316 | /// Determine whether the descriptor is open. |
317 | bool is_open() const |
318 | { |
319 | return impl_.get_service().is_open(impl_.get_implementation()); |
320 | } |
321 | |
322 | /// Close the descriptor. |
323 | /** |
324 | * This function is used to close the descriptor. Any asynchronous read or |
325 | * write operations will be cancelled immediately, and will complete with the |
326 | * boost::asio::error::operation_aborted error. |
327 | * |
328 | * @throws boost::system::system_error Thrown on failure. Note that, even if |
329 | * the function indicates an error, the underlying descriptor is closed. |
330 | */ |
331 | void close() |
332 | { |
333 | boost::system::error_code ec; |
334 | impl_.get_service().close(impl_.get_implementation(), ec); |
335 | boost::asio::detail::throw_error(err: ec, location: "close" ); |
336 | } |
337 | |
338 | /// Close the descriptor. |
339 | /** |
340 | * This function is used to close the descriptor. Any asynchronous read or |
341 | * write operations will be cancelled immediately, and will complete with the |
342 | * boost::asio::error::operation_aborted error. |
343 | * |
344 | * @param ec Set to indicate what error occurred, if any. Note that, even if |
345 | * the function indicates an error, the underlying descriptor is closed. |
346 | */ |
347 | BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec) |
348 | { |
349 | impl_.get_service().close(impl_.get_implementation(), ec); |
350 | BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); |
351 | } |
352 | |
353 | /// Get the native descriptor representation. |
354 | /** |
355 | * This function may be used to obtain the underlying representation of the |
356 | * descriptor. This is intended to allow access to native descriptor |
357 | * functionality that is not otherwise provided. |
358 | */ |
359 | native_handle_type native_handle() |
360 | { |
361 | return impl_.get_service().native_handle(impl_.get_implementation()); |
362 | } |
363 | |
364 | /// Release ownership of the native descriptor implementation. |
365 | /** |
366 | * This function may be used to obtain the underlying representation of the |
367 | * descriptor. After calling this function, @c is_open() returns false. The |
368 | * caller is responsible for closing the descriptor. |
369 | * |
370 | * All outstanding asynchronous read or write operations will finish |
371 | * immediately, and the handlers for cancelled operations will be passed the |
372 | * boost::asio::error::operation_aborted error. |
373 | */ |
374 | native_handle_type release() |
375 | { |
376 | return impl_.get_service().release(impl_.get_implementation()); |
377 | } |
378 | |
379 | /// Cancel all asynchronous operations associated with the descriptor. |
380 | /** |
381 | * This function causes all outstanding asynchronous read or write operations |
382 | * to finish immediately, and the handlers for cancelled operations will be |
383 | * passed the boost::asio::error::operation_aborted error. |
384 | * |
385 | * @throws boost::system::system_error Thrown on failure. |
386 | */ |
387 | void cancel() |
388 | { |
389 | boost::system::error_code ec; |
390 | impl_.get_service().cancel(impl_.get_implementation(), ec); |
391 | boost::asio::detail::throw_error(err: ec, location: "cancel" ); |
392 | } |
393 | |
394 | /// Cancel all asynchronous operations associated with the descriptor. |
395 | /** |
396 | * This function causes all outstanding asynchronous read or write operations |
397 | * to finish immediately, and the handlers for cancelled operations will be |
398 | * passed the boost::asio::error::operation_aborted error. |
399 | * |
400 | * @param ec Set to indicate what error occurred, if any. |
401 | */ |
402 | BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec) |
403 | { |
404 | impl_.get_service().cancel(impl_.get_implementation(), ec); |
405 | BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); |
406 | } |
407 | |
408 | /// Perform an IO control command on the descriptor. |
409 | /** |
410 | * This function is used to execute an IO control command on the descriptor. |
411 | * |
412 | * @param command The IO control command to be performed on the descriptor. |
413 | * |
414 | * @throws boost::system::system_error Thrown on failure. |
415 | * |
416 | * @sa IoControlCommand @n |
417 | * boost::asio::posix::descriptor_base::bytes_readable @n |
418 | * boost::asio::posix::descriptor_base::non_blocking_io |
419 | * |
420 | * @par Example |
421 | * Getting the number of bytes ready to read: |
422 | * @code |
423 | * boost::asio::posix::stream_descriptor descriptor(my_context); |
424 | * ... |
425 | * boost::asio::posix::stream_descriptor::bytes_readable command; |
426 | * descriptor.io_control(command); |
427 | * std::size_t bytes_readable = command.get(); |
428 | * @endcode |
429 | */ |
430 | template <typename IoControlCommand> |
431 | void io_control(IoControlCommand& command) |
432 | { |
433 | boost::system::error_code ec; |
434 | impl_.get_service().io_control(impl_.get_implementation(), command, ec); |
435 | boost::asio::detail::throw_error(err: ec, location: "io_control" ); |
436 | } |
437 | |
438 | /// Perform an IO control command on the descriptor. |
439 | /** |
440 | * This function is used to execute an IO control command on the descriptor. |
441 | * |
442 | * @param command The IO control command to be performed on the descriptor. |
443 | * |
444 | * @param ec Set to indicate what error occurred, if any. |
445 | * |
446 | * @sa IoControlCommand @n |
447 | * boost::asio::posix::descriptor_base::bytes_readable @n |
448 | * boost::asio::posix::descriptor_base::non_blocking_io |
449 | * |
450 | * @par Example |
451 | * Getting the number of bytes ready to read: |
452 | * @code |
453 | * boost::asio::posix::stream_descriptor descriptor(my_context); |
454 | * ... |
455 | * boost::asio::posix::stream_descriptor::bytes_readable command; |
456 | * boost::system::error_code ec; |
457 | * descriptor.io_control(command, ec); |
458 | * if (ec) |
459 | * { |
460 | * // An error occurred. |
461 | * } |
462 | * std::size_t bytes_readable = command.get(); |
463 | * @endcode |
464 | */ |
465 | template <typename IoControlCommand> |
466 | BOOST_ASIO_SYNC_OP_VOID io_control(IoControlCommand& command, |
467 | boost::system::error_code& ec) |
468 | { |
469 | impl_.get_service().io_control(impl_.get_implementation(), command, ec); |
470 | BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); |
471 | } |
472 | |
473 | /// Gets the non-blocking mode of the descriptor. |
474 | /** |
475 | * @returns @c true if the descriptor's synchronous operations will fail with |
476 | * boost::asio::error::would_block if they are unable to perform the requested |
477 | * operation immediately. If @c false, synchronous operations will block |
478 | * until complete. |
479 | * |
480 | * @note The non-blocking mode has no effect on the behaviour of asynchronous |
481 | * operations. Asynchronous operations will never fail with the error |
482 | * boost::asio::error::would_block. |
483 | */ |
484 | bool non_blocking() const |
485 | { |
486 | return impl_.get_service().non_blocking(impl_.get_implementation()); |
487 | } |
488 | |
489 | /// Sets the non-blocking mode of the descriptor. |
490 | /** |
491 | * @param mode If @c true, the descriptor's synchronous operations will fail |
492 | * with boost::asio::error::would_block if they are unable to perform the |
493 | * requested operation immediately. If @c false, synchronous operations will |
494 | * block until complete. |
495 | * |
496 | * @throws boost::system::system_error Thrown on failure. |
497 | * |
498 | * @note The non-blocking mode has no effect on the behaviour of asynchronous |
499 | * operations. Asynchronous operations will never fail with the error |
500 | * boost::asio::error::would_block. |
501 | */ |
502 | void non_blocking(bool mode) |
503 | { |
504 | boost::system::error_code ec; |
505 | impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec); |
506 | boost::asio::detail::throw_error(err: ec, location: "non_blocking" ); |
507 | } |
508 | |
509 | /// Sets the non-blocking mode of the descriptor. |
510 | /** |
511 | * @param mode If @c true, the descriptor's synchronous operations will fail |
512 | * with boost::asio::error::would_block if they are unable to perform the |
513 | * requested operation immediately. If @c false, synchronous operations will |
514 | * block until complete. |
515 | * |
516 | * @param ec Set to indicate what error occurred, if any. |
517 | * |
518 | * @note The non-blocking mode has no effect on the behaviour of asynchronous |
519 | * operations. Asynchronous operations will never fail with the error |
520 | * boost::asio::error::would_block. |
521 | */ |
522 | BOOST_ASIO_SYNC_OP_VOID non_blocking( |
523 | bool mode, boost::system::error_code& ec) |
524 | { |
525 | impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec); |
526 | BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); |
527 | } |
528 | |
529 | /// Gets the non-blocking mode of the native descriptor implementation. |
530 | /** |
531 | * This function is used to retrieve the non-blocking mode of the underlying |
532 | * native descriptor. This mode has no effect on the behaviour of the |
533 | * descriptor object's synchronous operations. |
534 | * |
535 | * @returns @c true if the underlying descriptor is in non-blocking mode and |
536 | * direct system calls may fail with boost::asio::error::would_block (or the |
537 | * equivalent system error). |
538 | * |
539 | * @note The current non-blocking mode is cached by the descriptor object. |
540 | * Consequently, the return value may be incorrect if the non-blocking mode |
541 | * was set directly on the native descriptor. |
542 | */ |
543 | bool native_non_blocking() const |
544 | { |
545 | return impl_.get_service().native_non_blocking( |
546 | impl_.get_implementation()); |
547 | } |
548 | |
549 | /// Sets the non-blocking mode of the native descriptor implementation. |
550 | /** |
551 | * This function is used to modify the non-blocking mode of the underlying |
552 | * native descriptor. It has no effect on the behaviour of the descriptor |
553 | * object's synchronous operations. |
554 | * |
555 | * @param mode If @c true, the underlying descriptor is put into non-blocking |
556 | * mode and direct system calls may fail with boost::asio::error::would_block |
557 | * (or the equivalent system error). |
558 | * |
559 | * @throws boost::system::system_error Thrown on failure. If the @c mode is |
560 | * @c false, but the current value of @c non_blocking() is @c true, this |
561 | * function fails with boost::asio::error::invalid_argument, as the |
562 | * combination does not make sense. |
563 | */ |
564 | void native_non_blocking(bool mode) |
565 | { |
566 | boost::system::error_code ec; |
567 | impl_.get_service().native_non_blocking( |
568 | impl_.get_implementation(), mode, ec); |
569 | boost::asio::detail::throw_error(err: ec, location: "native_non_blocking" ); |
570 | } |
571 | |
572 | /// Sets the non-blocking mode of the native descriptor implementation. |
573 | /** |
574 | * This function is used to modify the non-blocking mode of the underlying |
575 | * native descriptor. It has no effect on the behaviour of the descriptor |
576 | * object's synchronous operations. |
577 | * |
578 | * @param mode If @c true, the underlying descriptor is put into non-blocking |
579 | * mode and direct system calls may fail with boost::asio::error::would_block |
580 | * (or the equivalent system error). |
581 | * |
582 | * @param ec Set to indicate what error occurred, if any. If the @c mode is |
583 | * @c false, but the current value of @c non_blocking() is @c true, this |
584 | * function fails with boost::asio::error::invalid_argument, as the |
585 | * combination does not make sense. |
586 | */ |
587 | BOOST_ASIO_SYNC_OP_VOID native_non_blocking( |
588 | bool mode, boost::system::error_code& ec) |
589 | { |
590 | impl_.get_service().native_non_blocking( |
591 | impl_.get_implementation(), mode, ec); |
592 | BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); |
593 | } |
594 | |
595 | /// Wait for the descriptor to become ready to read, ready to write, or to |
596 | /// have pending error conditions. |
597 | /** |
598 | * This function is used to perform a blocking wait for a descriptor to enter |
599 | * a ready to read, write or error condition state. |
600 | * |
601 | * @param w Specifies the desired descriptor state. |
602 | * |
603 | * @par Example |
604 | * Waiting for a descriptor to become readable. |
605 | * @code |
606 | * boost::asio::posix::stream_descriptor descriptor(my_context); |
607 | * ... |
608 | * descriptor.wait(boost::asio::posix::stream_descriptor::wait_read); |
609 | * @endcode |
610 | */ |
611 | void wait(wait_type w) |
612 | { |
613 | boost::system::error_code ec; |
614 | impl_.get_service().wait(impl_.get_implementation(), w, ec); |
615 | boost::asio::detail::throw_error(err: ec, location: "wait" ); |
616 | } |
617 | |
618 | /// Wait for the descriptor to become ready to read, ready to write, or to |
619 | /// have pending error conditions. |
620 | /** |
621 | * This function is used to perform a blocking wait for a descriptor to enter |
622 | * a ready to read, write or error condition state. |
623 | * |
624 | * @param w Specifies the desired descriptor state. |
625 | * |
626 | * @param ec Set to indicate what error occurred, if any. |
627 | * |
628 | * @par Example |
629 | * Waiting for a descriptor to become readable. |
630 | * @code |
631 | * boost::asio::posix::stream_descriptor descriptor(my_context); |
632 | * ... |
633 | * boost::system::error_code ec; |
634 | * descriptor.wait(boost::asio::posix::stream_descriptor::wait_read, ec); |
635 | * @endcode |
636 | */ |
637 | BOOST_ASIO_SYNC_OP_VOID wait(wait_type w, boost::system::error_code& ec) |
638 | { |
639 | impl_.get_service().wait(impl_.get_implementation(), w, ec); |
640 | BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); |
641 | } |
642 | |
643 | /// Asynchronously wait for the descriptor to become ready to read, ready to |
644 | /// write, or to have pending error conditions. |
645 | /** |
646 | * This function is used to perform an asynchronous wait for a descriptor to |
647 | * enter a ready to read, write or error condition state. It is an initiating |
648 | * function for an @ref asynchronous_operation, and always returns |
649 | * immediately. |
650 | * |
651 | * @param w Specifies the desired descriptor state. |
652 | * |
653 | * @param token The @ref completion_token that will be used to produce a |
654 | * completion handler, which will be called when the wait completes. |
655 | * Potential completion tokens include @ref use_future, @ref use_awaitable, |
656 | * @ref yield_context, or a function object with the correct completion |
657 | * signature. The function signature of the completion handler must be: |
658 | * @code void handler( |
659 | * const boost::system::error_code& error // Result of operation. |
660 | * ); @endcode |
661 | * Regardless of whether the asynchronous operation completes immediately or |
662 | * not, the completion handler will not be invoked from within this function. |
663 | * On immediate completion, invocation of the handler will be performed in a |
664 | * manner equivalent to using boost::asio::post(). |
665 | * |
666 | * @par Completion Signature |
667 | * @code void(boost::system::error_code) @endcode |
668 | * |
669 | * @par Example |
670 | * @code |
671 | * void wait_handler(const boost::system::error_code& error) |
672 | * { |
673 | * if (!error) |
674 | * { |
675 | * // Wait succeeded. |
676 | * } |
677 | * } |
678 | * |
679 | * ... |
680 | * |
681 | * boost::asio::posix::stream_descriptor descriptor(my_context); |
682 | * ... |
683 | * descriptor.async_wait( |
684 | * boost::asio::posix::stream_descriptor::wait_read, |
685 | * wait_handler); |
686 | * @endcode |
687 | * |
688 | * @par Per-Operation Cancellation |
689 | * This asynchronous operation supports cancellation for the following |
690 | * boost::asio::cancellation_type values: |
691 | * |
692 | * @li @c cancellation_type::terminal |
693 | * |
694 | * @li @c cancellation_type::partial |
695 | * |
696 | * @li @c cancellation_type::total |
697 | */ |
698 | template < |
699 | BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code)) |
700 | WaitToken = default_completion_token_t<executor_type>> |
701 | auto async_wait(wait_type w, |
702 | WaitToken&& token = default_completion_token_t<executor_type>()) |
703 | -> decltype( |
704 | async_initiate<WaitToken, void (boost::system::error_code)>( |
705 | declval<initiate_async_wait>(), token, w)) |
706 | { |
707 | return async_initiate<WaitToken, void (boost::system::error_code)>( |
708 | initiate_async_wait(this), token, w); |
709 | } |
710 | |
711 | protected: |
712 | /// Protected destructor to prevent deletion through this type. |
713 | /** |
714 | * This function destroys the descriptor, cancelling any outstanding |
715 | * asynchronous wait operations associated with the descriptor as if by |
716 | * calling @c cancel. |
717 | */ |
718 | ~basic_descriptor() |
719 | { |
720 | } |
721 | |
722 | #if defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT) |
723 | detail::io_object_impl<detail::io_uring_descriptor_service, Executor> impl_; |
724 | #else // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT) |
725 | detail::io_object_impl<detail::reactive_descriptor_service, Executor> impl_; |
726 | #endif // defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT) |
727 | |
728 | private: |
729 | // Disallow copying and assignment. |
730 | basic_descriptor(const basic_descriptor&) = delete; |
731 | basic_descriptor& operator=(const basic_descriptor&) = delete; |
732 | |
733 | class initiate_async_wait |
734 | { |
735 | public: |
736 | typedef Executor executor_type; |
737 | |
738 | explicit initiate_async_wait(basic_descriptor* self) |
739 | : self_(self) |
740 | { |
741 | } |
742 | |
743 | const executor_type& get_executor() const noexcept |
744 | { |
745 | return self_->get_executor(); |
746 | } |
747 | |
748 | template <typename WaitHandler> |
749 | void operator()(WaitHandler&& handler, wait_type w) const |
750 | { |
751 | // If you get an error on the following line it means that your handler |
752 | // does not meet the documented type requirements for a WaitHandler. |
753 | BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; |
754 | |
755 | detail::non_const_lvalue<WaitHandler> handler2(handler); |
756 | self_->impl_.get_service().async_wait( |
757 | self_->impl_.get_implementation(), w, |
758 | handler2.value, self_->impl_.get_executor()); |
759 | } |
760 | |
761 | private: |
762 | basic_descriptor* self_; |
763 | }; |
764 | }; |
765 | |
766 | } // namespace posix |
767 | } // namespace asio |
768 | } // namespace boost |
769 | |
770 | #include <boost/asio/detail/pop_options.hpp> |
771 | |
772 | #endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) |
773 | // || defined(GENERATING_DOCUMENTATION) |
774 | |
775 | #endif // BOOST_ASIO_POSIX_BASIC_DESCRIPTOR_HPP |
776 | |