Exemple #1
0
        private ValueTask <int> ReadAsyncCore(Memory <byte> buffer, CancellationToken cancellationToken)
        {
            var completionSource = new ReadWriteCompletionSource(this, buffer, isWrite: false);

            // Queue an async ReadFile operation and pass in a packed overlapped
            int errorCode = 0;
            int r;

            unsafe
            {
                r = ReadFileNative(_handle !, buffer.Span, 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.Errors.ERROR_BROKEN_PIPE:
                case Interop.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(new ValueTask <int>(0));

                case Interop.Errors.ERROR_IO_PENDING:
                    break;

                default:
                    throw Win32Marshal.GetExceptionForWin32Error(errorCode);
                }
            }

            completionSource.RegisterForCancellation(cancellationToken);
            return(new ValueTask <int>(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 ReadWriteCompletionSource(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);
            }
        }
        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 ReadWriteCompletionSource(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);
            }
        }