Slimmer locks
This commit is contained in:
parent
09fda749b0
commit
310411075f
|
|
@ -383,7 +383,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Abort(Exception error = null)
|
public void Abort(Exception error = null)
|
||||||
{
|
{
|
||||||
if (Interlocked.CompareExchange(ref _requestAborted, 1, 0) == 0)
|
if (Interlocked.Exchange(ref _requestAborted, 1) == 0)
|
||||||
{
|
{
|
||||||
_requestProcessingStopping = true;
|
_requestProcessingStopping = true;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
|
|
||||||
public void IncomingComplete(int count, Exception error)
|
public void IncomingComplete(int count, Exception error)
|
||||||
{
|
{
|
||||||
|
Action awaitableState;
|
||||||
|
|
||||||
lock (_sync)
|
lock (_sync)
|
||||||
{
|
{
|
||||||
// Must call Add() before bytes are available to consumer, to ensure that Length is >= 0
|
// Must call Add() before bytes are available to consumer, to ensure that Length is >= 0
|
||||||
|
|
@ -107,8 +109,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
FinReceived();
|
FinReceived();
|
||||||
}
|
}
|
||||||
|
|
||||||
Complete();
|
awaitableState = Interlocked.Exchange(ref _awaitableState, _awaitableIsCompleted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Complete(awaitableState);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void IncomingDeferred()
|
public void IncomingDeferred()
|
||||||
|
|
@ -129,12 +133,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Complete()
|
private void Complete(Action awaitableState)
|
||||||
{
|
{
|
||||||
var awaitableState = Interlocked.Exchange(
|
|
||||||
ref _awaitableState,
|
|
||||||
_awaitableIsCompleted);
|
|
||||||
|
|
||||||
_manualResetEvent.Set();
|
_manualResetEvent.Set();
|
||||||
|
|
||||||
if (!ReferenceEquals(awaitableState, _awaitableIsCompleted) &&
|
if (!ReferenceEquals(awaitableState, _awaitableIsCompleted) &&
|
||||||
|
|
@ -146,21 +146,29 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
|
|
||||||
public MemoryPoolIterator ConsumingStart()
|
public MemoryPoolIterator ConsumingStart()
|
||||||
{
|
{
|
||||||
|
MemoryPoolBlock head;
|
||||||
|
bool isAlreadyConsuming;
|
||||||
|
|
||||||
lock (_sync)
|
lock (_sync)
|
||||||
{
|
{
|
||||||
if (_consuming)
|
isAlreadyConsuming = _consuming;
|
||||||
{
|
head = _head;
|
||||||
throw new InvalidOperationException("Already consuming input.");
|
|
||||||
}
|
|
||||||
_consuming = true;
|
_consuming = true;
|
||||||
return new MemoryPoolIterator(_head);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isAlreadyConsuming)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Already consuming input.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MemoryPoolIterator(head);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ConsumingComplete(
|
public void ConsumingComplete(
|
||||||
MemoryPoolIterator consumed,
|
MemoryPoolIterator consumed,
|
||||||
MemoryPoolIterator examined)
|
MemoryPoolIterator examined)
|
||||||
{
|
{
|
||||||
|
bool isConsuming;
|
||||||
MemoryPoolBlock returnStart = null;
|
MemoryPoolBlock returnStart = null;
|
||||||
MemoryPoolBlock returnEnd = null;
|
MemoryPoolBlock returnEnd = null;
|
||||||
|
|
||||||
|
|
@ -184,7 +192,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
{
|
{
|
||||||
// Everything has been consumed and no data is being written to the
|
// Everything has been consumed and no data is being written to the
|
||||||
// _tail block, so return all blocks between _head and _tail inclusive.
|
// _tail block, so return all blocks between _head and _tail inclusive.
|
||||||
returnEnd = null;
|
|
||||||
_head = null;
|
_head = null;
|
||||||
_tail = null;
|
_tail = null;
|
||||||
}
|
}
|
||||||
|
|
@ -214,31 +221,34 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Dispose won't have returned the blocks if we were consuming, so return them now
|
||||||
returnStart = _head;
|
returnStart = _head;
|
||||||
returnEnd = null;
|
|
||||||
_head = null;
|
_head = null;
|
||||||
_tail = null;
|
_tail = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnBlocks(returnStart, returnEnd);
|
isConsuming = _consuming;
|
||||||
|
|
||||||
if (!_consuming)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("No ongoing consuming operation to complete.");
|
|
||||||
}
|
|
||||||
_consuming = false;
|
_consuming = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReturnBlocks(returnStart, returnEnd);
|
||||||
|
|
||||||
|
if (!isConsuming)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("No ongoing consuming operation to complete.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CompleteAwaiting()
|
public void CompleteAwaiting()
|
||||||
{
|
{
|
||||||
Complete();
|
Complete(Interlocked.Exchange(ref _awaitableState, _awaitableIsCompleted));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AbortAwaiting()
|
public void AbortAwaiting()
|
||||||
{
|
{
|
||||||
SetConnectionError(new TaskCanceledException("The request was aborted"));
|
SetConnectionError(new TaskCanceledException("The request was aborted"));
|
||||||
Complete();
|
|
||||||
|
CompleteAwaiting();
|
||||||
}
|
}
|
||||||
|
|
||||||
public SocketInput GetAwaiter()
|
public SocketInput GetAwaiter()
|
||||||
|
|
@ -253,15 +263,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
continuation,
|
continuation,
|
||||||
_awaitableIsNotCompleted);
|
_awaitableIsNotCompleted);
|
||||||
|
|
||||||
if (ReferenceEquals(awaitableState, _awaitableIsNotCompleted))
|
if (ReferenceEquals(awaitableState, _awaitableIsCompleted))
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (ReferenceEquals(awaitableState, _awaitableIsCompleted))
|
|
||||||
{
|
{
|
||||||
_threadPool.Run(continuation);
|
_threadPool.Run(continuation);
|
||||||
}
|
}
|
||||||
else
|
else if (!ReferenceEquals(awaitableState, _awaitableIsNotCompleted))
|
||||||
{
|
{
|
||||||
SetConnectionError(new InvalidOperationException("Concurrent reads are not supported."));
|
SetConnectionError(new InvalidOperationException("Concurrent reads are not supported."));
|
||||||
|
|
||||||
|
|
@ -293,18 +299,23 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
AbortAwaiting();
|
||||||
|
|
||||||
|
MemoryPoolBlock block = null;
|
||||||
|
|
||||||
lock (_sync)
|
lock (_sync)
|
||||||
{
|
{
|
||||||
AbortAwaiting();
|
|
||||||
|
|
||||||
if (!_consuming)
|
if (!_consuming)
|
||||||
{
|
{
|
||||||
ReturnBlocks(_head, null);
|
block = _head;
|
||||||
_head = null;
|
_head = null;
|
||||||
_tail = null;
|
_tail = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
_disposed = true;
|
_disposed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReturnBlocks(block, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ReturnBlocks(MemoryPoolBlock block, MemoryPoolBlock end)
|
private static void ReturnBlocks(MemoryPoolBlock block, MemoryPoolBlock end)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue