-
Notifications
You must be signed in to change notification settings - Fork 560
Prevent the receive completion operation queued if unnecessary #4900
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
base: main
Are you sure you want to change the base?
Conversation
…te will be called inline.
@nibanks I modified this pr according to your suggestion. |
The more I think about this, the more I am wondering what the real problem is with the original behavior:
What is the downside of calling the queued completion with a zero length? |
Is the problem that the zero drain results in a paused receive path? |
Yes. I'm afraid that I forgot the detail, but recv path paused even though the data arrived. |
Thanks. Let me think on this problem a bit more to see what might be the simplest way forward. |
@guhetier can you please add this PR to your to-do list to help drive to completion? We need to get this fixed before the next release. |
Hi @masa-koz, are you still interested in working on this PR? After looking at the problem again, I think we can avoid the lock by storing both
I think this should work. There is still a possibility of a race in "Multiple Receive" mode, but in that mode, a receive completion work item with 0 bytes completed is not a problem, we don't stop indicating receives. This is similar to what Nick suggested in a comment, but slightly simpler. |
I'm still interested. But I have no time now. Could you mind waiting for a few days? |
It can wait a few days, we want to make sure we have this done for the next release (which doesn't have a specific date yet). Thanks for your contributions! |
There are also merge conflicts preventing the CI from being run. |
Co-authored-by: Guillaume Hetier <hetier.guillaume@gmail.com>
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4900 +/- ##
==========================================
+ Coverage 86.28% 86.95% +0.67%
==========================================
Files 59 59
Lines 18011 18013 +2
==========================================
+ Hits 15541 15664 +123
+ Misses 2470 2349 -121 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's a slight redesign that makes it cleaner and more efficient (I think).
@nibanks |
Could you replace merge/rebase main to get a few recent CI fixes? Then I think we'll be good to go. Thanks so much for working with us on this PR! |
(int64_t)BufferLength); | ||
if ((BufferLength & QUIC_STREAM_RECV_COMPLETION_LENGTH_CANARY_BIT) != 0 && | ||
(RecvCompletionLength & QUIC_STREAM_RECV_COMPLETION_LENGTH_CANARY_BIT) != 0) { | ||
QuicTraceEvent( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not convinced this is a good way to handle the error...
If we simply goto Exit
with a log, we silently break our contract with the app: the completed some bytes but we won't restart receive indications (or in multi-receive mode, they are now out of sync).
IMO, this should be a fatal error for the connection.
@nibanks, opinions?
(I thought I commented on this earlier but can't find it anymore...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For one, you have to be careful about aborting the connection on the app thread here. I think we may do something special above in one of the other functions. But you're probably right that we should abort the connection if this happens.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See this code in StreamSend above:
//
// We can't fail the send at this point, because we're already queued
// the send above. So instead, we're just going to abort the whole
// connection.
//
if (InterlockedCompareExchange16(
(short*)&Connection->BackUpOperUsed, 1, 0) != 0) {
goto Exit; // It's already started the shutdown.
}
Oper = &Connection->BackUpOper;
Oper->FreeAfterProcess = FALSE;
Oper->Type = QUIC_OPER_TYPE_API_CALL;
Oper->API_CALL.Context = &Connection->BackupApiContext;
Oper->API_CALL.Context->Type = QUIC_API_TYPE_CONN_SHUTDOWN;
Oper->API_CALL.Context->CONN_SHUTDOWN.Flags = QUIC_CONNECTION_SHUTDOWN_FLAG_SILENT;
Oper->API_CALL.Context->CONN_SHUTDOWN.ErrorCode = (QUIC_VAR_INT)QUIC_STATUS_OUT_OF_MEMORY;
Oper->API_CALL.Context->CONN_SHUTDOWN.RegistrationShutdown = FALSE;
Oper->API_CALL.Context->CONN_SHUTDOWN.TransportShutdown = TRUE;
QuicConnQueueHighestPriorityOper(Connection, Oper);
Description
If the receive complete API is called on a user thread before
QUIC_STREAM_EVENT_RECEIVE
finished, MsQuic will callQuicStreamReceiveComplete
immediately even though a completion operation is queued. And a completion operation will trigerQuicStreamReceiveComplete
even thoughRecvCompletionLength
is zero.So, this pull request introduces a new flag to track if the receive complete API was called inline and updates related logic in the
MsQuic
library. The most important changes include adding the new flagRecvCompletionInlineCalled
, modifying the condition checks, and updating comments to reflect the new logic.Testing
NA
Documentation
NA