Created
July 31, 2020 16:27
-
-
Save antonfirsov/b5deb76ebdc342f6f085206632c47c69 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using System.Threading; | |
using System.Threading.Tasks; | |
using Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework.Utilities; | |
using Xunit; | |
using Xunit.Abstractions; | |
namespace System.Net.Sockets.Tests | |
{ | |
public class Repro31570 : SocketTestHelperBase<SocketHelperEap> | |
{ | |
public Repro31570(ITestOutputHelper output) : base(output) | |
{ | |
} | |
public static TheoryData<int> GetDisposeAfterData() | |
{ | |
TheoryData<int> result = new TheoryData<int>(); | |
for (int i = 0; i < 10; i++) | |
{ | |
result.Add(8000 + 2 * i); | |
} | |
return result; | |
} | |
[Theory(Timeout = 5000)] | |
[MemberData(nameof(GetDisposeAfterData))] | |
public async Task ReproMaybe(int disposeAfterReceives) | |
{ | |
byte[] sendBuffer = new byte[512]; | |
byte[] receiveBuffer = new byte[512]; | |
// We need to send enough messages to make sure the OS will stop processing them synchronously, | |
// so the PAL will actually start queuing BufferMemoryReceiveOperation | |
int msgCount = 10000; | |
(Socket client, Socket server) = SocketTestExtensions.CreateConnectedSocketPair(); | |
List<Task> allTasks = new List<Task>(); | |
List<Task> receiveTasks = new List<Task>(); | |
ManualResetEventSlim shouldDisposeNow = new ManualResetEventSlim(); | |
Task disposeTask = Task.Factory.StartNew(() => | |
{ | |
shouldDisposeNow.Wait(); | |
Thread.Sleep(1); | |
client.Shutdown(SocketShutdown.Both); | |
client.Close(15); | |
}, TaskCreationOptions.LongRunning); | |
for (int i = 0; i < msgCount; i++) | |
{ | |
Task sendTask = SendAsync(server, sendBuffer); | |
allTasks.Add(sendTask); | |
} | |
for (int i = 0; i < msgCount; i++) | |
{ | |
if (client.SafeHandle.IsClosed) | |
{ | |
break; | |
} | |
Task receiveTask = null; | |
try | |
{ | |
receiveTask = ReceiveAsync(client, receiveBuffer); | |
} | |
catch (ObjectDisposedException) | |
{ | |
Console.WriteLine("Disposed. good!"); | |
break; | |
} | |
// Sufficient number of receives is completed, and we are sure BufferMemoryReceiveOperations are being queued, | |
// So we try to disturb the execution of a follow-up receive by a sudden disposal: | |
if (i == disposeAfterReceives) | |
{ | |
if (receiveTask.IsCompleted) | |
{ | |
Console.WriteLine($"Firing the dispose @ {i} [sync]"); | |
shouldDisposeNow.Set(); | |
} | |
else | |
{ | |
receiveTask.GetAwaiter().OnCompleted(() => | |
{ | |
Console.WriteLine($"Firing dispose @ {i} [async]"); | |
shouldDisposeNow.Set(); | |
}); | |
} | |
} | |
allTasks.Add(receiveTask); | |
receiveTasks.Add(receiveTask); | |
} | |
try | |
{ | |
await Task.WhenAll(receiveTasks); | |
} | |
catch (Exception ex) | |
{ | |
Console.WriteLine($"Got exception: {ex.GetType()} | {ex.Message}"); | |
Console.WriteLine(ex.StackTrace); | |
} | |
client.Dispose(); | |
server.Dispose(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment