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

fix: fix stream only write will stuck forever #398

Merged
merged 1 commit into from
Feb 28, 2025
Merged

Conversation

driftluo
Copy link
Collaborator

@driftluo driftluo requested a review from eval-exec as a code owner February 28, 2025 13:54
@driftluo driftluo force-pushed the fix-only-write-stuck branch from 59ed6e5 to b80f064 Compare February 28, 2025 14:32
@driftluo driftluo force-pushed the fix-only-write-stuck branch from b80f064 to cc2e5ca Compare February 28, 2025 14:40
@mcrakhman
Copy link

mcrakhman commented Feb 28, 2025

I have a quick question, how will this fix work if the window update is sent a bit later? I mean after we checked recv_frames and then stuck on waiting when n == 0

To clarify it seems it can happen that the frame_receiver channel is empty at that time

@driftluo
Copy link
Collaborator Author

driftluo commented Feb 28, 2025

I have a quick question, how will this fix work if the window update is sent a bit later? I mean after we checked recv_frames and then stuck on waiting when n == 0
To clarify it seems it can happen that the frame_receiver channel is empty at that time

if checked recv_frames and then stuck on waiting when n == 0:

writeable waker is registered on the frame_receiver(the poll_next fn https://github.com/rust-lang/futures-rs/blob/master/futures-channel/src/mpsc/mod.rs#L1079-L1085), when session receives the window update frame, it will wake frame_receiver to poll, and it will wake the writer part.

If an unexpected read operation occurs first, the writeable waker is also registered on stream when n ==0, the read part will also wake up the write part to continue.

@mcrakhman
Copy link

mcrakhman commented Feb 28, 2025

I have a quick question, how will this fix work if the window update is sent a bit later? I mean after we checked recv_frames and then stuck on waiting when n == 0
To clarify it seems it can happen that the frame_receiver channel is empty at that time

if checked recv_frames and then stuck on waiting when n == 0:

writeable waker is registered on the frame_receiver(the poll_next fn https://github.com/rust-lang/futures-rs/blob/master/futures-channel/src/mpsc/mod.rs#L1079-L1085), when session receives the window update frame, it will wake frame_receiver to poll, and it will wake the writer part.

Can you then clarify why it didn't work before? Thanks!

To clarify it can happen that we receive the update window on recv_frames before n == 0, and everything will work fine. But if we miss that, nobody will read (if we are only writing), and read part will only occur if somebody polls reader which is not the case in my situation.

@driftluo
Copy link
Collaborator Author

driftluo commented Feb 28, 2025

Can you then clarify why it didn't work before? Thanks!

To clarify it can happen that we receive the update window on recv_frames before n == 0, and everything will work fine. But if we miss that, nobody will read (if we are only writing), and read part will only occur if somebody polls reader which is not the case in my situation.

Under the previous logic, if only a write operation is performed, stream cannot read any messages sent from the remote end, including window updates.

The session does send a message, but its wake response is only in the read operation, and the window update message is never received by the stream(just in the channel, never pop to the stream), causing the send window to always be 0.

If you add debug information to the test case, you will find that the stream has been woken up multiple times.(master branch will stuck, this PR will fine)

@mcrakhman
Copy link

Can you then clarify why it didn't work before? Thanks!

To clarify it can happen that we receive the update window on recv_frames before n == 0, and everything will work fine. But if we miss that, nobody will read (if we are only writing), and read part will only occur if somebody polls reader which is not the case in my situation.

Under the previous logic, if only a write operation is performed, we cannot read any messages sent from the remote end, including window updates.

The session does send a message, but its wake response is only in the read operation, and the window update message is never received by the stream, causing the send window to always be 0.

If you add debug information to the test case, you will find that the stream has been woken up multiple times.

Super, I actually read the code and now it makes sense :-) Indeed we take the waker from the context of the write operation and register it with frame_reciever if there are no messages, then we park the future on n == 0, then the future will be polled again as soon as frame_receiver receives the message, and we will go to recv_frames again (this is basically what you wrote, but it took a while to understand lol). Thanks again!

@driftluo
Copy link
Collaborator Author

@mcrakhman You're welcome. I'll merge this PR shortly and publish the release.

@driftluo driftluo merged commit ba84ea9 into master Feb 28, 2025
7 checks passed
@driftluo driftluo deleted the fix-only-write-stuck branch February 28, 2025 15:45
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.

Problems with handling update window in tokio_yamux crate
4 participants