Skip to content

Commit 16cccb5

Browse files
committed
Merge pull request #3 from stephentoub/delay_cts_allocation
Lazily allocate the RequestAborted CTS
2 parents 174ec73 + c7d7f0e commit 16cccb5

File tree

1 file changed

+45
-16
lines changed
  • src/Microsoft.AspNet.Server.Kestrel/Http

1 file changed

+45
-16
lines changed

src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public partial class Frame : FrameContext, IFrameControl
4444
private volatile bool _requestProcessingStopping; // volatile, see: https://msdn.microsoft.com/en-us/library/x13ttww7.aspx
4545
private volatile bool _requestAborted;
4646
private CancellationTokenSource _abortedCts;
47+
private CancellationToken? _manuallySetRequestAbortToken;
4748

4849
private FrameRequestStream _requestBody;
4950
private FrameResponseStream _responseBody;
@@ -92,8 +93,47 @@ public Frame(ConnectionContext context,
9293

9394
public Stream DuplexStream { get; set; }
9495

95-
public CancellationToken RequestAborted { get; set; }
96+
public CancellationToken RequestAborted
97+
{
98+
get
99+
{
100+
// If a request abort token was previously explicitly set, return it.
101+
if (_manuallySetRequestAbortToken.HasValue)
102+
return _manuallySetRequestAbortToken.Value;
103+
104+
// Otherwise, get the abort CTS. If we have one, which would mean that someone previously
105+
// asked for the RequestAborted token, simply return its token. If we don't,
106+
// check to see whether we've already aborted, in which case just return an
107+
// already canceled token. Finally, force a source into existence if we still
108+
// don't have one, and return its token.
109+
var cts = _abortedCts;
110+
return
111+
cts != null ? cts.Token :
112+
_requestAborted ? new CancellationToken(true) :
113+
RequestAbortedSource.Token;
114+
}
115+
set
116+
{
117+
// Set an abort token, overriding one we create internally. This setter and associated
118+
// field exist purely to support IHttpRequestLifetimeFeature.set_RequestAborted.
119+
_manuallySetRequestAbortToken = value;
120+
}
121+
}
96122

123+
private CancellationTokenSource RequestAbortedSource
124+
{
125+
get
126+
{
127+
// Get the abort token, lazily-initializing it if necessary.
128+
// Make sure it's canceled if an abort request already came in.
129+
var cts = LazyInitializer.EnsureInitialized(ref _abortedCts, () => new CancellationTokenSource());
130+
if (_requestAborted)
131+
{
132+
cts.Cancel();
133+
}
134+
return cts;
135+
}
136+
}
97137
public bool HasResponseStarted
98138
{
99139
get { return _responseStarted; }
@@ -145,7 +185,7 @@ public void Reset()
145185

146186
_prepareRequest?.Invoke(this);
147187

148-
_abortedCts?.Dispose();
188+
_manuallySetRequestAbortToken = null;
149189
_abortedCts = null;
150190
}
151191

@@ -198,24 +238,14 @@ public void Abort()
198238
{
199239
ConnectionControl.End(ProduceEndType.SocketDisconnect);
200240
SocketInput.AbortAwaiting();
201-
202-
try
203-
{
204-
_abortedCts?.Cancel();
205-
}
206-
catch (ObjectDisposedException)
207-
{
208-
// Don't log ODEs thrown from _abortedCts.Cancel()
209-
// If _abortedCts is disposed, the app has already completed.
210-
}
241+
RequestAbortedSource.Cancel();
211242
}
212243
catch (Exception ex)
213244
{
214245
Log.LogError("Abort", ex);
215246
}
216247
finally
217248
{
218-
_abortedCts?.Dispose();
219249
_abortedCts = null;
220250
}
221251
}
@@ -261,8 +291,8 @@ public async Task RequestProcessingAsync()
261291
ResponseBody = _responseBody;
262292
DuplexStream = new FrameDuplexStream(RequestBody, ResponseBody);
263293

264-
_abortedCts = new CancellationTokenSource();
265-
RequestAborted = _abortedCts.Token;
294+
_abortedCts = null;
295+
_manuallySetRequestAbortToken = null;
266296

267297
var httpContext = HttpContextFactory.Create(this);
268298
try
@@ -315,7 +345,6 @@ public async Task RequestProcessingAsync()
315345
{
316346
try
317347
{
318-
_abortedCts?.Dispose();
319348
_abortedCts = null;
320349

321350
// If _requestAborted is set, the connection has already been closed.

0 commit comments

Comments
 (0)