Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose SocketAsyncEventArgs constructor for suppressing the execution context #706

Merged
merged 3 commits into from
Dec 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/libraries/System.Net.Sockets/ref/System.Net.Sockets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ public void Shutdown(System.Net.Sockets.SocketShutdown how) { }
public partial class SocketAsyncEventArgs : System.EventArgs, System.IDisposable
{
public SocketAsyncEventArgs() { }
public SocketAsyncEventArgs(bool unsafeSuppressExecutionContextFlow) { }
public System.Net.Sockets.Socket AcceptSocket { get { throw null; } set { } }
public byte[] Buffer { get { throw null; } }
public System.Collections.Generic.IList<System.ArraySegment<byte>> BufferList { get { throw null; } set { } }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -782,7 +782,7 @@ private class TaskSocketAsyncEventArgs<TResult> : SocketAsyncEventArgs
internal bool _accessed = false;

internal TaskSocketAsyncEventArgs() :
base(flowExecutionContext: false) // avoid flowing context at lower layers as we only expose Task, which handles it
base(unsafeSuppressExecutionContextFlow: true) // avoid flowing context at lower layers as we only expose Task, which handles it
{
}

Expand Down Expand Up @@ -836,7 +836,7 @@ internal sealed class AwaitableSocketAsyncEventArgs : SocketAsyncEventArgs, IVal

/// <summary>Initializes the event args.</summary>
public AwaitableSocketAsyncEventArgs() :
base(flowExecutionContext: false) // avoid flowing context at lower layers as we only expose ValueTask, which handles it
base(unsafeSuppressExecutionContextFlow: true) // avoid flowing context at lower layers as we only expose ValueTask, which handles it
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,18 +83,18 @@ public partial class SocketAsyncEventArgs : EventArgs, IDisposable

private MultipleConnectAsync _multipleConnect;

public SocketAsyncEventArgs() : this(flowExecutionContext: true)
public SocketAsyncEventArgs() : this(unsafeSuppressExecutionContextFlow: false)
{
}

/// <summary>Initialize the SocketAsyncEventArgs</summary>
/// <param name="flowExecutionContext">
/// Whether to capture and flow ExecutionContext. ExecutionContext flow should only
/// <param name="unsafeSuppressExecutionContextFlow">
/// Whether to disable the capturing and flow of ExecutionContext. ExecutionContext flow should only
/// be disabled if it's going to be handled by higher layers.
/// </param>
internal SocketAsyncEventArgs(bool flowExecutionContext)
public SocketAsyncEventArgs(bool unsafeSuppressExecutionContextFlow)
{
_flowExecutionContext = flowExecutionContext;
_flowExecutionContext = !unsafeSuppressExecutionContextFlow;
InitializeInternals();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,58 @@ await Task.WhenAll(
}
}

[Fact]
public async Task ExecutionContext_SocketAsyncEventArgs_Ctor_Default_FlowIsNotSuppressed()
{
await ExecutionContext_SocketAsyncEventArgs_Ctors(() => new SocketAsyncEventArgs(), false);
}

[Theory]
[InlineData(true)]
[InlineData(false)]
public async Task ExecutionContext_SocketAsyncEventArgs_Ctor_UnsafeSuppressExecutionContextFlow(bool suppressed)
{
await ExecutionContext_SocketAsyncEventArgs_Ctors(() => new SocketAsyncEventArgs(suppressed), suppressed);
}

private async Task ExecutionContext_SocketAsyncEventArgs_Ctors(Func<SocketAsyncEventArgs> saeaFactory, bool suppressed)
{
using (var listen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
listen.Bind(new IPEndPoint(IPAddress.Loopback, 0));
listen.Listen(1);

Task<Socket> acceptTask = listen.AcceptAsync();
await Task.WhenAll(
acceptTask,
client.ConnectAsync(new IPEndPoint(IPAddress.Loopback, ((IPEndPoint)listen.LocalEndPoint).Port)));

using (Socket server = await acceptTask)
using (SocketAsyncEventArgs receiveSaea = saeaFactory())
{
var local = new AsyncLocal<int>
{
Value = 42
};
int threadId = Environment.CurrentManagedThreadId;

var mres = new ManualResetEventSlim();
receiveSaea.SetBuffer(new byte[1], 0, 1);
receiveSaea.Completed += delegate
{
Assert.NotEqual(threadId, Environment.CurrentManagedThreadId);
Assert.Equal(suppressed ? 0 : 42, local.Value);
mres.Set();
};

Assert.True(client.ReceiveAsync(receiveSaea));
server.Send(new byte[1]);
mres.Wait();
}
}
}

[Fact]
public void SetBuffer_InvalidArgs_Throws()
{
Expand Down Expand Up @@ -390,7 +442,7 @@ await Task.WhenAll(

var args = new SocketAsyncEventArgs();
args.SetBuffer(new byte[1024], 0, 1024);
args.Completed += (_,__) => tcs.SetResult(true);
args.Completed += (_, __) => tcs.SetResult(true);

for (int i = 1; i <= 10; i++)
{
Expand Down Expand Up @@ -439,14 +491,14 @@ await Task.WhenAll(
sendBufferList.Add(new ArraySegment<byte>(sendBuffer, 0, 1));
var sendArgs = new SocketAsyncEventArgs();
sendArgs.BufferList = sendBufferList;
sendArgs.Completed += (_,__) => tcs.SetResult(true);
sendArgs.Completed += (_, __) => tcs.SetResult(true);

var recvBuffer = new byte[64];
var recvBufferList = new List<ArraySegment<byte>>();
recvBufferList.Add(new ArraySegment<byte>(recvBuffer, 0, 1));
var recvArgs = new SocketAsyncEventArgs();
recvArgs.BufferList = recvBufferList;
recvArgs.Completed += (_,__) => tcs.SetResult(true);
recvArgs.Completed += (_, __) => tcs.SetResult(true);

for (int i = 1; i <= 10; i++)
{
Expand Down