Struct mio::Poll[][src]

pub struct Poll {
    selector: Selector,
    readiness_queue: ReadinessQueue,
    lock_state: AtomicUsize,
    lock: Mutex<()>,
    condvar: Condvar,
}
Expand description

Polls for readiness events on all registered values.

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

To use Poll, an Evented type must first be registered with the Poll instance using the register method, 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 Evented handle that generated the event.

Examples

A basic example – establishing a TcpStream connection.

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

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

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

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

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

// Register the stream with `Poll`
poll.register(&stream, Token(0), Ready::readable() | Ready::writable(), PollOpt::edge())?;

// 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.readiness().is_writable() {
            // The socket connected (probably, it could still be a spurious
            // wakeup)
            return Ok(());
        }
    }
}

Edge-triggered and level-triggered

An Evented registration may request edge-triggered events or level-triggered events. This is done by setting register’s PollOpt argument to either edge or level.

The difference between the two can be described as follows. Supposed that this scenario happens:

  1. A TcpStream is registered with Poll.
  2. The socket receives 2kb of data.
  3. A call to Poll::poll returns the token associated with the socket indicating readable readiness.
  4. 1kb is read from the socket.
  5. Another call to Poll::poll is made.

If when the socket was registered with Poll, edge triggered events were requested, then the call to Poll::poll done in step 5 will (probably) hang despite there being another 1kb still present in the socket read buffer. The reason for this is that edge-triggered mode delivers events only when changes occur on the monitored Evented. So, in step 5 the caller might end up waiting for some data that is already present inside the socket buffer.

With edge-triggered events, operations must be performed on the Evented type until WouldBlock is returned. In other words, after receiving an event indicating readiness for a certain operation, one should assume that Poll::poll may never return another event for the same token and readiness until the operation returns WouldBlock.

By contrast, when level-triggered notifications was requested, each call to Poll::poll will return an event for the socket as long as data remains in the socket buffer. Generally, level-triggered events should be avoided if high performance is a concern.

Since even with edge-triggered events, multiple events can be generated upon receipt of multiple chunks of data, the caller has the option to set the oneshot flag. This tells Poll to disable the associated Evented after the event is returned from Poll::poll. The subsequent calls to Poll::poll will no longer include events for Evented handles that are disabled even if the readiness state changes. The handle can be re-enabled by calling reregister. When handles are disabled, internal resources used to monitor the handle are maintained until the handle is dropped or deregistered. This makes re-registering the handle a fast operation.

For example, in the following scenario:

  1. A TcpStream is registered with Poll.
  2. The socket receives 2kb of data.
  3. A call to Poll::poll returns the token associated with the socket indicating readable readiness.
  4. 2kb is read from the socket.
  5. Another call to read is issued and WouldBlock is returned
  6. The socket receives another 2kb of data.
  7. Another call to Poll::poll is made.

Assuming the socket was registered with Poll with the edge and oneshot options, then the call to Poll::poll in step 7 would block. This is because, oneshot tells Poll to disable events for the socket after returning an event.

In order to receive the event for the data received in step 6, the socket would need to be reregistered using reregister.

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 Evented handle 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 notification 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

When using edge-triggered mode, 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 Evented handle.

For example, in the first scenario described above, after step 5, even if the socket receives more data there is no guarantee that another readiness event will be delivered.

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, error, and hup interest, and either an error or hup 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 hup 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 hup or error readiness should be doing so as an optimization and always be able to handle an error or HUP situation when performing the actual read operation.

Registering handles

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

For example:

use mio::{Poll, Ready, PollOpt, Token};
use mio::net::TcpStream;
use std::time::Duration;
use std::thread;

let sock = TcpStream::connect(&"216.58.193.100:80".parse()?)?;

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.register(&sock, Token(0), Ready::readable() | Ready::writable(), PollOpt::edge())?;

Implementation notes

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

OSSelector
Linuxepoll
OS X, iOSkqueue
WindowsIOCP
FreeBSDkqueue
Androidepoll

On all supported platforms, socket operations are handled by using the system selector. Platform specific extensions (e.g. EventedFd) 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 EventedFd.

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.

Notifications generated by SetReadiness are handled by an internal readiness queue. A single call to Poll::poll will collect events from both from the system selector and the internal readiness queue.

Fields

selector: Selectorreadiness_queue: ReadinessQueuelock_state: AtomicUsizelock: Mutex<()>condvar: Condvar

Implementations

Return a new Poll handle.

This function will make a syscall to the operating system to create the system selector. If this syscall fails, Poll::new will return with the error.

See struct level docs for more details.

Examples
use mio::{Poll, Events};
use std::time::Duration;

let poll = match Poll::new() {
    Ok(poll) => poll,
    Err(e) => panic!("failed to create Poll instance; err={:?}", e),
};

// Create a structure to receive polled events
let mut events = Events::with_capacity(1024);

// Wait for events, but none will be received because no `Evented`
// handles have been registered with this `Poll` instance.
let n = poll.poll(&mut events, Some(Duration::from_millis(500)))?;
assert_eq!(n, 0);

Register an Evented handle with the Poll instance.

Once registered, the Poll instance will monitor the Evented handle for readiness state changes. When it notices a state change, it will return a readiness event for the handle the next time poll is called.

See the struct docs for a high level overview.

Arguments

