Fix flow control bug (#177)

This patch fixes a bug that prevents sent data from being flushed to the
socket.

When data is sent, the task managing the connection must be notified. A
guard exists that prevents unnecessary notification of the connection
when the stream does not have any send capacity. However, this guard was
buggy. Instead of notifying the connection if *any* data can be sent, it
notified the connection only when *all* data could be sent.

This patch fixes the check as well as adds some tests that ensure the
connection task is notified.
This commit is contained in:
Carl Lerche
2017-11-29 12:54:23 -08:00
committed by GitHub
parent 35e0125e82
commit 5d54d8cd79
5 changed files with 191 additions and 3 deletions

View File

@@ -52,6 +52,7 @@ pub mod raw;
pub mod frames;
pub mod prelude;
pub mod mock;
pub mod notify;
pub mod util;
mod future_ext;

55
tests/support/notify.rs Normal file
View File

@@ -0,0 +1,55 @@
use futures::executor::{self, Notify};
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering::SeqCst;
pub struct MockNotify {
inner: Arc<Inner>,
}
struct Inner {
notified: AtomicBool,
}
impl MockNotify {
pub fn new() -> Self {
MockNotify {
inner: Arc::new(Inner {
notified: AtomicBool::new(false),
}),
}
}
pub fn with<F: FnOnce() -> R, R>(&self, f: F) -> R {
use futures::Async::Ready;
use futures::future::poll_fn;
self.clear();
let mut f = Some(f);
let res = executor::spawn(poll_fn(move || {
Ok::<_, ()>(Ready(f.take().unwrap()()))
})).poll_future_notify(&self.inner, 0);
match res {
Ok(Ready(v)) => v,
_ => unreachable!(),
}
}
pub fn clear(&self) {
self.inner.notified.store(false, SeqCst);
}
pub fn is_notified(&self) -> bool {
self.inner.notified.load(SeqCst)
}
}
impl Notify for Inner {
fn notify(&self, _: usize) {
self.notified.store(true, SeqCst);
}
}

View File

@@ -13,6 +13,9 @@ pub use super::mock::{self, HandleFutureExt};
// Re-export frames helpers
pub use super::frames;
// Re-export mock notify
pub use super::notify::MockNotify;
// Re-export utility mod
pub use super::util;