Error concurrent reads gracefully
This commit is contained in:
parent
90ece575f7
commit
9e8b07ecf8
|
|
@ -216,8 +216,16 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// THIS IS AN ERROR STATE - ONLY ONE WAITER CAN WAIT
|
_awaitableError = new InvalidOperationException("Concurrent reads are not supported.");
|
||||||
throw new InvalidOperationException("Concurrent reads are not supported.");
|
|
||||||
|
awaitableState = Interlocked.Exchange(
|
||||||
|
ref _awaitableState,
|
||||||
|
_awaitableIsCompleted);
|
||||||
|
|
||||||
|
_manualResetEvent.Set();
|
||||||
|
|
||||||
|
_threadPool.Run(continuation);
|
||||||
|
_threadPool.Run(awaitableState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Server.Kestrel;
|
||||||
|
using Microsoft.AspNet.Server.Kestrel.Http;
|
||||||
|
using Microsoft.AspNet.Server.Kestrel.Infrastructure;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Server.KestrelTests
|
||||||
|
{
|
||||||
|
public class SocketInputTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task ConcurrentReadsFailGracefully()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var trace = new KestrelTrace(new TestKestrelTrace());
|
||||||
|
var ltp = new LoggingThreadPool(trace);
|
||||||
|
using (var memory2 = new MemoryPool2())
|
||||||
|
{
|
||||||
|
var socketInput = new SocketInput(memory2, ltp);
|
||||||
|
|
||||||
|
var task0Threw = false;
|
||||||
|
var task1Threw = false;
|
||||||
|
var task2Threw = false;
|
||||||
|
|
||||||
|
|
||||||
|
var task0 = AwaitAsTaskAsync(socketInput);
|
||||||
|
|
||||||
|
Assert.False(task0.IsFaulted);
|
||||||
|
|
||||||
|
var task = task0.ContinueWith(
|
||||||
|
(t) =>
|
||||||
|
{
|
||||||
|
TestConcurrentFaultedTask(t);
|
||||||
|
task0Threw = true;
|
||||||
|
},
|
||||||
|
TaskContinuationOptions.OnlyOnFaulted);
|
||||||
|
|
||||||
|
Assert.False(task0.IsFaulted);
|
||||||
|
|
||||||
|
// Awaiting/continuing two tasks faults both
|
||||||
|
|
||||||
|
var task1 = AwaitAsTaskAsync(socketInput);
|
||||||
|
|
||||||
|
await task1.ContinueWith(
|
||||||
|
(t) =>
|
||||||
|
{
|
||||||
|
TestConcurrentFaultedTask(t);
|
||||||
|
task1Threw = true;
|
||||||
|
},
|
||||||
|
TaskContinuationOptions.OnlyOnFaulted);
|
||||||
|
|
||||||
|
await task;
|
||||||
|
|
||||||
|
Assert.True(task0.IsFaulted);
|
||||||
|
Assert.True(task1.IsFaulted);
|
||||||
|
|
||||||
|
Assert.True(task0Threw);
|
||||||
|
Assert.True(task1Threw);
|
||||||
|
|
||||||
|
// socket stays faulted
|
||||||
|
|
||||||
|
var task2 = AwaitAsTaskAsync(socketInput);
|
||||||
|
|
||||||
|
await task2.ContinueWith(
|
||||||
|
(t) =>
|
||||||
|
{
|
||||||
|
TestConcurrentFaultedTask(t);
|
||||||
|
task2Threw = true;
|
||||||
|
},
|
||||||
|
TaskContinuationOptions.OnlyOnFaulted);
|
||||||
|
|
||||||
|
Assert.True(task2.IsFaulted);
|
||||||
|
Assert.True(task2Threw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void TestConcurrentFaultedTask(Task t)
|
||||||
|
{
|
||||||
|
Assert.True(t.IsFaulted);
|
||||||
|
Assert.IsType(typeof(System.IO.IOException), t.Exception.InnerException);
|
||||||
|
Assert.Equal(t.Exception.InnerException.Message, "Concurrent reads are not supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task AwaitAsTaskAsync(SocketInput socketInput)
|
||||||
|
{
|
||||||
|
await socketInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue