@@ -170,8 +170,14 @@ where
170170 // benchmarks often use. Perhaps it should be a config option instead.
171171 for _ in 0..16 {
172172 let _ = self.poll_read(cx)?;
173- let _ = self.poll_write(cx)?;
174- let _ = self.poll_flush(cx)?;
173+ let write_ready = self.poll_write(cx)?.is_ready();
174+ let flush_ready = self.poll_flush(cx)?.is_ready();
175+
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 wake-up 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() && (write_ready || flush_ready);
175181
176182 // This could happen if reading paused before blocking on IO,
177183 // such as getting to the end of a framed message, but then
@@ -181,14 +187,31 @@ where
181187 //
182188 // Using this instead of task::current() and notify() inside
183189 // the Conn is noticeably faster in pipelined benchmarks.
184- if !self.conn.wants_read_again() {
185- //break;
190+ let wants_read_again = self.conn.wants_read_again();
191+
192+ // If we cannot write or read again, we yield and rely on the
193+ // wake-up from the connection futures.
194+ if !(wants_write_again || wants_read_again) {
186195 return Poll::Ready(Ok(()));
187196 }
188- }
189197
198+ // If we are continuing only because "wants_write_again", check if write is ready.
199+ if !wants_read_again && wants_write_again {
200+ // If write was ready, just proceed with the loop
201+ if write_ready {
202+ continue;
203+ }
204+ // Write was previously pending, but may have become ready since polling flush, so
205+ // we need to check it again. If we simply proceeded, the case of an unbuffered
206+ // writer where flush is always ready would cause us to hot loop.
207+ if self.poll_write(cx)?.is_pending() {
208+ // write is pending, so it is safe to yield and rely on wake-up from connection
209+ // futures.
210+ return Poll::Ready(Ok(()));
211+ }
212+ }
213+ }
190214 trace!("poll_loop yielding (self = {:p})", self);
191-
192215 task::yield_now(cx).map(|never| match never {})
193216 }
194217
@@ -433,6 +456,11 @@ where
433456 self.conn.close_write();
434457 }
435458
459+ /// If there is pending data in body_rx, we can make progress writing if the connection is ready.
460+ fn can_write_again(&mut self) -> bool {
461+ self.body_rx.is_some()
462+ }
463+
436464 fn is_done(&self) -> bool {
437465 if self.is_closing {
438466 return true;
0 commit comments