Struct mio::Poll

source · []
pub struct Poll { /* private fields */ }
Expand description

Polls for readiness events on all registered values.

Poll allows a program to monitor a large number of event::Sources, waiting until one or more become “ready” for some class of operations; e.g. reading and writing. An event source is considered ready if it is possible to immediately perform a corresponding operation; e.g. read or write.

To use Poll, an event::Source must first be registered with the Poll instance using the register method on its associated Register, supplying readiness interest. The readiness interest tells Poll which specific operations on the handle to monitor for readiness. A Token is also passed to the register function. When Poll returns a readiness event, it will include this token. This associates the event with the event source that generated the event.

Examples

A basic example – establishing a TcpStream connection.

use mio::{Events, Poll, Interest, Token};
use mio::net::TcpStream;

use std::net::{self, SocketAddr};

// Bind a server socket to connect to.
let addr: SocketAddr = "127.0.0.1:0".parse()?;
let server = net::TcpListener::bind(addr)?;

// Construct a new `Poll` handle as well as the `Events` we'll store into
let mut poll = Poll::new()?;
let mut events = Events::with_capacity(1024);

// Connect the stream
let mut stream = TcpStream::connect(server.local_addr()?)?;

// Register the stream with `Poll`
poll.registry().register(&mut stream, Token(0), Interest::READABLE | Interest::WRITABLE)?;

// Wait for the socket to become ready. This has to happens in a loop to
// handle spurious wakeups.
loop {
    poll.poll(&mut events, None)?;

    for event in &events {
        if event.token() == Token(0) && event.is_writable() {
            // The socket connected (probably, it could still be a spurious
            // wakeup)
            return Ok(());
        }
    }
}

Portability

Using Poll provides a portable interface across supported platforms as long as the caller takes the following into consideration:

Spurious events

Poll::poll may return readiness events even if the associated event source is not actually ready. Given the same code, this may happen more on some platforms than others. It is important to never assume that, just because a readiness event was received, that the associated operation will succeed as well.

If operation fails with WouldBlock, then the caller should not treat this as an error, but instead should wait until another readiness event is received.

Draining readiness

Once a readiness event is received, the corresponding operation must be performed repeatedly until it returns WouldBlock. Unless this is done, there is no guarantee that another readiness event will be delivered, even if further data is received for the event source.

Readiness operations

The only readiness operations that are guaranteed to be present on all supported platforms are readable and writable. All other readiness operations may have false negatives and as such should be considered hints. This means that if a socket is registered with readable interest and either an error or close is received, a readiness event will be generated for the socket, but it may only include readable readiness. Also note that, given the potential for spurious events, receiving a readiness event with read_closed, write_closed, or error doesn’t actually mean that a read on the socket will return a result matching the readiness event.

In other words, portable programs that explicitly check for read_closed, write_closed, or error readiness should be doing so as an optimization and always be able to handle an error or close situation when performing the actual read operation.

Registering handles

Unless otherwise noted, it should be assumed that types implementing event::Source will never become ready unless they are registered with Poll.

For example:

use mio::{Poll, Interest, Token};
use mio::net::TcpStream;
use std::net::SocketAddr;
use std::time::Duration;
use std::thread;

let address: SocketAddr = "127.0.0.1:0".parse()?;
let listener = net::TcpListener::bind(address)?;
let mut sock = TcpStream::connect(listener.local_addr()?)?;

thread::sleep(Duration::from_secs(1));

let poll = Poll::new()?;

// The connect is not guaranteed to have started until it is registered at
// this point
poll.registry().register(&mut sock, Token(0), Interest::READABLE | Interest::WRITABLE)?;

Dropping Poll

When the Poll instance is dropped it may cancel in-flight operations for the registered event sources, meaning that no further events for them may be received. It also means operations on the registered event sources may no longer work. It is up to the user to keep the Poll instance alive while registered event sources are being used.

Implementation notes

Poll is backed by the selector provided by the operating system.

OSSelector
Androidepoll
DragonFly BSDkqueue
FreeBSDkqueue
Linuxepoll
NetBSDkqueue
OpenBSDkqueue
Solarisepoll
illumosepoll
WindowsIOCP
iOSkqueue
macOSkqueue

On all supported platforms, socket operations are handled by using the system selector. Platform specific extensions (e.g. SourceFd) allow accessing other features provided by individual system selectors. For example, Linux’s signalfd feature can be used by registering the FD with Poll via SourceFd.

On all platforms except windows, a call to Poll::poll is mostly just a direct call to the system selector. However, IOCP uses a completion model instead of a readiness model. In this case, Poll must adapt the completion model Mio’s API. While non-trivial, the bridge layer is still quite efficient. The most expensive part being calls to read and write require data to be copied into an intermediate buffer before it is passed to the kernel.

Implementations

Create a separate Registry which can be used to register event::Sources.

Wait for readiness events

Blocks the current thread and waits for readiness events for any of the event::Sources that have been registered with this Poll instance. The function will block until either at least one readiness event has been received or timeout has elapsed. A timeout of None means that poll will block until a readiness event has been received.

The supplied events will be cleared and newly received readiness events will be pushed onto the end. At most events.capacity() events will be returned. If there are further pending readiness events, they will be returned on the next call to poll.

A single call to poll may result in multiple readiness events being returned for a single event source. For example, if a TCP socket becomes both readable and writable, it may be possible for a single readiness event to be returned with both readable and writable readiness OR two separate events may be returned, one with readable set and one with writable set.

Note that the timeout will be rounded up to the system clock granularity (usually 1ms), and kernel scheduling delays mean that the blocking interval may be overrun by a small amount.

See the struct level documentation for a higher level discussion of polling.

Notes

This returns any errors without attempting to retry, previous versions of Mio would automatically retry the poll call if it was interrupted (if EINTR was returned).

Examples

A basic example – establishing a TcpStream connection.

use mio::{Events, Poll, Interest, Token};
use mio::net::TcpStream;

use std::net::{TcpListener, SocketAddr};
use std::thread;

// Bind a server socket to connect to.
let addr: SocketAddr = "127.0.0.1:0".parse()?;
let server = TcpListener::bind(addr)?;
let addr = server.local_addr()?.clone();

// Spawn a thread to accept the socket
thread::spawn(move || {
    let _ = server.accept();
});

// Construct a new `Poll` handle as well as the `Events` we'll store into
let mut poll = Poll::new()?;
let mut events = Events::with_capacity(1024);

// Connect the stream
let mut stream = TcpStream::connect(addr)?;

// Register the stream with `Poll`
poll.registry().register(
    &mut stream,
    Token(0),
    Interest::READABLE | Interest::WRITABLE)?;

// Wait for the socket to become ready. This has to happens in a loop to
// handle spurious wakeups.
loop {
    poll.poll(&mut events, None)?;

    for event in &events {
        if event.token() == Token(0) && event.is_writable() {
            // The socket connected (probably, it could still be a spurious
            // wakeup)
            return Ok(());
        }
    }
}

Trait Implementations

Extracts the raw file descriptor. Read more

Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

Immutably borrows from an owned value. Read more

Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The type returned in the event of a conversion error.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.