@@ -541,12 +541,12 @@ private unsafe int HandleEventShutdownInitiatedByTransport(ref SHUTDOWN_INITIATE
541
541
{
542
542
Exception exception = ExceptionDispatchInfo . SetCurrentStackTrace ( ThrowHelper . GetExceptionForMsQuicStatus ( data . Status , ( long ) data . ErrorCode ) ) ;
543
543
_connectedTcs . TrySetException ( exception ) ;
544
- CompleteAndDrainAcceptQueue ( exception ) ;
544
+ CompleteAcceptQueue ( exception , false ) ;
545
545
return QUIC_STATUS_SUCCESS ;
546
546
}
547
547
private unsafe int HandleEventShutdownInitiatedByPeer ( ref SHUTDOWN_INITIATED_BY_PEER_DATA data )
548
548
{
549
- CompleteAndDrainAcceptQueue ( ExceptionDispatchInfo . SetCurrentStackTrace ( ThrowHelper . GetConnectionAbortedException ( ( long ) data . ErrorCode ) ) ) ;
549
+ CompleteAcceptQueue ( ExceptionDispatchInfo . SetCurrentStackTrace ( ThrowHelper . GetConnectionAbortedException ( ( long ) data . ErrorCode ) ) , false ) ;
550
550
return QUIC_STATUS_SUCCESS ;
551
551
}
552
552
private unsafe int HandleEventShutdownComplete ( )
@@ -555,7 +555,7 @@ private unsafe int HandleEventShutdownComplete()
555
555
_tlsSecret ? . WriteSecret ( ) ;
556
556
557
557
Exception exception = ExceptionDispatchInfo . SetCurrentStackTrace ( _disposed == 1 ? new ObjectDisposedException ( GetType ( ) . FullName ) : ThrowHelper . GetOperationAbortedException ( ) ) ;
558
- CompleteAndDrainAcceptQueue ( exception ) ;
558
+ CompleteAcceptQueue ( exception , true ) ;
559
559
_connectedTcs . TrySetException ( exception ) ;
560
560
_shutdownTokenSource . Cancel ( ) ;
561
561
_shutdownTcs . TrySetResult ( final : true ) ;
@@ -666,22 +666,26 @@ private static unsafe int NativeCallback(QUIC_HANDLE* connection, void* context,
666
666
}
667
667
}
668
668
669
- private void CompleteAndDrainAcceptQueue ( Exception ? ex )
669
+ private void CompleteAcceptQueue ( Exception ? ex , bool drain )
670
670
{
671
- if ( _acceptQueue . Writer . TryComplete ( ex ) )
671
+ _acceptQueue . Writer . TryComplete ( ex ) ;
672
+
673
+ if ( drain )
672
674
{
673
- // also drain the queue. Because stream shutdown events are indicated before connection shutdown,
674
- // the QuicStream instances have already been signaled and closed internally. We only need to dispose them,
675
- // which in this situation should complete synchronously.
675
+ // This should be only called after connection SHUTDOWN_COMPLETE has been indicated.
676
+ // At that point, all streams have been already shut down internally and we need
677
+ // only to close the handle via dispose, so DisposeAsync below should complete
678
+ // synchronously (which is necessary for this method to be callable from MsQuic
679
+ // event callback).
676
680
while ( _acceptQueue . Reader . TryRead ( out QuicStream ? stream ) )
677
681
{
678
682
ValueTask task = stream . DisposeAsync ( ) ;
679
683
Debug . Assert ( task . IsCompletedSuccessfully ) ;
680
684
task . GetAwaiter ( ) . GetResult ( ) ;
681
685
}
682
- }
683
686
684
- Debug . Assert ( _acceptQueue . Reader . Completion . IsCompleted ) ;
687
+ Debug . Assert ( _acceptQueue . Reader . Completion . IsCompleted ) ;
688
+ }
685
689
}
686
690
687
691
/// <summary>
@@ -737,6 +741,6 @@ public async ValueTask DisposeAsync()
737
741
}
738
742
739
743
// Flush the queue and dispose all remaining streams.
740
- CompleteAndDrainAcceptQueue ( ExceptionDispatchInfo . SetCurrentStackTrace ( new ObjectDisposedException ( GetType ( ) . FullName ) ) ) ;
744
+ CompleteAcceptQueue ( ExceptionDispatchInfo . SetCurrentStackTrace ( new ObjectDisposedException ( GetType ( ) . FullName ) ) , true ) ;
741
745
}
742
746
}
0 commit comments