Files
tokio/src/readiness_stream.rs
T

167 lines
6.1 KiB
Rust
Raw Normal View History

2016-07-30 17:53:12 -07:00
use std::io;
2016-08-17 09:29:05 -07:00
use std::sync::atomic::{AtomicUsize, Ordering};
2016-07-30 17:53:12 -07:00
2016-09-01 16:42:48 -07:00
use futures::{Future, Poll, Async};
2016-08-20 22:59:14 -07:00
use mio;
2016-07-30 17:53:12 -07:00
2016-08-20 22:59:14 -07:00
use event_loop::{IoToken, LoopHandle, AddSource};
2016-07-30 17:53:12 -07:00
2016-08-01 17:41:58 -07:00
/// A concrete implementation of a stream of readiness notifications for I/O
/// objects that originates from an event loop.
///
/// Created by the `ReadinessStream::new` method, each `ReadinessStream` is
/// associated with a specific event loop and source of events that will be
/// registered with an event loop.
///
2016-08-18 10:21:25 -07:00
/// Each readiness stream has a number of methods to test whether the underlying
/// object is readable or writable. Once the methods return that an object is
/// readable/writable, then it will continue to do so until the `need_read` or
/// `need_write` methods are called.
2016-08-01 17:41:58 -07:00
///
2016-08-18 10:21:25 -07:00
/// That is, this object is typically wrapped in another form of I/O object.
/// It's the responsibility of the wrapper to inform the readiness stream when a
/// "would block" I/O event is seen. The readiness stream will then take care of
/// any scheduling necessary to get notified when the event is ready again.
2016-08-20 22:59:14 -07:00
pub struct ReadinessStream<E> {
token: IoToken,
handle: LoopHandle,
2016-08-17 09:29:05 -07:00
readiness: AtomicUsize,
2016-08-20 22:59:14 -07:00
io: E,
2016-07-30 17:53:12 -07:00
}
2016-08-20 22:59:14 -07:00
pub struct ReadinessStreamNew<E> {
inner: AddSource<E>,
handle: LoopHandle,
}
2016-08-20 22:59:14 -07:00
impl<E> ReadinessStream<E>
where E: mio::Evented + Send + 'static,
{
2016-08-01 17:41:58 -07:00
/// Creates a new readiness stream associated with the provided
/// `loop_handle` and for the given `source`.
///
/// This method returns a future which will resolve to the readiness stream
/// when it's ready.
2016-08-20 22:59:14 -07:00
pub fn new(loop_handle: LoopHandle, source: E) -> ReadinessStreamNew<E> {
ReadinessStreamNew {
2016-08-20 22:59:14 -07:00
inner: loop_handle.add_source(source),
handle: loop_handle,
}
}
2016-08-20 23:41:19 -07:00
}
2016-08-17 09:29:05 -07:00
2016-08-20 23:41:19 -07:00
impl<E> ReadinessStream<E> {
2016-08-17 09:29:05 -07:00
/// Tests to see if this source is ready to be read from or not.
2016-08-18 10:21:25 -07:00
///
/// If this stream is not ready for a read then `NotReady` will be returned
/// and the current task will be scheduled to receive a notification when
/// the stream is readable again. In other words, this method is only safe
/// to call from within the context of a future's task, typically done in a
/// `Future::poll` method.
2016-08-17 09:29:05 -07:00
pub fn poll_read(&self) -> Poll<(), io::Error> {
if self.readiness.load(Ordering::SeqCst) & 1 != 0 {
2016-09-01 16:42:48 -07:00
return Ok(Async::Ready(()))
2016-08-17 09:29:05 -07:00
}
2016-08-20 22:59:14 -07:00
self.readiness.fetch_or(self.token.take_readiness(), Ordering::SeqCst);
2016-08-17 09:29:05 -07:00
if self.readiness.load(Ordering::SeqCst) & 1 != 0 {
2016-09-01 16:42:48 -07:00
Ok(Async::Ready(()))
2016-08-17 09:29:05 -07:00
} else {
2016-08-20 22:59:14 -07:00
self.handle.schedule_read(&self.token);
2016-09-01 16:42:48 -07:00
Ok(Async::NotReady)
2016-08-17 09:29:05 -07:00
}
}
/// Tests to see if this source is ready to be written to or not.
2016-08-18 10:21:25 -07:00
///
/// If this stream is not ready for a write then `NotReady` will be returned
/// and the current task will be scheduled to receive a notification when
/// the stream is writable again. In other words, this method is only safe
/// to call from within the context of a future's task, typically done in a
/// `Future::poll` method.
2016-08-17 09:29:05 -07:00
pub fn poll_write(&self) -> Poll<(), io::Error> {
if self.readiness.load(Ordering::SeqCst) & 2 != 0 {
2016-09-01 16:42:48 -07:00
return Ok(Async::Ready(()))
2016-08-17 09:29:05 -07:00
}
2016-08-20 22:59:14 -07:00
self.readiness.fetch_or(self.token.take_readiness(), Ordering::SeqCst);
2016-08-17 09:29:05 -07:00
if self.readiness.load(Ordering::SeqCst) & 2 != 0 {
2016-09-01 16:42:48 -07:00
Ok(Async::Ready(()))
2016-08-17 09:29:05 -07:00
} else {
2016-08-20 22:59:14 -07:00
self.handle.schedule_write(&self.token);
2016-09-01 16:42:48 -07:00
Ok(Async::NotReady)
2016-08-17 09:29:05 -07:00
}
}
2016-08-18 10:21:25 -07:00
/// Indicates to this source of events that the corresponding I/O object is
/// no longer readable, but it needs to be.
///
/// This function, like `poll_read`, is only safe to call from the context
/// of a future's task (typically in a `Future::poll` implementation). It
/// informs this readiness stream that the underlying object is no longer
/// readable, typically because a "would block" error was seen.
///
/// The flag indicating that this stream is readable is unset and the
/// current task is scheduled to receive a notification when the stream is
/// then again readable.
2016-08-17 09:29:05 -07:00
pub fn need_read(&self) {
self.readiness.fetch_and(!1, Ordering::SeqCst);
2016-08-20 22:59:14 -07:00
self.handle.schedule_read(&self.token);
2016-08-17 09:29:05 -07:00
}
2016-08-18 10:21:25 -07:00
/// Indicates to this source of events that the corresponding I/O object is
/// no longer writable, but it needs to be.
///
/// This function, like `poll_write`, is only safe to call from the context
/// of a future's task (typically in a `Future::poll` implementation). It
/// informs this readiness stream that the underlying object is no longer
/// writable, typically because a "would block" error was seen.
///
/// The flag indicating that this stream is writable is unset and the
/// current task is scheduled to receive a notification when the stream is
/// then again writable.
2016-08-17 09:29:05 -07:00
pub fn need_write(&self) {
self.readiness.fetch_and(!2, Ordering::SeqCst);
2016-08-20 22:59:14 -07:00
self.handle.schedule_write(&self.token);
}
/// Returns a reference to the event loop handle that this readiness stream
/// is associated with.
pub fn loop_handle(&self) -> &LoopHandle {
&self.handle
}
/// Returns a shared reference to the underlying I/O object this readiness
/// stream is wrapping.
pub fn get_ref(&self) -> &E {
&self.io
}
/// Returns a mutable reference to the underlying I/O object this readiness
/// stream is wrapping.
pub fn get_mut(&mut self) -> &mut E {
&mut self.io
2016-08-17 09:29:05 -07:00
}
}
2016-08-20 22:59:14 -07:00
impl<E> Future for ReadinessStreamNew<E>
where E: mio::Evented + Send + 'static,
{
type Item = ReadinessStream<E>;
type Error = io::Error;
2016-08-20 22:59:14 -07:00
fn poll(&mut self) -> Poll<ReadinessStream<E>, io::Error> {
2016-09-01 16:42:48 -07:00
let (io, token) = try_ready!(self.inner.poll());
Ok(ReadinessStream {
token: token,
handle: self.handle.clone(),
io: io,
readiness: AtomicUsize::new(0),
}.into())
}
2016-07-30 17:53:12 -07:00
}
2016-08-20 22:59:14 -07:00
impl<E> Drop for ReadinessStream<E> {
2016-07-30 17:53:12 -07:00
fn drop(&mut self) {
2016-08-20 22:59:14 -07:00
self.handle.drop_source(&self.token)
2016-07-30 17:53:12 -07:00
}
}