private Task<int> ReadAsyncCorePrivate(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { Debug.Assert(_handle != null, "_handle is null"); Debug.Assert(!_handle.IsClosed, "_handle is closed"); Debug.Assert(CanRead, "can't read"); Debug.Assert(buffer != null, "buffer == null"); Debug.Assert(_isAsync, "ReadAsyncCorePrivate doesn't work on synchronous file streams!"); Debug.Assert(offset >= 0, "offset is negative"); Debug.Assert(count >= 0, "count is negative"); if (buffer.Length == 0) { UpdateMessageCompletion(false); return s_zeroTask; } else { var completionSource = new PipeStreamCompletionSource(this, buffer, cancellationToken, isWrite: false); // Queue an async ReadFile operation and pass in a packed overlapped int errorCode = 0; int r; unsafe { r = ReadFileNative(_handle, buffer, offset, count, completionSource.Overlapped, out errorCode); } // ReadFile, the OS version, will return 0 on failure, but this ReadFileNative wrapper // returns -1. This will return the following: // - On error, r==-1. // - On async requests that are still pending, r==-1 w/ hr==ERROR_IO_PENDING // - On async requests that completed sequentially, r==0 // // You will NEVER RELIABLY be able to get the number of buffer read back from this call // when using overlapped structures! You must not pass in a non-null lpNumBytesRead to // ReadFile when using overlapped structures! This is by design NT behavior. if (r == -1) { switch (errorCode) { // One side has closed its handle or server disconnected. // Set the state to Broken and do some cleanup work case Interop.mincore.Errors.ERROR_BROKEN_PIPE: case Interop.mincore.Errors.ERROR_PIPE_NOT_CONNECTED: State = PipeState.Broken; unsafe { // Clear the overlapped status bit for this special case. Failure to do so looks // like we are freeing a pending overlapped. completionSource.Overlapped->InternalLow = IntPtr.Zero; } completionSource.ReleaseResources(); UpdateMessageCompletion(true); return s_zeroTask; case Interop.mincore.Errors.ERROR_IO_PENDING: break; default: throw Win32Marshal.GetExceptionForWin32Error(errorCode); } } completionSource.RegisterForCancellation(); return completionSource.Task; } }
private Task WriteAsyncCorePrivate(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { Debug.Assert(_handle != null, "_handle is null"); Debug.Assert(!_handle.IsClosed, "_handle is closed"); Debug.Assert(CanWrite, "can't write"); Debug.Assert(buffer != null, "buffer == null"); Debug.Assert(_isAsync, "WriteAsyncCorePrivate doesn't work on synchronous file streams!"); Debug.Assert(offset >= 0, "offset is negative"); Debug.Assert(count >= 0, "count is negative"); if (buffer.Length == 0) { return Task.CompletedTask; } else { var completionSource = new PipeStreamCompletionSource(this, buffer, cancellationToken, isWrite: true); int errorCode = 0; // Queue an async WriteFile operation and pass in a packed overlapped int r; unsafe { r = WriteFileNative(_handle, buffer, offset, count, completionSource.Overlapped, out errorCode); } // WriteFile, the OS version, will return 0 on failure, but this WriteFileNative // wrapper returns -1. This will return the following: // - On error, r==-1. // - On async requests that are still pending, r==-1 w/ hr==ERROR_IO_PENDING // - On async requests that completed sequentially, r==0 // // You will NEVER RELIABLY be able to get the number of buffer written back from this // call when using overlapped structures! You must not pass in a non-null // lpNumBytesWritten to WriteFile when using overlapped structures! This is by design // NT behavior. if (r == -1 && errorCode != Interop.mincore.Errors.ERROR_IO_PENDING) { completionSource.ReleaseResources(); throw WinIOError(errorCode); } completionSource.RegisterForCancellation(); return completionSource.Task; } }