Skip to content

Commit

Permalink
Split lock to prevent deadlock in Http2Stream. (#47769)
Browse files Browse the repository at this point in the history
Http2Connection.ChangeInitialWindowSize locks connection's SyncObject and calls Http2Stream.OnWindowUpdate which locks stream's SyncObject.
Http2Stream.Complete is called only while stream's SyncObject lock is take and then it calls Http2Connection.RemoveStream that locks connection SyncObject.
  • Loading branch information
ManickaP authored Feb 8, 2021
1 parent bde474e commit 0f055ba
Showing 1 changed file with 10 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 avoid lock ordering problems with Http2Connection.SyncObject

private StreamCompletionState _requestCompletionState;
private StreamCompletionState _responseCompletionState;
Expand Down Expand Up @@ -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;
}
}
}

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -1219,7 +1223,7 @@ private async ValueTask SendDataAsync(ReadOnlyMemory<byte> buffer, CancellationT
while (buffer.Length > 0)
{
int sendSize = -1;
lock (SyncObject)
lock (_creditSyncObject)
{
if (_availableCredit > 0)
{
Expand Down

0 comments on commit 0f055ba

Please sign in to comment.