mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-08-25 00:00:18 +02:00
Poll evented mutability (#37)
Generally speaking, it is unsafe to access to perform asynchronous operations using `&self`. Taking `&self` allows usage from a `Sync` context, which has unexpected results. Taking `&mut self` to perform these operations prevents using these asynchronous values from across tasks (unless they are wrapped in `RefCell` or `Mutex`.
This commit is contained in:
+25
-68
@@ -8,7 +8,7 @@
|
||||
|
||||
use std::fmt;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use futures::{Async, Poll};
|
||||
use mio::event::Evented;
|
||||
@@ -63,9 +63,9 @@ use reactor::{Handle, Direction};
|
||||
/// method you want to also use `need_read` to signal blocking and you should
|
||||
/// otherwise probably avoid using two tasks on the same `PollEvented`.
|
||||
pub struct PollEvented<E> {
|
||||
handle: Handle,
|
||||
token: usize,
|
||||
readiness: AtomicUsize,
|
||||
handle: Handle,
|
||||
readiness: usize,
|
||||
io: E,
|
||||
}
|
||||
|
||||
@@ -92,8 +92,8 @@ impl<E> PollEvented<E> {
|
||||
|
||||
Ok(PollEvented {
|
||||
token,
|
||||
readiness: 0,
|
||||
handle: handle.clone(),
|
||||
readiness: AtomicUsize::new(0),
|
||||
io: io,
|
||||
})
|
||||
}
|
||||
@@ -112,7 +112,7 @@ impl<E> PollEvented<E> {
|
||||
///
|
||||
/// This function will panic if called outside the context of a future's
|
||||
/// task.
|
||||
pub fn poll_read(&self) -> Async<()> {
|
||||
pub fn poll_read(&mut self) -> Async<()> {
|
||||
self.poll_ready(super::read_ready())
|
||||
.map(|_| ())
|
||||
}
|
||||
@@ -131,7 +131,7 @@ impl<E> PollEvented<E> {
|
||||
///
|
||||
/// This function will panic if called outside the context of a future's
|
||||
/// task.
|
||||
pub fn poll_write(&self) -> Async<()> {
|
||||
pub fn poll_write(&mut self) -> Async<()> {
|
||||
self.poll_ready(Ready::writable())
|
||||
.map(|_| ())
|
||||
}
|
||||
@@ -159,9 +159,10 @@ impl<E> PollEvented<E> {
|
||||
///
|
||||
/// This function will panic if called outside the context of a future's
|
||||
/// task.
|
||||
pub fn poll_ready(&self, mask: Ready) -> Async<Ready> {
|
||||
pub fn poll_ready(&mut self, mask: Ready) -> Async<Ready> {
|
||||
let bits = super::ready2usize(mask);
|
||||
match self.readiness.load(Ordering::SeqCst) & bits {
|
||||
|
||||
match self.readiness & bits {
|
||||
0 => {}
|
||||
n => return Async::Ready(super::usize2ready(n)),
|
||||
}
|
||||
@@ -171,8 +172,9 @@ impl<E> PollEvented<E> {
|
||||
io_dispatch[self.token].readiness.swap(0, Ordering::SeqCst)
|
||||
}).unwrap_or(0);
|
||||
|
||||
self.readiness.fetch_or(token_readiness, Ordering::SeqCst);
|
||||
match self.readiness.load(Ordering::SeqCst) & bits {
|
||||
self.readiness |= token_readiness;
|
||||
|
||||
match self.readiness & bits {
|
||||
0 => {
|
||||
if mask.is_writable() {
|
||||
if self.need_write().is_err() {
|
||||
@@ -220,9 +222,9 @@ impl<E> PollEvented<E> {
|
||||
///
|
||||
/// This function will panic if called outside the context of a future's
|
||||
/// task.
|
||||
pub fn need_read(&self) -> io::Result<()> {
|
||||
pub fn need_read(&mut self) -> io::Result<()> {
|
||||
let bits = super::ready2usize(super::read_ready());
|
||||
self.readiness.fetch_and(!bits, Ordering::SeqCst);
|
||||
self.readiness &= !bits;
|
||||
|
||||
let inner = match self.handle.inner() {
|
||||
Some(inner) => inner,
|
||||
@@ -260,9 +262,9 @@ impl<E> PollEvented<E> {
|
||||
///
|
||||
/// This function will panic if called outside the context of a future's
|
||||
/// task.
|
||||
pub fn need_write(&self) -> io::Result<()> {
|
||||
pub fn need_write(&mut self) -> io::Result<()> {
|
||||
let bits = super::ready2usize(Ready::writable());
|
||||
self.readiness.fetch_and(!bits, Ordering::SeqCst);
|
||||
self.readiness &= !bits;
|
||||
|
||||
let inner = match self.handle.inner() {
|
||||
Some(inner) => inner,
|
||||
@@ -319,10 +321,13 @@ impl<E: Read> Read for PollEvented<E> {
|
||||
if let Async::NotReady = self.poll_read() {
|
||||
return Err(io::ErrorKind::WouldBlock.into())
|
||||
}
|
||||
|
||||
let r = self.get_mut().read(buf);
|
||||
|
||||
if is_wouldblock(&r) {
|
||||
self.need_read()?;
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
}
|
||||
@@ -332,10 +337,13 @@ impl<E: Write> Write for PollEvented<E> {
|
||||
if let Async::NotReady = self.poll_write() {
|
||||
return Err(io::ErrorKind::WouldBlock.into())
|
||||
}
|
||||
|
||||
let r = self.get_mut().write(buf);
|
||||
|
||||
if is_wouldblock(&r) {
|
||||
self.need_write()?;
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
@@ -343,10 +351,13 @@ impl<E: Write> Write for PollEvented<E> {
|
||||
if let Async::NotReady = self.poll_write() {
|
||||
return Err(io::ErrorKind::WouldBlock.into())
|
||||
}
|
||||
|
||||
let r = self.get_mut().flush();
|
||||
|
||||
if is_wouldblock(&r) {
|
||||
self.need_write()?;
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
}
|
||||
@@ -360,60 +371,6 @@ impl<E: Write> AsyncWrite for PollEvented<E> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E> Read for &'a PollEvented<E>
|
||||
where &'a E: Read,
|
||||
{
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
if let Async::NotReady = self.poll_read() {
|
||||
return Err(io::ErrorKind::WouldBlock.into())
|
||||
}
|
||||
let r = self.get_ref().read(buf);
|
||||
if is_wouldblock(&r) {
|
||||
self.need_read()?;
|
||||
}
|
||||
return r
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E> Write for &'a PollEvented<E>
|
||||
where &'a E: Write,
|
||||
{
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
if let Async::NotReady = self.poll_write() {
|
||||
return Err(io::ErrorKind::WouldBlock.into())
|
||||
}
|
||||
let r = self.get_ref().write(buf);
|
||||
if is_wouldblock(&r) {
|
||||
self.need_write()?;
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
if let Async::NotReady = self.poll_write() {
|
||||
return Err(io::ErrorKind::WouldBlock.into())
|
||||
}
|
||||
let r = self.get_ref().flush();
|
||||
if is_wouldblock(&r) {
|
||||
self.need_write()?;
|
||||
}
|
||||
return r
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E> AsyncRead for &'a PollEvented<E>
|
||||
where &'a E: Read,
|
||||
{
|
||||
}
|
||||
|
||||
impl<'a, E> AsyncWrite for &'a PollEvented<E>
|
||||
where &'a E: Write,
|
||||
{
|
||||
fn shutdown(&mut self) -> Poll<(), io::Error> {
|
||||
Ok(().into())
|
||||
}
|
||||
}
|
||||
|
||||
fn is_wouldblock<T>(r: &io::Result<T>) -> bool {
|
||||
match *r {
|
||||
Ok(_) => false,
|
||||
|
||||
Reference in New Issue
Block a user