pub struct AsyncFdReadyGuard<'a, T: AsRawFd> { /* private fields */ }
Expand description
Represents an IO-ready event detected on a particular file descriptor that
has not yet been acknowledged. This is a must_use
structure to help ensure
that you do not forget to explicitly clear (or not clear) the event.
This type exposes an immutable reference to the underlying IO object.
Implementations§
Source§impl<'a, Inner: AsRawFd> AsyncFdReadyGuard<'a, Inner>
impl<'a, Inner: AsRawFd> AsyncFdReadyGuard<'a, Inner>
Sourcepub fn clear_ready(&mut self)
pub fn clear_ready(&mut self)
Indicates to tokio that the file descriptor is no longer ready. All internal readiness flags will be cleared, and tokio will wait for the next edge-triggered readiness notification from the OS.
This function is commonly used with guards returned by AsyncFd::readable
and
AsyncFd::writable
.
It is critical that this function not be called unless your code actually observes that the file descriptor is not ready. Do not call it simply because, for example, a read succeeded; it should be called when a read is observed to block.
This method only clears readiness events that happened before the creation of this guard.
In other words, if the IO resource becomes ready between the creation of the guard and
this call to clear_ready
, then the readiness is not actually cleared.
Sourcepub fn clear_ready_matching(&mut self, ready: Ready)
pub fn clear_ready_matching(&mut self, ready: Ready)
Indicates to tokio that the file descriptor no longer has a specific readiness. The internal readiness flag will be cleared, and tokio will wait for the next edge-triggered readiness notification from the OS.
This function is useful in combination with the AsyncFd::ready
method when a
combined interest like Interest::READABLE | Interest::WRITABLE
is used.
It is critical that this function not be called unless your code
actually observes that the file descriptor is not ready for the provided Ready
.
Do not call it simply because, for example, a read succeeded; it should be called
when a read is observed to block. Only clear the specific readiness that is observed to
block. For example when a read blocks when using a combined interest,
only clear Ready::READABLE
.
This method only clears readiness events that happened before the creation of this guard.
In other words, if the IO resource becomes ready between the creation of the guard and
this call to clear_ready
, then the readiness is not actually cleared.
§Examples
Concurrently read and write to a std::net::TcpStream
on the same task without
splitting.
use std::error::Error;
use std::io;
use std::io::{Read, Write};
use std::net::TcpStream;
use tokio::io::unix::AsyncFd;
use tokio::io::{Interest, Ready};
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let stream = TcpStream::connect("127.0.0.1:8080")?;
stream.set_nonblocking(true)?;
let stream = AsyncFd::new(stream)?;
loop {
let mut guard = stream
.ready(Interest::READABLE | Interest::WRITABLE)
.await?;
if guard.ready().is_readable() {
let mut data = vec![0; 1024];
// Try to read data, this may still fail with `WouldBlock`
// if the readiness event is a false positive.
match stream.get_ref().read(&mut data) {
Ok(n) => {
println!("read {} bytes", n);
}
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
// a read has blocked, but a write might still succeed.
// clear only the read readiness.
guard.clear_ready_matching(Ready::READABLE);
continue;
}
Err(e) => {
return Err(e.into());
}
}
}
if guard.ready().is_writable() {
// Try to write data, this may still fail with `WouldBlock`
// if the readiness event is a false positive.
match stream.get_ref().write(b"hello world") {
Ok(n) => {
println!("write {} bytes", n);
}
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
// a write has blocked, but a read might still succeed.
// clear only the write readiness.
guard.clear_ready_matching(Ready::WRITABLE);
continue;
}
Err(e) => {
return Err(e.into());
}
}
}
}
}
Sourcepub fn retain_ready(&mut self)
pub fn retain_ready(&mut self)
This method should be invoked when you intentionally want to keep the ready flag asserted.
While this function is itself a no-op, it satisfies the #[must_use]
constraint on the AsyncFdReadyGuard
type.
Sourcepub fn ready(&self) -> Ready
pub fn ready(&self) -> Ready
Get the Ready
value associated with this guard.
This method will return the empty readiness state if
AsyncFdReadyGuard::clear_ready
has been called on
the guard.
Sourcepub fn try_io<R>(
&mut self,
f: impl FnOnce(&'a AsyncFd<Inner>) -> Result<R>,
) -> Result<Result<R>, TryIoError>
pub fn try_io<R>( &mut self, f: impl FnOnce(&'a AsyncFd<Inner>) -> Result<R>, ) -> Result<Result<R>, TryIoError>
Performs the provided IO operation.
If f
returns a WouldBlock
error, the readiness state associated
with this file descriptor is cleared, and the method returns
Err(TryIoError::WouldBlock)
. You will typically need to poll the
AsyncFd
again when this happens.
This method helps ensure that the readiness state of the underlying file
descriptor remains in sync with the tokio-side readiness state, by
clearing the tokio-side state only when a WouldBlock
condition
occurs. It is the responsibility of the caller to ensure that f
returns WouldBlock
only if the file descriptor that originated this
AsyncFdReadyGuard
no longer expresses the readiness state that was queried to
create this AsyncFdReadyGuard
.
§Examples
This example sends some bytes to the inner std::net::UdpSocket
. Waiting
for write-readiness and retrying when the send operation does block are explicit.
This example can be written more succinctly using AsyncFd::async_io
.
use tokio::io::unix::AsyncFd;
use std::io;
use std::net::UdpSocket;
#[tokio::main]
async fn main() -> io::Result<()> {
let socket = UdpSocket::bind("0.0.0.0:8080")?;
socket.set_nonblocking(true)?;
let async_fd = AsyncFd::new(socket)?;
let written = loop {
let mut guard = async_fd.writable().await?;
match guard.try_io(|inner| inner.get_ref().send(&[1, 2])) {
Ok(result) => {
break result?;
}
Err(_would_block) => {
// try_io already cleared the file descriptor's readiness state
continue;
}
}
};
println!("wrote {written} bytes");
Ok(())
}