[−][src]Struct mio::Poll
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:
- A
TcpStreamis registered withPoll. - The socket receives 2kb of data.
- A call to
Poll::pollreturns the token associated with the socket indicating readable readiness. - 1kb is read from the socket.
- Another call to
Poll::pollis 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:
- A
TcpStreamis registered withPoll. - The socket receives 2kb of data.
- A call to
Poll::pollreturns the token associated with the socket indicating readable readiness. - 2kb is read from the socket.
- Another call to read is issued and
WouldBlockis returned - The socket receives another 2kb of data.
- Another call to
Poll::pollis 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.
| OS | Selector |
|---|---|
| Linux | epoll |
| OS X, iOS | kqueue |
| Windows | IOCP |
| FreeBSD | kqueue |
| Android | epoll |
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.
Implementations
impl Poll[src]
pub fn new() -> Result<Poll>[src]
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);
pub fn register<E: ?Sized>(
&self,
handle: &E,
token: Token,
interest: Ready,
opts: PollOpt
) -> Result<()> where
E: Evented, [src]
&self,
handle: &E,
token: Token,
interest: Ready,
opts: PollOpt
) -> Result<()> where
E: Evented,
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(()); } } }
pub fn reregister<E: ?Sized>(
&self,
handle: &E,
token: Token,
interest: Ready,
opts: PollOpt
) -> Result<()> where
E: Evented, [src]
&self,
handle: &E,
token: Token,
interest: Ready,
opts: PollOpt
) -> Result<()> where
E: Evented,
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())?;
pub fn deregister<E: ?Sized>(&self, handle: &E) -> Result<()> where
E: Evented, [src]
E: Evented,
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);
pub fn poll(
&self,
events: &mut Events,
timeout: Option<Duration>
) -> Result<usize>[src]
&self,
events: &mut Events,
timeout: Option<Duration>
) -> Result<usize>
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(()); } } }
pub fn poll_interruptible(
&self,
events: &mut Events,
timeout: Option<Duration>
) -> Result<usize>[src]
&self,
events: &mut Events,
timeout: Option<Duration>
) -> Result<usize>
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
Auto Trait Implementations
impl !RefUnwindSafe for Poll
impl Send for Poll
impl Sync for Poll
impl Unpin for Poll
impl !UnwindSafe for Poll
Blanket Implementations
impl<T> Any for T where
T: 'static + ?Sized, [src]
T: 'static + ?Sized,
impl<T> Borrow<T> for T where
T: ?Sized, [src]
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized, [src]
T: ?Sized,
fn borrow_mut(&mut self) -> &mut T[src]
impl<T> From<T> for T[src]
impl<T, U> Into<U> for T where
U: From<T>, [src]
U: From<T>,
impl<T, U> TryFrom<U> for T where
U: Into<T>, [src]
U: Into<T>,
type Error = Infallible
The type returned in the event of a conversion error.
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>[src]
impl<T, U> TryInto<U> for T where
U: TryFrom<T>, [src]
U: TryFrom<T>,