diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs index c1ef8c1b3385b..e36b56b13da7e 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs @@ -39,6 +39,7 @@ private sealed class Http2Stream : IValueTaskSource, IHttpHeadersHandler, IHttpT private int _pendingWindowUpdate; private CreditWaiter? _creditWaiter; private int _availableCredit; + private readonly object _creditSyncObject = new object(); // split from SyncObject to mitigate deadlock in OnWindowUpdate. private StreamCompletionState _requestCompletionState; private StreamCompletionState _responseCompletionState; @@ -349,11 +350,14 @@ private void Complete() _connection.RemoveStream(this); - CreditWaiter? w = _creditWaiter; - if (w != null) + lock (_creditSyncObject) { - w.Dispose(); - _creditWaiter = null; + CreditWaiter? waiter = _creditWaiter; + if (waiter != null) + { + waiter.Dispose(); + _creditWaiter = null; + } } } @@ -421,7 +425,7 @@ private void Cancel() public void OnWindowUpdate(int amount) { - lock (SyncObject) + lock (_creditSyncObject) { _availableCredit = checked(_availableCredit + amount); if (_availableCredit > 0 && _creditWaiter != null) @@ -1219,7 +1223,7 @@ private async ValueTask SendDataAsync(ReadOnlyMemory buffer, CancellationT while (buffer.Length > 0) { int sendSize = -1; - lock (SyncObject) + lock (_creditSyncObject) { if (_availableCredit > 0) {