-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
The documentation for NamedPipeServerStream.WaitForConnectionAsync(CancellationToken) claims the following:
Cancellation requests using the cancellation token will only work if the NamedPipeServerStream object was created with a pipe option value of PipeOptions.Asynchronous or if the cancellation occurs before the WaitForConnectionAsync method is called.
This does not appear to be true though when .NET Core is run in Unix environments. The following code snippet will hang waiting for the WaitForConnectionAsync method to complete on Unix. It does not seem to respect the cancellation request. The same code running on Windows though will properly cancel the WaitForConnectionAsync.
using System;
using System.IO.Pipes;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
using var mre = new ManualResetEvent(initialState: false);
var pipeName = Guid.NewGuid().ToString();
var cts = new CancellationTokenSource();
var task = Task.Run(async () =>
{
try
{
using var server = new NamedPipeServerStream(
pipeName,
PipeDirection.InOut,
maxNumberOfServerInstances: 10,
PipeTransmissionMode.Byte,
PipeOptions.Asynchronous);
var waitTask = server.WaitForConnectionAsync(cts.Token);
// The sync portion of WaitForConnectionAsync is the only part that
// considers the CancellationToken on Unix. Signal other thread that
// it's time to cancel.
mre.Set();
await waitTask;
Console.WriteLine($"After await waitTask");
}
catch (Exception ex)
{
Console.WriteLine($"Exception thrown {ex.Message}");
}
});
mre.WaitOne();
cts.Cancel();
Console.WriteLine("Token cancelled");
await task;
Console.WriteLine("await task complete");
}
}Looking at the WaitForConnectionAsync implementation on Unix it seems that the cancellation is simply not considered after a quick check at the start of the method.
public Task WaitForConnectionAsync(CancellationToken cancellationToken)
{
CheckConnectOperationsServer();
if (State == PipeState.Connected)
{
throw new InvalidOperationException(SR.InvalidOperation_PipeAlreadyConnected);
}
return cancellationToken.IsCancellationRequested ?
Task.FromCanceled(cancellationToken) :
WaitForConnectionAsyncCore();
async Task WaitForConnectionAsyncCore() =>
HandleAcceptedSocket(await _instance!.ListeningSocket.AcceptAsync().ConfigureAwait(false));
}Is the documentation simply out of date here and should be using and not or?