Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid spurious wakeups when stream capacity is not available #661

Merged
merged 2 commits into from Feb 20, 2023

Conversation

vadim-eg
Copy link
Contributor

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.

@vadim-eg vadim-eg changed the title Avoid spurious workups when stream capacity is not available Avoid spurious wakeups when stream capacity is not available Feb 17, 2023
Fixes hyperium#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.
Copy link
Member

@seanmonstar seanmonstar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent work, thank you!

@seanmonstar seanmonstar merged commit 7323190 into hyperium:master Feb 20, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

poll_capacity spuriously returns Ready(Some(0))
2 participants