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

AnonymousPipeClientStream.ReadAsync does not seem to support cancellation #23638

Closed
tintoy opened this issue Sep 24, 2017 · 2 comments
Closed
Milestone

Comments

@tintoy
Copy link
Contributor

tintoy commented Sep 24, 2017

Hi.

After some experimentation, it seems to me that unlike NamedPipeClientStream, AnonymousPipeClientStream (or AnonymousPipeServerStream for that matter) does not support cancellation (because there's no way to open the pipe in async mode and so Stream.ReadAsync is used instead of PipeStream.ReadAsyncCore). This is a little painful because it means there's no way to "unblock" a pending read or write on that stream when the stream contains no data.

Here's a simple repro that shows what I'm trying to do. It works for named pipes, but not for anonymous ones:

NamedPipeServerStream source = new NamedPipeServerStream("pipe-test", PipeDirection.Out, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
NamedPipeClientStream destination = new NamedPipeClientStream(".", "pipe-test", PipeDirection.In, PipeOptions.Asynchronous);
await destination.ConnectAsync();

CancellationTokenSource cancellationSource = new CancellationTokenSource();

byte[] buffer = new byte[10];
Task<int> readTask = destination.ReadAsync(buffer, 0, buffer.Length, cancellationSource.Token);

// Right now, readTask is blocked waiting for data.
Task timeout = Task.Delay(TimeSpan.FromSeconds(1));
Task winner = await Task.WhenAny(readTask, timeout);
Assert.Equal(timeout, winner);

cancellationSource.Cancel();

// readTask will now fault with TaskCanceledException
timeout = Task.Delay(TimeSpan.FromSeconds(5));
winner = await Task.WhenAny(readTask, timeout);
Assert.Equal(readTask, winner);

// Prove that it was canceled via the correct CancellationToken
TaskCanceledException cancelled = await Assert.ThrowsAsync<TaskCanceledException>(() => readTask);
Assert.Equal(cancellationSource.Token, cancelled.CancellationToken);

Is this by design, or simply something nobody has gotten around to, yet? Because it looks like it should be possible to implement by constructing the base PipeStream with isAsync: true to use the correct code-path.

@pjanotti
Copy link
Contributor

pjanotti commented Oct 6, 2017

@tintoy this is a limitation of anonymous pipes in Windows:

Asynchronous (overlapped) read and write operations are not supported by anonymous pipes. This means that you cannot use the ReadFileEx and WriteFileEx functions with anonymous pipes. In addition, the lpOverlapped parameter of ReadFile and WriteFile is ignored when these functions are used with anonymous pipes.

source: https://msdn.microsoft.com/en-us/library/aa365141(VS.85).aspx

@tintoy
Copy link
Contributor Author

tintoy commented Oct 6, 2017

Ah, ok thanks - that's the missing piece of the puzzle; I'll stick to named pipes for now then :)

@tintoy tintoy closed this as completed Oct 6, 2017
@msftgits msftgits transferred this issue from dotnet/corefx Jan 31, 2020
@msftgits msftgits added this to the 2.1.0 milestone Jan 31, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 20, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants