Slimmer locks

This commit is contained in:
Ben Adams 2016-09-04 09:05:27 +01:00 committed by Stephen Halter
parent 09fda749b0
commit 310411075f
2 changed files with 42 additions and 31 deletions

View File

@ -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;

View File

@ -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)