Skip to content

Commit d659dab

Browse files
authored
Remove allocation of state machine in QuicStream.WriteAsync (#103902)
* Remove unnecessary state machine allocation * Optimize hot path on QuicStream.ReadAsync * Revert "Optimize hot path on QuicStream.ReadAsync" This reverts commit 4b8db0e. * No explicit throwing * ExceptionDispatchInfo.SetCurrentStackTrace
1 parent 2fab73c commit d659dab

File tree

1 file changed

+13
-11
lines changed

1 file changed

+13
-11
lines changed

src/libraries/System.Net.Quic/src/System/Net/Quic/QuicStream.cs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Diagnostics;
55
using System.IO;
66
using System.Runtime.CompilerServices;
7+
using System.Runtime.ExceptionServices;
78
using System.Runtime.InteropServices;
89
using System.Threading;
910
using System.Threading.Tasks;
@@ -359,38 +360,40 @@ public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationTo
359360
/// <param name="buffer">The region of memory to write data from.</param>
360361
/// <param name="cancellationToken">The token to monitor for cancellation requests. The default value is <see cref="CancellationToken.None"/>.</param>
361362
/// <param name="completeWrites">Notifies the peer about gracefully closing the write side, i.e.: sends FIN flag with the data.</param>
362-
public async ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, bool completeWrites, CancellationToken cancellationToken = default)
363+
public ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, bool completeWrites, CancellationToken cancellationToken = default)
363364
{
364-
ObjectDisposedException.ThrowIf(_disposed == 1, this);
365+
if (_disposed == 1)
366+
{
367+
return ValueTask.FromException(ExceptionDispatchInfo.SetCurrentStackTrace(new ObjectDisposedException(nameof(QuicStream))));
368+
}
365369

366370
if (!_canWrite)
367371
{
368-
throw new InvalidOperationException(SR.net_quic_writing_notallowed);
372+
return ValueTask.FromException(ExceptionDispatchInfo.SetCurrentStackTrace(new InvalidOperationException(SR.net_quic_writing_notallowed)));
369373
}
370374

371375
if (NetEventSource.Log.IsEnabled())
372376
{
373377
NetEventSource.Info(this, $"{this} Stream writing memory of '{buffer.Length}' bytes while {(completeWrites ? "completing" : "not completing")} writes.");
374378
}
375379

376-
if (_sendTcs.IsCompleted)
380+
if (_sendTcs.IsCompleted && cancellationToken.IsCancellationRequested)
377381
{
378382
// Special case exception type for pre-canceled token while we've already transitioned to a final state and don't need to abort write.
379383
// It must happen before we try to get the value task, since the task source is versioned and each instance must be awaited.
380-
cancellationToken.ThrowIfCancellationRequested();
384+
return ValueTask.FromCanceled(cancellationToken);
381385
}
382386

383387
// Concurrent call, this one lost the race.
384388
if (!_sendTcs.TryGetValueTask(out ValueTask valueTask, this, cancellationToken))
385389
{
386-
throw new InvalidOperationException(SR.Format(SR.net_io_invalidnestedcall, "write"));
390+
return ValueTask.FromException(ExceptionDispatchInfo.SetCurrentStackTrace(new InvalidOperationException(SR.Format(SR.net_io_invalidnestedcall, "write"))));
387391
}
388392

389393
// No need to call anything since we already have a result, most likely an exception.
390394
if (valueTask.IsCompleted)
391395
{
392-
await valueTask.ConfigureAwait(false);
393-
return;
396+
return valueTask;
394397
}
395398

396399
// For an empty buffer complete immediately, close the writing side of the stream if necessary.
@@ -401,8 +404,7 @@ public async ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, bool completeWrit
401404
{
402405
CompleteWrites();
403406
}
404-
await valueTask.ConfigureAwait(false);
405-
return;
407+
return valueTask;
406408
}
407409

408410
// We own the lock, abort might happen, but exception will get stored instead.
@@ -438,7 +440,7 @@ public async ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, bool completeWrit
438440
}
439441
}
440442

441-
await valueTask.ConfigureAwait(false);
443+
return valueTask;
442444
}
443445

444446
/// <summary>

0 commit comments

Comments
 (0)