|
2 | 2 | // The .NET Foundation licenses this file to you under the MIT license.
|
3 | 3 |
|
4 | 4 | using System.Diagnostics;
|
5 |
| -using System.Diagnostics.CodeAnalysis; |
6 |
| -using System.Runtime.CompilerServices; |
| 5 | +using System.Runtime.ExceptionServices; |
7 | 6 | using System.Runtime.InteropServices;
|
8 | 7 | using System.Security.AccessControl;
|
9 | 8 | using System.Security.Principal;
|
@@ -55,7 +54,7 @@ protected override void Dispose(bool disposing)
|
55 | 54 | }
|
56 | 55 | }
|
57 | 56 |
|
58 |
| - internal override void TryToReuse<TResult>(PipeValueTaskSource<TResult> source) |
| 57 | + internal override void TryToReuse(PipeValueTaskSource source) |
59 | 58 | {
|
60 | 59 | base.TryToReuse(source);
|
61 | 60 |
|
@@ -324,53 +323,49 @@ internal ExecuteHelper(PipeStreamImpersonationWorker userCode, SafePipeHandle? h
|
324 | 323 | private unsafe ValueTask WaitForConnectionCoreAsync(CancellationToken cancellationToken)
|
325 | 324 | {
|
326 | 325 | CheckConnectOperationsServerWithHandle();
|
| 326 | + Debug.Assert(IsAsync); |
327 | 327 |
|
328 |
| - if (!IsAsync) |
329 |
| - { |
330 |
| - throw new InvalidOperationException(SR.InvalidOperation_PipeNotAsync); |
331 |
| - } |
332 |
| - |
333 |
| - var valueTaskSource = Interlocked.Exchange(ref _reusableConnectionValueTaskSource, null) ?? new ConnectionValueTaskSource(this); |
| 328 | + ConnectionValueTaskSource? vts = Interlocked.Exchange(ref _reusableConnectionValueTaskSource, null) ?? new ConnectionValueTaskSource(this); |
334 | 329 | try
|
335 | 330 | {
|
336 |
| - valueTaskSource.PrepareForOperation(); |
337 |
| - if (!Interop.Kernel32.ConnectNamedPipe(InternalHandle!, valueTaskSource.Overlapped)) |
| 331 | + vts.PrepareForOperation(); |
| 332 | + if (!Interop.Kernel32.ConnectNamedPipe(InternalHandle!, vts._overlapped)) |
338 | 333 | {
|
339 | 334 | int errorCode = Marshal.GetLastPInvokeError();
|
340 |
| - |
341 | 335 | switch (errorCode)
|
342 | 336 | {
|
343 | 337 | case Interop.Errors.ERROR_IO_PENDING:
|
344 |
| - valueTaskSource.RegisterForCancellation(cancellationToken); |
| 338 | + // Common case: IO was initiated, completion will be handled by callback. |
| 339 | + // Register for cancellation now that the operation has been initiated. |
| 340 | + vts.RegisterForCancellation(cancellationToken); |
345 | 341 | break;
|
346 | 342 |
|
347 |
| - // If we are here then the pipe is already connected, or there was an error |
348 |
| - // so we should unpin and free the overlapped. |
349 | 343 | case Interop.Errors.ERROR_PIPE_CONNECTED:
|
| 344 | + // If we are here then the pipe is already connected. |
350 | 345 | // IOCompletitionCallback will not be called because we completed synchronously.
|
351 |
| - valueTaskSource.Dispose(); |
| 346 | + vts.Dispose(); |
352 | 347 | if (State == PipeState.Connected)
|
353 | 348 | {
|
354 |
| - throw new InvalidOperationException(SR.InvalidOperation_PipeAlreadyConnected); |
| 349 | + return ValueTask.FromException(ExceptionDispatchInfo.SetCurrentStackTrace(new InvalidOperationException(SR.InvalidOperation_PipeAlreadyConnected))); |
355 | 350 | }
|
356 |
| - valueTaskSource.SetCompletedSynchronously(); |
357 |
| - |
358 |
| - // We return a cached task instead of TaskCompletionSource's Task allowing the GC to collect it. |
| 351 | + State = PipeState.Connected; |
359 | 352 | return ValueTask.CompletedTask;
|
360 | 353 |
|
361 | 354 | default:
|
362 |
| - valueTaskSource.Dispose(); |
363 |
| - return ValueTask.FromException(Win32Marshal.GetExceptionForWin32Error(errorCode)); |
| 355 | + vts.Dispose(); |
| 356 | + return ValueTask.FromException(ExceptionDispatchInfo.SetCurrentStackTrace(Win32Marshal.GetExceptionForWin32Error(errorCode))); |
364 | 357 | }
|
365 | 358 | }
|
366 | 359 | }
|
367 | 360 | catch
|
368 | 361 | {
|
369 |
| - valueTaskSource.Dispose(); |
| 362 | + vts.Dispose(); |
370 | 363 | throw;
|
371 | 364 | }
|
372 | 365 |
|
373 |
| - return new ValueTask(valueTaskSource, valueTaskSource.Version); |
| 366 | + // Completion handled by callback. |
| 367 | + vts.FinishedScheduling(); |
| 368 | + return new ValueTask(vts, vts.Version); |
374 | 369 | }
|
375 | 370 |
|
376 | 371 | private void CheckConnectOperationsServerWithHandle()
|
|
0 commit comments