diff --git a/benchmarks/Kestrel.Performance/Http1ConnectionParsingOverheadBenchmark.cs b/benchmarks/Kestrel.Performance/Http1ConnectionParsingOverheadBenchmark.cs index 4d3f9ec311..3046c5f1e9 100644 --- a/benchmarks/Kestrel.Performance/Http1ConnectionParsingOverheadBenchmark.cs +++ b/benchmarks/Kestrel.Performance/Http1ConnectionParsingOverheadBenchmark.cs @@ -24,7 +24,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance public void Setup() { var memoryPool = KestrelMemoryPool.Create(); - var pair = DuplexPipe.CreateConnectionPair(memoryPool); + var options = new PipeOptions(memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false); + var pair = DuplexPipe.CreateConnectionPair(options, options); var serviceContext = new ServiceContext { diff --git a/benchmarks/Kestrel.Performance/Http1WritingBenchmark.cs b/benchmarks/Kestrel.Performance/Http1WritingBenchmark.cs index d3137dac17..891d94ab0a 100644 --- a/benchmarks/Kestrel.Performance/Http1WritingBenchmark.cs +++ b/benchmarks/Kestrel.Performance/Http1WritingBenchmark.cs @@ -96,7 +96,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance private TestHttp1Connection MakeHttp1Connection() { - var pair = DuplexPipe.CreateConnectionPair(_memoryPool); + var options = new PipeOptions(_memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false); + var pair = DuplexPipe.CreateConnectionPair(options, options); _pair = pair; var serviceContext = new ServiceContext diff --git a/benchmarks/Kestrel.Performance/HttpProtocolFeatureCollection.cs b/benchmarks/Kestrel.Performance/HttpProtocolFeatureCollection.cs index 081d17dc79..24b2c6c4b6 100644 --- a/benchmarks/Kestrel.Performance/HttpProtocolFeatureCollection.cs +++ b/benchmarks/Kestrel.Performance/HttpProtocolFeatureCollection.cs @@ -80,7 +80,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance public HttpProtocolFeatureCollection() { var memoryPool = KestrelMemoryPool.Create(); - var pair = DuplexPipe.CreateConnectionPair(memoryPool); + var options = new PipeOptions(memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false); + var pair = DuplexPipe.CreateConnectionPair(options, options); var serviceContext = new ServiceContext { diff --git a/benchmarks/Kestrel.Performance/InMemoryTransportBenchmark.cs b/benchmarks/Kestrel.Performance/InMemoryTransportBenchmark.cs index 73b94be6e1..0cf3e137a3 100644 --- a/benchmarks/Kestrel.Performance/InMemoryTransportBenchmark.cs +++ b/benchmarks/Kestrel.Performance/InMemoryTransportBenchmark.cs @@ -156,7 +156,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance public class InMemoryConnection : TransportConnection { - public PipeAwaiter SendRequestAsync(byte[] request) + public ValueTask SendRequestAsync(byte[] request) { return Input.WriteAsync(request); } diff --git a/benchmarks/Kestrel.Performance/RequestParsingBenchmark.cs b/benchmarks/Kestrel.Performance/RequestParsingBenchmark.cs index e6ea256d01..2d881588d2 100644 --- a/benchmarks/Kestrel.Performance/RequestParsingBenchmark.cs +++ b/benchmarks/Kestrel.Performance/RequestParsingBenchmark.cs @@ -25,7 +25,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance public void Setup() { _memoryPool = KestrelMemoryPool.Create(); - var pair = DuplexPipe.CreateConnectionPair(_memoryPool); + var options = new PipeOptions(_memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false); + var pair = DuplexPipe.CreateConnectionPair(options, options); var serviceContext = new ServiceContext { @@ -147,7 +148,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance return; } - var readableBuffer = awaitable.GetResult().Buffer; + var readableBuffer = awaitable.GetAwaiter().GetResult().Buffer; do { Http1Connection.Reset(); diff --git a/benchmarks/Kestrel.Performance/ResponseHeaderCollectionBenchmark.cs b/benchmarks/Kestrel.Performance/ResponseHeaderCollectionBenchmark.cs index b36f674ba4..e04f007222 100644 --- a/benchmarks/Kestrel.Performance/ResponseHeaderCollectionBenchmark.cs +++ b/benchmarks/Kestrel.Performance/ResponseHeaderCollectionBenchmark.cs @@ -172,7 +172,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance public void Setup() { var memoryPool = KestrelMemoryPool.Create(); - var pair = DuplexPipe.CreateConnectionPair(memoryPool); + var options = new PipeOptions(memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false); + var pair = DuplexPipe.CreateConnectionPair(options, options); var serviceContext = new ServiceContext { diff --git a/benchmarks/Kestrel.Performance/ResponseHeadersWritingBenchmark.cs b/benchmarks/Kestrel.Performance/ResponseHeadersWritingBenchmark.cs index 67b3705238..69df7fdb88 100644 --- a/benchmarks/Kestrel.Performance/ResponseHeadersWritingBenchmark.cs +++ b/benchmarks/Kestrel.Performance/ResponseHeadersWritingBenchmark.cs @@ -114,7 +114,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance public void Setup() { _memoryPool = KestrelMemoryPool.Create(); - var pair = DuplexPipe.CreateConnectionPair(_memoryPool); + var options = new PipeOptions(_memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false); + var pair = DuplexPipe.CreateConnectionPair(options, options); var serviceContext = new ServiceContext { diff --git a/build/dependencies.props b/build/dependencies.props index dd30197b3e..b83388dd08 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -16,7 +16,8 @@ 2.1.0-preview2-30272 2.1.0-preview2-30272 2.1.0-preview2-30272 - 2.1.0-preview2-30272 + 2.1.0-preview2-pk-corefx0-16426 + 2.1.0-preview2-pk-corefx0-16426 2.1.0-preview2-30272 2.1.0-preview2-30272 2.1.0-preview2-30272 @@ -26,18 +27,18 @@ 2.1.0-preview2-30272 2.1.0-preview2-30272 2.0.0 - 2.1.0-preview2-26225-03 + 2.1.0-preview2-26308-01 2.1.0-preview2-30272 15.6.0 4.7.49 10.0.1 - 4.5.0-preview2-26224-02 - 4.5.0-preview2-26224-02 - 4.5.0-preview2-26224-02 - 4.5.0-preview2-26224-02 - 4.5.0-preview2-26224-02 - 4.5.0-preview2-26224-02 - 4.5.0-preview2-26224-02 + 4.5.0-preview2-26308-02 + 4.5.0-preview2-26308-02 + 4.5.0-preview2-26308-02 + 4.5.0-preview2-26308-02 + 4.5.0-preview2-26308-02 + 4.5.0-preview2-26308-02 + 4.5.0-preview2-26308-02 0.8.0 2.3.1 2.4.0-beta.1.build3945 diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 4b89a431e7..a1676ede80 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,6 +1,8 @@ - + + $(DefineConstants);INNER_LOOP + diff --git a/src/Kestrel.Core/Adapter/Internal/LoggingStream.cs b/src/Kestrel.Core/Adapter/Internal/LoggingStream.cs index 62f62a5d4c..0b5fdf3975 100644 --- a/src/Kestrel.Core/Adapter/Internal/LoggingStream.cs +++ b/src/Kestrel.Core/Adapter/Internal/LoggingStream.cs @@ -139,7 +139,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal } #if NETCOREAPP2_1 - public override Task WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default) + public override ValueTask WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default) { Log("WriteAsync", source.Span); return _inner.WriteAsync(source, cancellationToken); diff --git a/src/Kestrel.Core/Adapter/Internal/RawStream.cs b/src/Kestrel.Core/Adapter/Internal/RawStream.cs index 32fb757db2..ea381c22b2 100644 --- a/src/Kestrel.Core/Adapter/Internal/RawStream.cs +++ b/src/Kestrel.Core/Adapter/Internal/RawStream.cs @@ -92,7 +92,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal } #if NETCOREAPP2_1 - public override async Task WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default) + public override async ValueTask WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default) { _output.Write(source.Span); await _output.FlushAsync(cancellationToken); diff --git a/src/Kestrel.Core/Internal/ConnectionHandler.cs b/src/Kestrel.Core/Internal/ConnectionHandler.cs index 8cd9552522..12ea3d189c 100644 --- a/src/Kestrel.Core/Internal/ConnectionHandler.cs +++ b/src/Kestrel.Core/Internal/ConnectionHandler.cs @@ -89,7 +89,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal readerScheduler: serviceContext.ThreadPool, writerScheduler: writerScheduler, pauseWriterThreshold: serviceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0, - resumeWriterThreshold: serviceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0 + resumeWriterThreshold: serviceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0, + useSynchronizationContext: false ); internal static PipeOptions GetOutputPipeOptions(ServiceContext serviceContext, MemoryPool memoryPool, PipeScheduler readerScheduler) => new PipeOptions @@ -98,7 +99,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal readerScheduler: readerScheduler, writerScheduler: serviceContext.ThreadPool, pauseWriterThreshold: GetOutputResponseBufferSize(serviceContext), - resumeWriterThreshold: GetOutputResponseBufferSize(serviceContext) + resumeWriterThreshold: GetOutputResponseBufferSize(serviceContext), + useSynchronizationContext: false ); private static long GetOutputResponseBufferSize(ServiceContext serviceContext) diff --git a/src/Kestrel.Core/Internal/Http/Http1Connection.cs b/src/Kestrel.Core/Internal/Http/Http1Connection.cs index 3876e63194..1251ac3518 100644 --- a/src/Kestrel.Core/Internal/Http/Http1Connection.cs +++ b/src/Kestrel.Core/Internal/Http/Http1Connection.cs @@ -10,6 +10,7 @@ using System.Runtime.InteropServices; using System.Text; using System.Text.Encodings.Web; using System.Threading; +using System.Threading.Tasks; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Protocols.Abstractions; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; @@ -429,7 +430,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http TimeoutControl.SetTimeout(_keepAliveTicks, TimeoutAction.StopProcessingNextRequest); } - protected override bool BeginRead(out PipeAwaiter awaitable) + protected override bool BeginRead(out ValueTask awaitable) { awaitable = Input.ReadAsync(); return true; diff --git a/src/Kestrel.Core/Internal/Http/Http1MessageBody.cs b/src/Kestrel.Core/Internal/Http/Http1MessageBody.cs index 503e21e5bd..5ac13c69a4 100644 --- a/src/Kestrel.Core/Internal/Http/Http1MessageBody.cs +++ b/src/Kestrel.Core/Internal/Http/Http1MessageBody.cs @@ -93,12 +93,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http BadHttpRequestException.Throw(RequestRejectionReason.UnexpectedEndOfRequestContent); } - awaitable = _context.Input.ReadAsync(); } finally { _context.Input.AdvanceTo(consumed, examined); } + + awaitable = _context.Input.ReadAsync(); } } catch (Exception ex) @@ -320,7 +321,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var actual = (int)Math.Min(readableBuffer.Length, _inputLength); _inputLength -= actual; - consumed = readableBuffer.GetPosition(readableBuffer.Start, actual); + consumed = readableBuffer.GetPosition(actual); examined = consumed; Copy(readableBuffer.Slice(0, actual), writableBuffer); @@ -561,7 +562,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http private void ReadChunkedData(ReadOnlySequence buffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined) { var actual = Math.Min(buffer.Length, _inputLength); - consumed = buffer.GetPosition(buffer.Start, actual); + consumed = buffer.GetPosition(actual); examined = consumed; Copy(buffer.Slice(0, actual), writableBuffer); diff --git a/src/Kestrel.Core/Internal/Http/Http1OutputProducer.cs b/src/Kestrel.Core/Internal/Http/Http1OutputProducer.cs index 3ecbf9298f..d767539185 100644 --- a/src/Kestrel.Core/Internal/Http/Http1OutputProducer.cs +++ b/src/Kestrel.Core/Internal/Http/Http1OutputProducer.cs @@ -38,6 +38,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http private readonly object _flushLock = new object(); private Action _flushCompleted; + private ValueTask _flushTask; + public Http1OutputProducer( PipeReader outputPipeReader, PipeWriter pipeWriter, @@ -200,7 +202,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http return FlushAsyncAwaited(awaitable, bytesWritten, cancellationToken); } - private async Task FlushAsyncAwaited(PipeAwaiter awaitable, long count, CancellationToken cancellationToken) + private async Task FlushAsyncAwaited(ValueTask awaitable, long count, CancellationToken cancellationToken) { // https://github.com/dotnet/corefxlab/issues/1334 // Since the flush awaitable doesn't currently support multiple awaiters @@ -208,24 +210,47 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http // All awaiters get the same task lock (_flushLock) { + _flushTask = awaitable; if (_flushTcs == null || _flushTcs.Task.IsCompleted) { _flushTcs = new TaskCompletionSource(); - awaitable.OnCompleted(_flushCompleted); + _flushTask.GetAwaiter().OnCompleted(_flushCompleted); } } _timeoutControl.StartTimingWrite(count); - await _flushTcs.Task; - _timeoutControl.StopTimingWrite(); - - cancellationToken.ThrowIfCancellationRequested(); + try + { + await _flushTcs.Task; + cancellationToken.ThrowIfCancellationRequested(); + } + catch (OperationCanceledException) + { + _completed = true; + throw; + } + finally + { + _timeoutControl.StopTimingWrite(); + } } private void OnFlushCompleted() { - _flushTcs.TrySetResult(null); + try + { + _flushTask.GetAwaiter().GetResult(); + _flushTcs.TrySetResult(null); + } + catch (Exception exception) + { + _flushTcs.TrySetResult(exception); + } + finally + { + _flushTask = default; + } } } } diff --git a/src/Kestrel.Core/Internal/Http/HttpParser.cs b/src/Kestrel.Core/Internal/Http/HttpParser.cs index 976841466a..416976b8ac 100644 --- a/src/Kestrel.Core/Internal/Http/HttpParser.cs +++ b/src/Kestrel.Core/Internal/Http/HttpParser.cs @@ -44,7 +44,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var lineIndex = span.IndexOf(ByteLF); if (lineIndex >= 0) { - consumed = buffer.GetPosition(consumed, lineIndex + 1); + consumed = buffer.GetPosition(lineIndex + 1, consumed); span = span.Slice(0, lineIndex + 1); } else if (buffer.IsSingleSegment) @@ -293,7 +293,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http var lineEnd = lineEndPosition.Value; // Make sure LF is included in lineEnd - lineEnd = buffer.GetPosition(lineEnd, 1); + lineEnd = buffer.GetPosition(1, lineEnd); var headerSpan = buffer.Slice(current, lineEnd).ToSpan(); length = headerSpan.Length; @@ -425,7 +425,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http if (byteLfPosition != null) { // Move 1 byte past the \n - found = buffer.GetPosition(byteLfPosition.Value, 1); + found = buffer.GetPosition(1, byteLfPosition.Value); return true; } diff --git a/src/Kestrel.Core/Internal/Http/HttpProtocol.cs b/src/Kestrel.Core/Internal/Http/HttpProtocol.cs index ad90b76a1e..2954368f4c 100644 --- a/src/Kestrel.Core/Internal/Http/HttpProtocol.cs +++ b/src/Kestrel.Core/Internal/Http/HttpProtocol.cs @@ -383,7 +383,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http { } - protected virtual bool BeginRead(out PipeAwaiter awaitable) + protected virtual bool BeginRead(out ValueTask awaitable) { awaitable = default; return false; @@ -1336,7 +1336,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http readerScheduler: ServiceContext.ThreadPool, writerScheduler: PipeScheduler.Inline, pauseWriterThreshold: 1, - resumeWriterThreshold: 1 + resumeWriterThreshold: 1, + useSynchronizationContext: false )); } } diff --git a/src/Kestrel.Core/Internal/Http/HttpResponseStream.cs b/src/Kestrel.Core/Internal/Http/HttpResponseStream.cs index 93cea42956..fb2cc91a9d 100644 --- a/src/Kestrel.Core/Internal/Http/HttpResponseStream.cs +++ b/src/Kestrel.Core/Internal/Http/HttpResponseStream.cs @@ -112,11 +112,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http } #if NETCOREAPP2_1 - public override Task WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default) + public override ValueTask WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default) { ValidateState(cancellationToken); - return _httpResponseControl.WriteAsync(source, cancellationToken); + return new ValueTask(_httpResponseControl.WriteAsync(source, cancellationToken)); } #endif diff --git a/src/Kestrel.Core/Internal/Http/MessageBody.cs b/src/Kestrel.Core/Internal/Http/MessageBody.cs index 2ebf6f1212..a406e64ffa 100644 --- a/src/Kestrel.Core/Internal/Http/MessageBody.cs +++ b/src/Kestrel.Core/Internal/Http/MessageBody.cs @@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http // buffer.Count is int var actual = (int) Math.Min(readableBuffer.Length, buffer.Length); var slice = readableBuffer.Slice(0, actual); - consumed = readableBuffer.GetPosition(readableBuffer.Start, actual); + consumed = readableBuffer.GetPosition(actual); slice.CopyTo(buffer.Span); return actual; } diff --git a/src/Kestrel.Core/Internal/Http/PipelineExtensions.cs b/src/Kestrel.Core/Internal/Http/PipelineExtensions.cs index b5a2664bda..e56c43b23c 100644 --- a/src/Kestrel.Core/Internal/Http/PipelineExtensions.cs +++ b/src/Kestrel.Core/Internal/Http/PipelineExtensions.cs @@ -28,12 +28,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http public static ArraySegment GetArray(this Memory buffer) { - ArraySegment result; - if (!buffer.TryGetArray(out result)) - { - throw new InvalidOperationException("Buffer backed by array was expected"); - } - return result; + return ((ReadOnlyMemory)buffer).GetArray(); } public static ArraySegment GetArray(this ReadOnlyMemory memory) diff --git a/src/Kestrel.Core/Internal/Http2/Http2Connection.cs b/src/Kestrel.Core/Internal/Http2/Http2Connection.cs index d0b46039db..0e1928720f 100644 --- a/src/Kestrel.Core/Internal/Http2/Http2Connection.cs +++ b/src/Kestrel.Core/Internal/Http2/Http2Connection.cs @@ -237,7 +237,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 } } - consumed = examined = readableBuffer.GetPosition(readableBuffer.Start, ClientPreface.Length); + consumed = examined = readableBuffer.GetPosition(ClientPreface.Length); return true; } diff --git a/src/Kestrel.Core/Internal/Http2/Http2FrameReader.cs b/src/Kestrel.Core/Internal/Http2/Http2FrameReader.cs index b9d84fc896..6b2ab584db 100644 --- a/src/Kestrel.Core/Internal/Http2/Http2FrameReader.cs +++ b/src/Kestrel.Core/Internal/Http2/Http2FrameReader.cs @@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 } readableBuffer.Slice(Http2Frame.HeaderLength, frame.Length).CopyTo(frame.Payload); - consumed = examined = readableBuffer.GetPosition(readableBuffer.Start, Http2Frame.HeaderLength + frame.Length); + consumed = examined = readableBuffer.GetPosition(Http2Frame.HeaderLength + frame.Length); return true; } diff --git a/src/Kestrel.Core/Internal/HttpConnection.cs b/src/Kestrel.Core/Internal/HttpConnection.cs index b3895a72c9..aff705e7ee 100644 --- a/src/Kestrel.Core/Internal/HttpConnection.cs +++ b/src/Kestrel.Core/Internal/HttpConnection.cs @@ -77,7 +77,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal readerScheduler: _context.ServiceContext.ThreadPool, writerScheduler: PipeScheduler.Inline, pauseWriterThreshold: _context.ServiceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0, - resumeWriterThreshold: _context.ServiceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0 + resumeWriterThreshold: _context.ServiceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0, + useSynchronizationContext: false ); internal PipeOptions AdaptedOutputPipeOptions => new PipeOptions @@ -86,7 +87,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, pauseWriterThreshold: _context.ServiceContext.ServerOptions.Limits.MaxResponseBufferSize ?? 0, - resumeWriterThreshold: _context.ServiceContext.ServerOptions.Limits.MaxResponseBufferSize ?? 0 + resumeWriterThreshold: _context.ServiceContext.ServerOptions.Limits.MaxResponseBufferSize ?? 0, + useSynchronizationContext: false ); private IKestrelTrace Log => _context.ServiceContext.Log; diff --git a/src/Kestrel.Core/Internal/Infrastructure/Heartbeat.cs b/src/Kestrel.Core/Internal/Infrastructure/Heartbeat.cs index f722f60e9d..fb0f17d83b 100644 --- a/src/Kestrel.Core/Internal/Infrastructure/Heartbeat.cs +++ b/src/Kestrel.Core/Internal/Infrastructure/Heartbeat.cs @@ -15,20 +15,27 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure private readonly ISystemClock _systemClock; private readonly IDebugger _debugger; private readonly IKestrelTrace _trace; + private readonly TimeSpan _interval; private Timer _timer; private int _executingOnHeartbeat; - public Heartbeat(IHeartbeatHandler[] callbacks, ISystemClock systemClock, IDebugger debugger, IKestrelTrace trace) + public Heartbeat(IHeartbeatHandler[] callbacks, ISystemClock systemClock, IDebugger debugger, IKestrelTrace trace): this(callbacks, systemClock, debugger, trace, Interval) + { + + } + + internal Heartbeat(IHeartbeatHandler[] callbacks, ISystemClock systemClock, IDebugger debugger, IKestrelTrace trace, TimeSpan interval) { _callbacks = callbacks; _systemClock = systemClock; _debugger = debugger; _trace = trace; + _interval = interval; } public void Start() { - _timer = new Timer(OnHeartbeat, state: this, dueTime: Interval, period: Interval); + _timer = new Timer(OnHeartbeat, state: this, dueTime: _interval, period: _interval); } private static void OnHeartbeat(object state) @@ -63,7 +70,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure { if (!_debugger.IsAttached) { - _trace.HeartbeatSlow(Interval, now); + _trace.HeartbeatSlow(_interval, now); } } } diff --git a/src/Kestrel.Core/Internal/Infrastructure/InlineLoggingThreadPool.cs b/src/Kestrel.Core/Internal/Infrastructure/InlineLoggingThreadPool.cs index 26219bf8b0..b3ab4c905b 100644 --- a/src/Kestrel.Core/Internal/Infrastructure/InlineLoggingThreadPool.cs +++ b/src/Kestrel.Core/Internal/Infrastructure/InlineLoggingThreadPool.cs @@ -33,12 +33,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure action(state); } - public override void Schedule(Action action) - { - Run(action); - } - - public override void Schedule(Action action, object state) + public override void Schedule(Action action, T state) { try { diff --git a/src/Kestrel.Core/Internal/Infrastructure/LoggingThreadPool.cs b/src/Kestrel.Core/Internal/Infrastructure/LoggingThreadPool.cs index 70c90bd1ea..da0ae6ac39 100644 --- a/src/Kestrel.Core/Internal/Infrastructure/LoggingThreadPool.cs +++ b/src/Kestrel.Core/Internal/Infrastructure/LoggingThreadPool.cs @@ -50,12 +50,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure System.Threading.ThreadPool.QueueUserWorkItem(action, state); } - public override void Schedule(Action action) - { - Run(action); - } - - public override void Schedule(Action action, object state) + public override void Schedule(Action action, T state) { Run(() => action(state)); } diff --git a/src/Kestrel.Transport.Libuv/Internal/LibuvConnection.cs b/src/Kestrel.Transport.Libuv/Internal/LibuvConnection.cs index bb98d1c8c1..b5df138e61 100644 --- a/src/Kestrel.Transport.Libuv/Internal/LibuvConnection.cs +++ b/src/Kestrel.Transport.Libuv/Internal/LibuvConnection.cs @@ -173,7 +173,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal _bufferHandle.Dispose(); } - private async Task ApplyBackpressureAsync(PipeAwaiter flushTask) + private async Task ApplyBackpressureAsync(ValueTask flushTask) { Log.ConnectionPause(ConnectionId); _socket.ReadStop(); diff --git a/src/Kestrel.Transport.Libuv/Internal/LibuvThread.cs b/src/Kestrel.Transport.Libuv/Internal/LibuvThread.cs index 0d6530303f..f26f656528 100644 --- a/src/Kestrel.Transport.Libuv/Internal/LibuvThread.cs +++ b/src/Kestrel.Transport.Libuv/Internal/LibuvThread.cs @@ -48,8 +48,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal _log = transport.Log; _loop = new UvLoopHandle(_log); _post = new UvAsyncHandle(_log); + _thread = new Thread(ThreadStart); +#if !INNER_LOOP _thread.Name = nameof(LibuvThread); +#endif + #if !DEBUG // Mark the thread as being as unimportant to keeping the process alive. // Don't do this for debug builds, so we know if the thread isn't terminating. @@ -132,7 +136,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal _closeError?.Throw(); } -#if DEBUG +#if DEBUG && !INNER_LOOP private void CheckUvReqLeaks() { GC.Collect(); @@ -177,6 +181,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal { CallbackAdapter = CallbackAdapter.PostCallbackAdapter, Callback = callback, + //TODO: This boxes State = state }; @@ -301,7 +306,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal WriteReqPool.Dispose(); _threadTcs.SetResult(null); -#if DEBUG +#if DEBUG && !INNER_LOOP // Check for handle leaks after disposing everything CheckUvReqLeaks(); #endif @@ -391,12 +396,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal return await Task.WhenAny(task, Task.Delay(timeout)).ConfigureAwait(false) == task; } - public override void Schedule(Action action) - { - Post(state => state(), action); - } - - public override void Schedule(Action action, object state) + public override void Schedule(Action action, T state) { Post(action, state); } diff --git a/src/Kestrel.Transport.Libuv/Internal/Networking/UvMemory.cs b/src/Kestrel.Transport.Libuv/Internal/Networking/UvMemory.cs index 1285777910..9454e6fc23 100644 --- a/src/Kestrel.Transport.Libuv/Internal/Networking/UvMemory.cs +++ b/src/Kestrel.Transport.Libuv/Internal/Networking/UvMemory.cs @@ -51,7 +51,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networkin { _uv = uv; ThreadId = threadId; - + handle = Marshal.AllocCoTaskMem(size); *(IntPtr*)handle = GCHandle.ToIntPtr(GCHandle.Alloc(this, _handleType)); } diff --git a/src/Kestrel.Transport.Libuv/LibuvTransport.cs b/src/Kestrel.Transport.Libuv/LibuvTransport.cs index f3d376c3f3..19eb6cf72e 100644 --- a/src/Kestrel.Transport.Libuv/LibuvTransport.cs +++ b/src/Kestrel.Transport.Libuv/LibuvTransport.cs @@ -62,7 +62,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv } Threads.Clear(); -#if DEBUG +#if DEBUG && !INNER_LOOP GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); diff --git a/src/Kestrel.Transport.Sockets/Internal/BufferExtensions.cs b/src/Kestrel.Transport.Sockets/Internal/BufferExtensions.cs index 7340736bd8..9985dfbc5b 100644 --- a/src/Kestrel.Transport.Sockets/Internal/BufferExtensions.cs +++ b/src/Kestrel.Transport.Sockets/Internal/BufferExtensions.cs @@ -10,11 +10,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal { public static ArraySegment GetArray(this Memory memory) { - if (!memory.TryGetArray(out var result)) - { - throw new InvalidOperationException("Buffer backed by array was expected"); - } - return result; + return ((ReadOnlyMemory)memory).GetArray(); } public static ArraySegment GetArray(this ReadOnlyMemory memory) diff --git a/src/Protocols.Abstractions/DuplexPipe.cs b/src/Protocols.Abstractions/DuplexPipe.cs index 60fc029aec..adf8b497c6 100644 --- a/src/Protocols.Abstractions/DuplexPipe.cs +++ b/src/Protocols.Abstractions/DuplexPipe.cs @@ -18,11 +18,6 @@ namespace System.IO.Pipelines { } - public static DuplexPipePair CreateConnectionPair(MemoryPool memoryPool) - { - return CreateConnectionPair(new PipeOptions(memoryPool), new PipeOptions(memoryPool)); - } - public static DuplexPipePair CreateConnectionPair(PipeOptions inputOptions, PipeOptions outputOptions) { var input = new Pipe(inputOptions); diff --git a/test/Kestrel.Core.Tests/AsciiDecoding.cs b/test/Kestrel.Core.Tests/AsciiDecoding.cs index 8f593f9671..7fa45513d2 100644 --- a/test/Kestrel.Core.Tests/AsciiDecoding.cs +++ b/test/Kestrel.Core.Tests/AsciiDecoding.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using System.Numerics; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; using Xunit; @@ -41,7 +42,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests [InlineData(0x80)] private void ExceptionThrownForZeroOrNonAscii(byte b) { - for (var length = 1; length < 1024; length++) + for (var length = 1; length < Vector.Count * 4; length++) { for (var position = 0; position < length; position++) { diff --git a/test/Kestrel.Core.Tests/HeartbeatTests.cs b/test/Kestrel.Core.Tests/HeartbeatTests.cs index bf80664c6d..86fc9093f3 100644 --- a/test/Kestrel.Core.Tests/HeartbeatTests.cs +++ b/test/Kestrel.Core.Tests/HeartbeatTests.cs @@ -65,11 +65,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests debugger.Setup(d => d.IsAttached).Returns(true); kestrelTrace.Setup(t => t.HeartbeatSlow(Heartbeat.Interval, systemClock.UtcNow)).Callback(() => traceMre.Set()); - using (var heartbeat = new Heartbeat(new[] { heartbeatHandler.Object }, systemClock, debugger.Object, kestrelTrace.Object)) + using (var heartbeat = new Heartbeat(new[] { heartbeatHandler.Object }, systemClock, debugger.Object, kestrelTrace.Object, TimeSpan.FromSeconds(0.01))) { onHeartbeatTasks[0] = Task.Run(() => heartbeat.OnHeartbeat()); onHeartbeatTasks[1] = Task.Run(() => heartbeat.OnHeartbeat()); - Assert.False(traceMre.Wait(TimeSpan.FromSeconds(10))); + Assert.False(traceMre.Wait(TimeSpan.FromSeconds(2))); } handlerMre.Set(); diff --git a/test/Kestrel.Core.Tests/Http1ConnectionTests.cs b/test/Kestrel.Core.Tests/Http1ConnectionTests.cs index 7428e20ec2..c4cac14b78 100644 --- a/test/Kestrel.Core.Tests/Http1ConnectionTests.cs +++ b/test/Kestrel.Core.Tests/Http1ConnectionTests.cs @@ -41,7 +41,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests public Http1ConnectionTests() { _pipelineFactory = KestrelMemoryPool.Create(); - var pair = DuplexPipe.CreateConnectionPair(_pipelineFactory); + var options = new PipeOptions(_pipelineFactory, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false); + var pair = DuplexPipe.CreateConnectionPair(options, options); _transport = pair.Transport; _application = pair.Application; diff --git a/test/Kestrel.Core.Tests/Http2ConnectionTests.cs b/test/Kestrel.Core.Tests/Http2ConnectionTests.cs index ca49803ee4..7766a9179b 100644 --- a/test/Kestrel.Core.Tests/Http2ConnectionTests.cs +++ b/test/Kestrel.Core.Tests/Http2ConnectionTests.cs @@ -126,7 +126,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests var inlineSchedulingPipeOptions = new PipeOptions( pool: _memoryPool, readerScheduler: PipeScheduler.Inline, - writerScheduler: PipeScheduler.Inline + writerScheduler: PipeScheduler.Inline, + useSynchronizationContext: false ); _pair = DuplexPipe.CreateConnectionPair(inlineSchedulingPipeOptions, inlineSchedulingPipeOptions); diff --git a/test/Kestrel.Core.Tests/HttpConnectionTests.cs b/test/Kestrel.Core.Tests/HttpConnectionTests.cs index 27b1c3c5b3..8710055844 100644 --- a/test/Kestrel.Core.Tests/HttpConnectionTests.cs +++ b/test/Kestrel.Core.Tests/HttpConnectionTests.cs @@ -26,7 +26,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests public HttpConnectionTests() { _memoryPool = KestrelMemoryPool.Create(); - var pair = DuplexPipe.CreateConnectionPair(_memoryPool); + var options = new PipeOptions(_memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false); + var pair = DuplexPipe.CreateConnectionPair(options, options); _httpConnectionContext = new HttpConnectionContext { diff --git a/test/Kestrel.Core.Tests/HttpParserTests.cs b/test/Kestrel.Core.Tests/HttpParserTests.cs index 8baa695f96..dec3c68681 100644 --- a/test/Kestrel.Core.Tests/HttpParserTests.cs +++ b/test/Kestrel.Core.Tests/HttpParserTests.cs @@ -18,6 +18,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests { public class HttpParserTests { + private static IKestrelTrace _nullTrace = Mock.Of(); + [Theory] [MemberData(nameof(RequestLineValidData))] public void ParsesRequestLine( @@ -33,7 +35,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests #pragma warning restore xUnit1026 string expectedVersion) { - var parser = CreateParser(Mock.Of()); + var parser = CreateParser(_nullTrace); var buffer = new ReadOnlySequence(Encoding.ASCII.GetBytes(requestLine)); var requestHandler = new RequestHandler(); @@ -52,7 +54,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests [MemberData(nameof(RequestLineIncompleteData))] public void ParseRequestLineReturnsFalseWhenGivenIncompleteRequestLines(string requestLine) { - var parser = CreateParser(Mock.Of()); + var parser = CreateParser(_nullTrace); var buffer = new ReadOnlySequence(Encoding.ASCII.GetBytes(requestLine)); var requestHandler = new RequestHandler(); @@ -63,7 +65,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests [MemberData(nameof(RequestLineIncompleteData))] public void ParseRequestLineDoesNotConsumeIncompleteRequestLine(string requestLine) { - var parser = CreateParser(Mock.Of()); + var parser = CreateParser(_nullTrace); var buffer = new ReadOnlySequence(Encoding.ASCII.GetBytes(requestLine)); var requestHandler = new RequestHandler(); @@ -176,7 +178,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests [InlineData("Header-1: value1\r\nHeader-2: value2\r\n\r")] public void ParseHeadersReturnsFalseWhenGivenIncompleteHeaders(string rawHeaders) { - var parser = CreateParser(Mock.Of()); + var parser = CreateParser(_nullTrace); var buffer = new ReadOnlySequence(Encoding.ASCII.GetBytes(rawHeaders)); var requestHandler = new RequestHandler(); @@ -201,7 +203,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests [InlineData("Header: value\r")] public void ParseHeadersDoesNotConsumeIncompleteHeader(string rawHeaders) { - var parser = CreateParser(Mock.Of()); + var parser = CreateParser(_nullTrace); var buffer = new ReadOnlySequence(Encoding.ASCII.GetBytes(rawHeaders)); var requestHandler = new RequestHandler(); @@ -290,14 +292,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests [Fact] public void ParseHeadersConsumesBytesCorrectlyAtEnd() { - var parser = CreateParser(Mock.Of()); + var parser = CreateParser(_nullTrace); const string headerLine = "Header: value\r\n\r"; var buffer1 = new ReadOnlySequence(Encoding.ASCII.GetBytes(headerLine)); var requestHandler = new RequestHandler(); Assert.False(parser.ParseHeaders(requestHandler, buffer1, out var consumed, out var examined, out var consumedBytes)); - Assert.Equal(buffer1.GetPosition(buffer1.Start, headerLine.Length - 1), consumed); + Assert.Equal(buffer1.GetPosition(headerLine.Length - 1), consumed); Assert.Equal(buffer1.End, examined); Assert.Equal(headerLine.Length - 1, consumedBytes); @@ -371,8 +373,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests [Fact] public void ParseRequestLineSplitBufferWithoutNewLineDoesNotUpdateConsumed() { - var parser = CreateParser(Mock.Of()); - var buffer = CreateBuffer("GET ", "/"); + var parser = CreateParser(_nullTrace); + var buffer = ReadOnlySequenceFactory.CreateSegments( + Encoding.ASCII.GetBytes("GET "), + Encoding.ASCII.GetBytes("/")); var requestHandler = new RequestHandler(); var result = parser.ParseRequestLine(requestHandler, buffer, out var consumed, out var examined); @@ -387,7 +391,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests string rawHeaderValue, string expectedHeaderValue) { - var parser = CreateParser(Mock.Of()); + var parser = CreateParser(_nullTrace); var buffer = new ReadOnlySequence(Encoding.ASCII.GetBytes($"{headerName}:{rawHeaderValue}\r\n")); var requestHandler = new RequestHandler(); @@ -405,7 +409,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests { Assert.True(expectedHeaderNames.Count() == expectedHeaderValues.Count(), $"{nameof(expectedHeaderNames)} and {nameof(expectedHeaderValues)} sizes must match"); - var parser = CreateParser(Mock.Of()); + var parser = CreateParser(_nullTrace); var buffer = new ReadOnlySequence(Encoding.ASCII.GetBytes(rawHeaders)); var requestHandler = new RequestHandler(); @@ -465,86 +469,5 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests PathEncoded = pathEncoded; } } - - private static ReadOnlySequence CreateBuffer(params string[] inputs) - { - var buffers = new byte[inputs.Length][]; - for (int i = 0; i < inputs.Length; i++) - { - buffers[i] = Encoding.UTF8.GetBytes(inputs[i]); - } - return CreateBuffer(buffers); - } - - // Copied from https://github.com/dotnet/corefx/blob/master/src/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.cs - private static ReadOnlySequence CreateBuffer(params byte[][] inputs) - { - if (inputs == null || inputs.Length == 0) - { - throw new InvalidOperationException(); - } - - int i = 0; - - BufferSegment last = null; - BufferSegment first = null; - - do - { - byte[] s = inputs[i]; - int length = s.Length; - int dataOffset = length; - var chars = new byte[length * 2]; - - for (int j = 0; j < length; j++) - { - chars[dataOffset + j] = s[j]; - } - - // Create a segment that has offset relative to the OwnedMemory and OwnedMemory itself has offset relative to array - var memory = new Memory(chars).Slice(length, length); - - if (first == null) - { - first = new BufferSegment(memory); - last = first; - } - else - { - last = last.Append(memory); - } - i++; - } while (i < inputs.Length); - - return new ReadOnlySequence(first, 0, last, last.Memory.Length); - } - - // Copied from https://github.com/dotnet/corefx/blob/master/src/System.Memory/tests/ReadOnlyBuffer/BufferSegment.cs - private class BufferSegment : IMemoryList - { - public BufferSegment(Memory memory) - { - Memory = memory; - } - - /// - /// Combined length of all segments before this - /// - public long RunningIndex { get; private set; } - - public Memory Memory { get; set; } - - public IMemoryList Next { get; private set; } - - public BufferSegment Append(Memory memory) - { - var segment = new BufferSegment(memory) - { - RunningIndex = RunningIndex + Memory.Length - }; - Next = segment; - return segment; - } - } } } diff --git a/test/Kestrel.Core.Tests/HttpProtocolFeatureCollectionTests.cs b/test/Kestrel.Core.Tests/HttpProtocolFeatureCollectionTests.cs index 846b441862..84d08ff3d7 100644 --- a/test/Kestrel.Core.Tests/HttpProtocolFeatureCollectionTests.cs +++ b/test/Kestrel.Core.Tests/HttpProtocolFeatureCollectionTests.cs @@ -24,15 +24,16 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests private readonly TestHttp1Connection _http1Connection; private readonly ServiceContext _serviceContext; private readonly Http1ConnectionContext _http1ConnectionContext; - private readonly MemoryPool _pipelineFactory; + private readonly MemoryPool _memoryPool; private Mock _timeoutControl; private readonly IFeatureCollection _collection; public HttpProtocolFeatureCollectionTests() { - _pipelineFactory = KestrelMemoryPool.Create(); - var pair = DuplexPipe.CreateConnectionPair(_pipelineFactory); + _memoryPool = KestrelMemoryPool.Create(); + var options = new PipeOptions(_memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false); + var pair = DuplexPipe.CreateConnectionPair(options, options); _transport = pair.Transport; _application = pair.Application; @@ -43,7 +44,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests { ServiceContext = _serviceContext, ConnectionFeatures = new FeatureCollection(), - MemoryPool = _pipelineFactory, + MemoryPool = _memoryPool, TimeoutControl = _timeoutControl.Object, Application = pair.Application, Transport = pair.Transport @@ -62,7 +63,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests _application.Input.Complete(); _application.Output.Complete(); - _pipelineFactory.Dispose(); + _memoryPool.Dispose(); } [Fact] diff --git a/test/Kestrel.Core.Tests/HttpResponseHeadersTests.cs b/test/Kestrel.Core.Tests/HttpResponseHeadersTests.cs index 8a602351ad..a8e2e7f441 100644 --- a/test/Kestrel.Core.Tests/HttpResponseHeadersTests.cs +++ b/test/Kestrel.Core.Tests/HttpResponseHeadersTests.cs @@ -23,7 +23,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests { using (var memoryPool = KestrelMemoryPool.Create()) { - var pair = DuplexPipe.CreateConnectionPair(memoryPool); + var options = new PipeOptions(memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false); + var pair = DuplexPipe.CreateConnectionPair(options, options); var http1ConnectionContext = new Http1ConnectionContext { ServiceContext = new TestServiceContext(), diff --git a/test/Kestrel.Core.Tests/Kestrel.Core.Tests.csproj b/test/Kestrel.Core.Tests/Kestrel.Core.Tests.csproj index fdbbd000ef..2d65668838 100644 --- a/test/Kestrel.Core.Tests/Kestrel.Core.Tests.csproj +++ b/test/Kestrel.Core.Tests/Kestrel.Core.Tests.csproj @@ -23,6 +23,7 @@ + diff --git a/test/Kestrel.Core.Tests/OutputProducerTests.cs b/test/Kestrel.Core.Tests/OutputProducerTests.cs index 8cd730fca0..dc063922ff 100644 --- a/test/Kestrel.Core.Tests/OutputProducerTests.cs +++ b/test/Kestrel.Core.Tests/OutputProducerTests.cs @@ -35,7 +35,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests ( pool: _memoryPool, readerScheduler: Mock.Of(), - writerScheduler: PipeScheduler.Inline + writerScheduler: PipeScheduler.Inline, + useSynchronizationContext: false ); using (var socketOutput = CreateOutputProducer(pipeOptions)) diff --git a/test/Kestrel.Core.Tests/PipelineExtensionTests.cs b/test/Kestrel.Core.Tests/PipelineExtensionTests.cs index 35e4f02e05..485183ff85 100644 --- a/test/Kestrel.Core.Tests/PipelineExtensionTests.cs +++ b/test/Kestrel.Core.Tests/PipelineExtensionTests.cs @@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests public PipelineExtensionTests() { - _pipe = new Pipe(new PipeOptions(_memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline)); + _pipe = new Pipe(new PipeOptions(_memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false)); } public void Dispose() diff --git a/test/Kestrel.Core.Tests/TestInput.cs b/test/Kestrel.Core.Tests/TestInput.cs index f91def83ec..1295121548 100644 --- a/test/Kestrel.Core.Tests/TestInput.cs +++ b/test/Kestrel.Core.Tests/TestInput.cs @@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests public TestInput() { _memoryPool = KestrelMemoryPool.Create(); - var options = new PipeOptions(pool: _memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline); + var options = new PipeOptions(pool: _memoryPool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false); var pair = DuplexPipe.CreateConnectionPair(options, options); Transport = pair.Transport; Application = pair.Application; diff --git a/test/Kestrel.FunctionalTests/KeepAliveTimeoutTests.cs b/test/Kestrel.FunctionalTests/KeepAliveTimeoutTests.cs index 5d4a3c553f..32278e4159 100644 --- a/test/Kestrel.FunctionalTests/KeepAliveTimeoutTests.cs +++ b/test/Kestrel.FunctionalTests/KeepAliveTimeoutTests.cs @@ -1,6 +1,6 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - +#if !INNER_LOOP using System; using System.Text; using System.Threading; @@ -252,3 +252,4 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests } } } +#endif \ No newline at end of file diff --git a/test/Kestrel.FunctionalTests/TestHelpers/TestServer.cs b/test/Kestrel.FunctionalTests/TestHelpers/TestServer.cs index 0aff951af4..7cf3399dd5 100644 --- a/test/Kestrel.FunctionalTests/TestHelpers/TestServer.cs +++ b/test/Kestrel.FunctionalTests/TestHelpers/TestServer.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Linq; using System.Net; using System.Net.Sockets; using System.Reflection; @@ -11,9 +12,11 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.AspNetCore.Server.Kestrel.Core.Internal; using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal; using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests @@ -68,7 +71,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests } return new KestrelServer(sp.GetRequiredService(), context); }); - + RemoveDevCert(services); configureServices(services); }) .UseSetting(WebHostDefaults.ApplicationKey, typeof(TestServer).GetTypeInfo().Assembly.FullName) @@ -77,6 +80,19 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests _host.Start(); } + public static void RemoveDevCert(IServiceCollection services) + { + // KestrelServerOptionsSetup would scan all system certificates on every test server creation + // making test runs very slow + foreach (var descriptor in services.ToArray()) + { + if (descriptor.ImplementationType == typeof(KestrelServerOptionsSetup)) + { + services.Remove(descriptor); + } + } + } + public IPEndPoint EndPoint => _listenOptions.IPEndPoint; public int Port => _listenOptions.IPEndPoint.Port; public AddressFamily AddressFamily => _listenOptions.IPEndPoint.AddressFamily; diff --git a/test/Kestrel.Transport.Libuv.FunctionalTests/TransportSelector.cs b/test/Kestrel.Transport.Libuv.FunctionalTests/TransportSelector.cs index cba3395d11..db778d603b 100644 --- a/test/Kestrel.Transport.Libuv.FunctionalTests/TransportSelector.cs +++ b/test/Kestrel.Transport.Libuv.FunctionalTests/TransportSelector.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests { public static IWebHostBuilder GetWebHostBuilder() { - return new WebHostBuilder().UseLibuv(); + return new WebHostBuilder().UseLibuv().ConfigureServices(TestServer.RemoveDevCert); } } } diff --git a/test/Kestrel.Transport.Libuv.Tests/LibuvConnectionTests.cs b/test/Kestrel.Transport.Libuv.Tests/LibuvConnectionTests.cs index 5071a3cbad..2eeec77ab7 100644 --- a/test/Kestrel.Transport.Libuv.Tests/LibuvConnectionTests.cs +++ b/test/Kestrel.Transport.Libuv.Tests/LibuvConnectionTests.cs @@ -64,11 +64,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests pool: pool, pauseWriterThreshold: 3, readerScheduler: PipeScheduler.Inline, - writerScheduler: PipeScheduler.Inline); + writerScheduler: PipeScheduler.Inline, + useSynchronizationContext: false); // We don't set the output writer scheduler here since we want to run the callback inline - mockConnectionHandler.OutputOptions = pool => new PipeOptions(pool: pool, readerScheduler: thread, writerScheduler: PipeScheduler.Inline); + mockConnectionHandler.OutputOptions = pool => new PipeOptions(pool: pool, readerScheduler: thread, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false); Task connectionTask = null; @@ -121,9 +122,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests var thread = new LibuvThread(transport); var mockScheduler = new Mock(); Action backPressure = null; - mockScheduler.Setup(m => m.Schedule(It.IsAny())).Callback(a => + mockScheduler.Setup(m => m.Schedule(It.IsAny>(), It.IsAny())).Callback, object>((a, o) => { - backPressure = a; + backPressure = () => a(o); }); mockConnectionHandler.InputOptions = pool => new PipeOptions( @@ -131,9 +132,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests pauseWriterThreshold: 3, resumeWriterThreshold: 3, writerScheduler: mockScheduler.Object, - readerScheduler: PipeScheduler.Inline); + readerScheduler: PipeScheduler.Inline, + useSynchronizationContext: false); - mockConnectionHandler.OutputOptions = pool => new PipeOptions(pool: pool, readerScheduler: thread, writerScheduler: PipeScheduler.Inline); + mockConnectionHandler.OutputOptions = pool => new PipeOptions(pool: pool, readerScheduler: thread, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false); Task connectionTask = null; try diff --git a/test/Kestrel.Transport.Libuv.Tests/LibuvOutputConsumerTests.cs b/test/Kestrel.Transport.Libuv.Tests/LibuvOutputConsumerTests.cs index adc58f5794..3b6d6abf7c 100644 --- a/test/Kestrel.Transport.Libuv.Tests/LibuvOutputConsumerTests.cs +++ b/test/Kestrel.Transport.Libuv.Tests/LibuvOutputConsumerTests.cs @@ -69,7 +69,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests readerScheduler: _libuvThread, writerScheduler: PipeScheduler.Inline, pauseWriterThreshold: maxResponseBufferSize ?? 0, - resumeWriterThreshold: maxResponseBufferSize ?? 0 + resumeWriterThreshold: maxResponseBufferSize ?? 0, + useSynchronizationContext: false ); using (var outputProducer = CreateOutputProducer(pipeOptions)) @@ -106,7 +107,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests readerScheduler: _libuvThread, writerScheduler: PipeScheduler.Inline, pauseWriterThreshold: 0, - resumeWriterThreshold: 0 + resumeWriterThreshold: 0, + useSynchronizationContext: false ); using (var outputProducer = CreateOutputProducer(pipeOptions)) @@ -155,7 +157,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests readerScheduler: _libuvThread, writerScheduler: PipeScheduler.Inline, pauseWriterThreshold: 1, - resumeWriterThreshold: 1 + resumeWriterThreshold: 1, + useSynchronizationContext: false ); using (var outputProducer = CreateOutputProducer(pipeOptions)) @@ -212,7 +215,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests readerScheduler: _libuvThread, writerScheduler: PipeScheduler.Inline, pauseWriterThreshold: maxResponseBufferSize, - resumeWriterThreshold: maxResponseBufferSize + resumeWriterThreshold: maxResponseBufferSize, + useSynchronizationContext: false ); using (var outputProducer = CreateOutputProducer(pipeOptions)) @@ -277,7 +281,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests readerScheduler: _libuvThread, writerScheduler: PipeScheduler.Inline, pauseWriterThreshold: maxResponseBufferSize, - resumeWriterThreshold: maxResponseBufferSize + resumeWriterThreshold: maxResponseBufferSize, + useSynchronizationContext: false ); using (var outputProducer = CreateOutputProducer(pipeOptions)) @@ -348,7 +353,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests readerScheduler: _libuvThread, writerScheduler: PipeScheduler.Inline, pauseWriterThreshold: maxResponseBufferSize, - resumeWriterThreshold: maxResponseBufferSize + resumeWriterThreshold: maxResponseBufferSize, + useSynchronizationContext: false ); using (var outputProducer = CreateOutputProducer(pipeOptions, abortedSource)) @@ -442,7 +448,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests readerScheduler: _libuvThread, writerScheduler: PipeScheduler.Inline, pauseWriterThreshold: maxResponseBufferSize, - resumeWriterThreshold: maxResponseBufferSize + resumeWriterThreshold: maxResponseBufferSize, + useSynchronizationContext: false ); using (var outputProducer = CreateOutputProducer(pipeOptions)) @@ -527,7 +534,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests readerScheduler: _libuvThread, writerScheduler: PipeScheduler.Inline, pauseWriterThreshold: maxResponseBufferSize, - resumeWriterThreshold: maxResponseBufferSize + resumeWriterThreshold: maxResponseBufferSize, + useSynchronizationContext: false ); using (var outputProducer = CreateOutputProducer(pipeOptions)) @@ -610,7 +618,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests readerScheduler: _libuvThread, writerScheduler: PipeScheduler.Inline, pauseWriterThreshold: maxResponseBufferSize, - resumeWriterThreshold: maxResponseBufferSize + resumeWriterThreshold: maxResponseBufferSize, + useSynchronizationContext: false ); using (var outputProducer = CreateOutputProducer(pipeOptions)) @@ -672,7 +681,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests readerScheduler: _libuvThread, writerScheduler: PipeScheduler.Inline, pauseWriterThreshold: maxResponseBufferSize ?? 0, - resumeWriterThreshold: maxResponseBufferSize ?? 0 + resumeWriterThreshold: maxResponseBufferSize ?? 0, + useSynchronizationContext: false ); using (var outputProducer = CreateOutputProducer(pipeOptions)) diff --git a/test/Kestrel.Transport.Libuv.Tests/TestHelpers/MockConnectionHandler.cs b/test/Kestrel.Transport.Libuv.Tests/TestHelpers/MockConnectionHandler.cs index e6e8ec3738..daf6cdd27c 100644 --- a/test/Kestrel.Transport.Libuv.Tests/TestHelpers/MockConnectionHandler.cs +++ b/test/Kestrel.Transport.Libuv.Tests/TestHelpers/MockConnectionHandler.cs @@ -13,8 +13,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests.TestHelpers { public class MockConnectionHandler : IConnectionHandler { - public Func, PipeOptions> InputOptions { get; set; } = pool => new PipeOptions(pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline); - public Func, PipeOptions> OutputOptions { get; set; } = pool => new PipeOptions(pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline); + public Func, PipeOptions> InputOptions { get; set; } = pool => new PipeOptions(pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false); + public Func, PipeOptions> OutputOptions { get; set; } = pool => new PipeOptions(pool, readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false); public void OnConnection(IFeatureCollection features) { diff --git a/test/Kestrel.Transport.Sockets.FunctionalTests/TransportSelector.cs b/test/Kestrel.Transport.Sockets.FunctionalTests/TransportSelector.cs index 1a433cc9ec..52d2b0a4a8 100644 --- a/test/Kestrel.Transport.Sockets.FunctionalTests/TransportSelector.cs +++ b/test/Kestrel.Transport.Sockets.FunctionalTests/TransportSelector.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests { public static IWebHostBuilder GetWebHostBuilder() { - return new WebHostBuilder().UseSockets(); + return new WebHostBuilder().UseSockets().ConfigureServices(TestServer.RemoveDevCert); } } }