hyperium / h2

HTTP 2.0 client & server implementation for Rust.
MIT License
1.38k stars 277 forks source link

Avoid spurious wakeups when stream capacity is not available #661

Closed vadim-eg closed 1 year ago

vadim-eg commented 1 year ago

Fixes #628

Sometimes poll_capacity returns Ready(Some(0)) - in which case caller will have no way to wait for the stream capacity to become available. The previous attempt on the fix has addressed only a part of the problem.

The root cause - in a nutshell - is the race condition between the application tasks that performs stream I/O and the task that serves the underlying HTTP/2 connection. The application thread that is about to send data calls reserve_capacity/poll_capacity, is provided with some send capacity and proceeds to send_data.

Meanwhile the service thread may send some buffered data and/or receive some window updates - either way the stream's effective allocated send capacity may not change, but, since the capacity still available, send_capacity_inc flag may be set.

The sending task calls send_data and uses the entire allocated capacity, leaving the flag set. Next time poll_capacity returns Ready(Some(0)).

This change sets the flag and dispatches the wakeup event only in cases when the effective capacity reported by poll_capacity actually increases.