handle: &E: Evented: This is the handle that the Poll instance should monitor for readiness state changes.

token: Token: The caller picks a token to associate with the socket. When poll returns an event for the handle, this token is included. This allows the caller to map the event to its handle. The token associated with the Evented handle can be changed at any time by calling reregister.

token cannot be Token(usize::MAX) as it is reserved for internal usage.

See documentation on Token for an example showing how to pick Token values.

interest: Ready: Specifies which operations Poll should monitor for readiness. Poll will only return readiness events for operations specified by this argument.

If a socket is registered with readable interest and the socket becomes writable, no event will be returned from poll.

The readiness interest for an Evented handle can be changed at any time by calling reregister.

opts: PollOpt: Specifies the registration options. The most common options being level for level-triggered events, edge for edge-triggered events, and oneshot.

The registration options for an Evented handle can be changed at any time by calling reregister.

Notes

Unless otherwise specified, the caller should assume that once an Evented handle is registered with a Poll instance, it is bound to that Poll instance for the lifetime of the Evented handle. This remains true even if the Evented handle is deregistered from the poll instance using deregister.

This function is thread safe. It can be called concurrently from multiple threads.

Examples
use mio::{Events, Poll, Ready, PollOpt, Token};
use mio::net::TcpStream;
use std::time::{Duration, Instant};

let poll = Poll::new()?;
let socket = TcpStream::connect(&"216.58.193.100:80".parse()?)?;

// Register the socket with `poll`
poll.register(&socket, Token(0), Ready::readable() | Ready::writable(), PollOpt::edge())?;

let mut events = Events::with_capacity(1024);
let start = Instant::now();
let timeout = Duration::from_millis(500);

loop {
    let elapsed = start.elapsed();

    if elapsed >= timeout {
        // Connection timed out
        return Ok(());
    }

    let remaining = timeout - elapsed;
    poll.poll(&mut events, Some(remaining))?;

    for event in &events {
        if event.token() == Token(0) {
            // Something (probably) happened on the socket.
            return Ok(());
        }
    }
}

Re-register an Evented handle with the Poll instance.

Re-registering an Evented handle allows changing the details of the registration. Specifically, it allows updating the associated token, interest, and opts specified in previous register and reregister calls.

The reregister arguments fully override the previous values. In other words, if a socket is registered with readable interest and the call to reregister specifies writable, then read interest is no longer requested for the handle.

The Evented handle must have previously been registered with this instance of Poll otherwise the call to reregister will return with an error.

token cannot be Token(usize::MAX) as it is reserved for internal usage.

See the register documentation for details about the function arguments and see the struct docs for a high level overview of polling.

Examples
use mio::{Poll, Ready, PollOpt, Token};
use mio::net::TcpStream;

let poll = Poll::new()?;
let socket = TcpStream::connect(&"216.58.193.100:80".parse()?)?;

// Register the socket with `poll`, requesting readable
poll.register(&socket, Token(0), Ready::readable(), PollOpt::edge())?;

// Reregister the socket specifying a different token and write interest
// instead. `PollOpt::edge()` must be specified even though that value
// is not being changed.
poll.reregister(&socket, Token(2), Ready::writable(), PollOpt::edge())?;

Deregister an Evented handle with the Poll instance.

When an Evented handle is deregistered, the Poll instance will no longer monitor it for readiness state changes. Unlike disabling handles with oneshot, deregistering clears up any internal resources needed to track the handle.

A handle can be passed back to register after it has been deregistered; however, it must be passed back to the same Poll instance.

Evented handles are automatically deregistered when they are dropped. It is common to never need to explicitly call deregister.

Examples
use mio::{Events, Poll, Ready, PollOpt, Token};
use mio::net::TcpStream;
use std::time::Duration;

let poll = Poll::new()?;
let socket = TcpStream::connect(&"216.58.193.100:80".parse()?)?;

// Register the socket with `poll`
poll.register(&socket, Token(0), Ready::readable(), PollOpt::edge())?;

poll.deregister(&socket)?;

let mut events = Events::with_capacity(1024);

// Set a timeout because this poll should never receive any events.
let n = poll.poll(&mut events, Some(Duration::from_secs(1)))?;
assert_eq!(0, n);

Wait for readiness events

Blocks the current thread and waits for readiness events for any of the Evented handles 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 Evented handle. 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.

poll returns the number of readiness events that have been pushed into events or Err when an error has been encountered with the system selector. The value returned is deprecated and will be removed in 0.7.0. Accessing the events by index is also deprecated. Events can be inserted by other events triggering, thus making sequential access problematic. Use the iterator API instead. See iter.

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

Examples

A basic example – establishing a TcpStream connection.

use mio::{Events, Poll, Ready, PollOpt, 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 poll = Poll::new()?;
let mut events = Events::with_capacity(1024);

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

// Register the stream with `Poll`
poll.register(&stream, Token(0), Ready::readable() | Ready::writable(), PollOpt::edge())?;

// 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.readiness().is_writable() {
            // The socket connected (probably, it could still be a spurious
            // wakeup)
            return Ok(());
        }
    }
}

Like poll, but may be interrupted by a signal

If poll is inturrupted while blocking, it will transparently retry the syscall. If you want to handle signals yourself, however, use poll_interruptible.

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

Performs the conversion.

Performs the conversion.

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.