157: More robust file implementation r=stjepang a=stjepang

This is a reimplementation of the `File`s state machine.

The previous implementation was simple and a bit naive. It was not fundamentally wrong but had surprises in some corner cases. For example, if an async read operation was started but we timed out on it, the file cursor would move even though we didn't complete the operation. The new implementation will move the cursor only when read/write operations complete successfully.

There was also a deadlock hazard in the case where multiple tasks were concurrently reading or writing to the same file, in which case some task wakeups would be lost. This PR fixes the problem.

A nice consequence of this PR: `futures-channel` is now unused, so we can remove it from the dependency list.

Co-authored-by: Stjepan Glavina <stjepang@gmail.com>
staging
bors[bot] 5 years ago committed by GitHub
commit a8a2ae9e29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -27,10 +27,9 @@ unstable = []
async-task = "1.0.0"
cfg-if = "0.1.9"
crossbeam-channel = "0.3.9"
futures-channel-preview = "0.3.0-alpha.18"
futures-core-preview = "0.3.0-alpha.18"
futures-io-preview = "0.3.0-alpha.18"
futures-timer = "0.3.0"
futures-timer = "0.4.0"
lazy_static = "1.3.0"
log = { version = "0.4.8", features = ["kv_unstable"] }
memchr = "2.2.1"

@ -7,7 +7,7 @@ use async_std::io;
use async_std::prelude::*;
use async_std::task;
const LEN: usize = 4 * 1024 * 1024; // 4 Mb
const LEN: usize = 16 * 1024; // 16 Kb
fn main() -> io::Result<()> {
let path = args().nth(1).expect("missing path argument");

File diff suppressed because it is too large Load Diff

@ -213,7 +213,11 @@ impl<T: Evented> IoHandle<T> {
let mut readiness = mio::Ready::from_usize(self.entry.readiness.load(Ordering::SeqCst));
if (readiness & mask).is_empty() {
self.entry.readers.lock().unwrap().push(cx.waker().clone());
let mut list = self.entry.readers.lock().unwrap();
if list.iter().all(|w| !w.will_wake(cx.waker())) {
list.push(cx.waker().clone());
}
readiness = mio::Ready::from_usize(self.entry.readiness.fetch_or(0, Ordering::SeqCst));
}
@ -250,7 +254,11 @@ impl<T: Evented> IoHandle<T> {
let mut readiness = mio::Ready::from_usize(self.entry.readiness.load(Ordering::SeqCst));
if (readiness & mask).is_empty() {
self.entry.writers.lock().unwrap().push(cx.waker().clone());
let mut list = self.entry.writers.lock().unwrap();
if list.iter().all(|w| !w.will_wake(cx.waker())) {
list.push(cx.waker().clone());
}
readiness = mio::Ready::from_usize(self.entry.readiness.fetch_or(0, Ordering::SeqCst));
}

Loading…
Cancel
Save