Skip to content

Commit 4862c20

Browse files
committed
fix(http1): poll_loop writes when ready
1 parent 94e9993 commit 4862c20

File tree

1 file changed

+15
-2
lines changed

1 file changed

+15
-2
lines changed

src/proto/h1/dispatch.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,13 @@ where
171171
for _ in 0..16 {
172172
let _ = self.poll_read(cx)?;
173173
let _ = self.poll_write(cx)?;
174-
let _ = self.poll_flush(cx)?;
174+
let conn_ready = self.poll_flush(cx)?.is_ready();
175175

176+
// If we can write more body and the connection is ready, we should
177+
// write again. If we return `Ready(Ok(())` here, we will yield
178+
// without a guaranteed wakeup from the write side of the connection.
179+
// This would lead to a deadlock if we also don't expect reads.
180+
let wants_write_again = self.can_write_again() && conn_ready;
176181
// This could happen if reading paused before blocking on IO,
177182
// such as getting to the end of a framed message, but then
178183
// writing/flushing set the state back to Init. In that case,
@@ -181,7 +186,10 @@ where
181186
//
182187
// Using this instead of task::current() and notify() inside
183188
// the Conn is noticeably faster in pipelined benchmarks.
184-
if !self.conn.wants_read_again() {
189+
let wants_read_again = self.conn.wants_read_again();
190+
// If we cannot write or read again, we yield and rely on the
191+
// wakeup from the connection futures.
192+
if !(wants_write_again || wants_read_again) {
185193
//break;
186194
return Poll::Ready(Ok(()));
187195
}
@@ -433,6 +441,11 @@ where
433441
self.conn.close_write();
434442
}
435443

444+
/// If there is pending data in body_rx, we can make progress writing if the connection is ready.
445+
fn can_write_again(&mut self) -> bool {
446+
self.body_rx.is_some()
447+
}
448+
436449
fn is_done(&self) -> bool {
437450
if self.is_closing {
438451
return true;

0 commit comments

Comments
 (0)