diff --git a/src/core/api.c b/src/core/api.c index 7cf0b70b35..24b7e33571 100644 --- a/src/core/api.c +++ b/src/core/api.c @@ -1007,6 +1007,7 @@ MsQuicStreamSend( uint64_t TotalLength; QUIC_SEND_REQUEST* SendRequest; BOOLEAN QueueOper = TRUE; + BOOLEAN SendInline; QUIC_OPERATION* Oper; QuicTraceEvent( @@ -1081,6 +1082,10 @@ MsQuicStreamSend( SendRequest->TotalLength = TotalLength; SendRequest->ClientContext = ClientSendContext; + SendInline = + !Connection->Settings.SendBufferingEnabled && + Connection->WorkerThreadID == CxPlatCurThreadID(); + CxPlatDispatchLockAcquire(&Stream->ApiSendRequestLock); if (!Stream->Flags.SendEnabled) { Status = @@ -1095,6 +1100,15 @@ MsQuicStreamSend( } *ApiSendRequestsTail = SendRequest; Status = QUIC_STATUS_SUCCESS; + + if (!SendInline && QueueOper) { + // + // Async stream operations need to hold a ref on the stream so that + // the stream isn't freed before the operation can be processed. The + // ref is released after the operation is processed. + // + QuicStreamAddRef(Stream, QUIC_STREAM_REF_OPERATION); + } } CxPlatDispatchLockRelease(&Stream->ApiSendRequestLock); @@ -1103,8 +1117,7 @@ MsQuicStreamSend( goto Exit; } - if (!Connection->Settings.SendBufferingEnabled && - Connection->WorkerThreadID == CxPlatCurThreadID()) { + if (SendInline) { CXPLAT_PASSIVE_CODE(); @@ -1125,6 +1138,15 @@ MsQuicStreamSend( "Allocation of '%s' failed. (%llu bytes)", "STRM_SEND operation", 0); + + Status = QUIC_STATUS_OUT_OF_MEMORY; + + // + // We failed to alloc the operation we needed to queue, so make sure + // to release the ref we took above. + // + QuicStreamRelease(Stream, QUIC_STREAM_REF_OPERATION); + // // 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 @@ -1146,16 +1168,10 @@ MsQuicStreamSend( QuicConnQueueOper(Connection, Oper); goto Exit; } + Oper->API_CALL.Context->Type = QUIC_API_TYPE_STRM_SEND; Oper->API_CALL.Context->STRM_SEND.Stream = Stream; - // - // Async stream operations need to hold a ref on the stream so that the - // stream isn't freed before the operation can be processed. The ref is - // released after the operation is processed. - // - QuicStreamAddRef(Stream, QUIC_STREAM_REF_OPERATION); - // // Queue the operation but don't wait for the completion. //