Merge pull request #3 from stephentoub/delay_cts_allocation

Lazily allocate the RequestAborted CTS
This commit is contained in:
Ben Adams 2015-11-21 14:16:28 +00:00
commit 16cccb50cb
1 changed files with 45 additions and 16 deletions

View File

@ -44,6 +44,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
private volatile bool _requestProcessingStopping; // volatile, see: https://msdn.microsoft.com/en-us/library/x13ttww7.aspx
private volatile bool _requestAborted;
private CancellationTokenSource _abortedCts;
private CancellationToken? _manuallySetRequestAbortToken;
private FrameRequestStream _requestBody;
private FrameResponseStream _responseBody;
@ -92,8 +93,47 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
public Stream DuplexStream { get; set; }
public CancellationToken RequestAborted { get; set; }
public CancellationToken RequestAborted
{
get
{
// If a request abort token was previously explicitly set, return it.
if (_manuallySetRequestAbortToken.HasValue)
return _manuallySetRequestAbortToken.Value;
// Otherwise, get the abort CTS. If we have one, which would mean that someone previously
// asked for the RequestAborted token, simply return its token. If we don't,
// check to see whether we've already aborted, in which case just return an
// already canceled token. Finally, force a source into existence if we still
// don't have one, and return its token.
var cts = _abortedCts;
return
cts != null ? cts.Token :
_requestAborted ? new CancellationToken(true) :
RequestAbortedSource.Token;
}
set
{
// Set an abort token, overriding one we create internally. This setter and associated
// field exist purely to support IHttpRequestLifetimeFeature.set_RequestAborted.
_manuallySetRequestAbortToken = value;
}
}
private CancellationTokenSource RequestAbortedSource
{
get
{
// Get the abort token, lazily-initializing it if necessary.
// Make sure it's canceled if an abort request already came in.
var cts = LazyInitializer.EnsureInitialized(ref _abortedCts, () => new CancellationTokenSource());
if (_requestAborted)
{
cts.Cancel();
}
return cts;
}
}
public bool HasResponseStarted
{
get { return _responseStarted; }
@ -145,7 +185,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
_prepareRequest?.Invoke(this);
_abortedCts?.Dispose();
_manuallySetRequestAbortToken = null;
_abortedCts = null;
}
@ -198,16 +238,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
ConnectionControl.End(ProduceEndType.SocketDisconnect);
SocketInput.AbortAwaiting();
try
{
_abortedCts?.Cancel();
}
catch (ObjectDisposedException)
{
// Don't log ODEs thrown from _abortedCts.Cancel()
// If _abortedCts is disposed, the app has already completed.
}
RequestAbortedSource.Cancel();
}
catch (Exception ex)
{
@ -215,7 +246,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
}
finally
{
_abortedCts?.Dispose();
_abortedCts = null;
}
}
@ -261,8 +291,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
ResponseBody = _responseBody;
DuplexStream = new FrameDuplexStream(RequestBody, ResponseBody);
_abortedCts = new CancellationTokenSource();
RequestAborted = _abortedCts.Token;
_abortedCts = null;
_manuallySetRequestAbortToken = null;
var httpContext = HttpContextFactory.Create(this);
try
@ -315,7 +345,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
try
{
_abortedCts?.Dispose();
_abortedCts = null;
// If _requestAborted is set, the connection has already been closed.