public override Task WriteAsync(Byte[] buffer, int offset, int count, CancellationToken cancellationToken) { if (buffer == null) throw new ArgumentNullException("buffer"); if (offset < 0) throw new ArgumentOutOfRangeException("offset", SR.ArgumentOutOfRange_NeedNonNegNum); if (count < 0) throw new ArgumentOutOfRangeException("count", SR.ArgumentOutOfRange_NeedNonNegNum); if (buffer.Length - offset < count) throw new ArgumentException(SR.Argument_InvalidOffLen); Contract.EndContractBlock(); if (cancellationToken.IsCancellationRequested) { return Task.FromCanceled<int>(cancellationToken); } CheckWriteOperations(); if (!_isAsync) { return base.WriteAsync(buffer, offset, count, cancellationToken); } ReadWriteAsyncParams state = new ReadWriteAsyncParams(buffer, offset, count, cancellationToken); return Task.Factory.FromAsync(BeginWrite, EndWrite, state); }
private IAsyncResult BeginRead(AsyncCallback callback, Object state) { ReadWriteAsyncParams readWriteParams = state as ReadWriteAsyncParams; Debug.Assert(readWriteParams != null); byte[] buffer = readWriteParams.Buffer; int offset = readWriteParams.Offset; int count = readWriteParams.Count; if (buffer == null) { throw new ArgumentNullException("buffer", SR.ArgumentNull_Buffer); } if (offset < 0) { throw new ArgumentOutOfRangeException("offset", SR.ArgumentOutOfRange_NeedNonNegNum); } if (count < 0) { throw new ArgumentOutOfRangeException("count", SR.ArgumentOutOfRange_NeedNonNegNum); } if (buffer.Length - offset < count) { throw new ArgumentException(SR.Argument_InvalidOffLen); } if (!CanRead) { throw __Error.GetReadNotSupported(); } CheckReadOperations(); if (!_isAsync) { // special case when this is called for sync broken pipes because otherwise Stream's // Begin/EndRead hang. Reads return 0 bytes in this case so we can call the user's // callback immediately if (_state == PipeState.Broken) { PipeStreamAsyncResult asyncResult = new PipeStreamAsyncResult(); asyncResult._handle = _handle; asyncResult._userCallback = callback; asyncResult._userStateObject = state; asyncResult._isWrite = false; asyncResult.CallUserCallback(); return(asyncResult); } else { return(_streamAsyncHelper.BeginRead(buffer, offset, count, callback, state)); } } else { return(BeginReadCore(buffer, offset, count, callback, state)); } }
private IAsyncResult BeginWrite(AsyncCallback callback, Object state) { ReadWriteAsyncParams readWriteParams = state as ReadWriteAsyncParams; Debug.Assert(readWriteParams != null); byte[] buffer = readWriteParams.Buffer; int offset = readWriteParams.Offset; int count = readWriteParams.Count; if (buffer == null) { throw new ArgumentNullException("buffer", SR.ArgumentNull_Buffer); } if (offset < 0) { throw new ArgumentOutOfRangeException("offset", SR.ArgumentOutOfRange_NeedNonNegNum); } if (count < 0) { throw new ArgumentOutOfRangeException("count", SR.ArgumentOutOfRange_NeedNonNegNum); } if (buffer.Length - offset < count) { throw new ArgumentException(SR.Argument_InvalidOffLen); } if (!CanWrite) { throw __Error.GetWriteNotSupported(); } CheckWriteOperations(); if (!_isAsync) { return(_streamAsyncHelper.BeginWrite(buffer, offset, count, callback, state)); } else { return(BeginWriteCore(buffer, offset, count, callback, state)); } }
private unsafe int EndRead(IAsyncResult asyncResult) { // There are 3 significantly different IAsyncResults we'll accept // here. One is from Stream::BeginRead. The other two are variations // on our PipeStreamAsyncResult. One is from BeginReadCore, // while the other is from the BeginRead buffering wrapper. if (asyncResult == null) { throw new ArgumentNullException("asyncResult"); } if (!_isAsync) { return(_streamAsyncHelper.EndRead(asyncResult)); } PipeStreamAsyncResult afsar = asyncResult as PipeStreamAsyncResult; if (afsar == null || afsar._isWrite) { throw __Error.GetWrongAsyncResult(); } // Ensure we can't get into any races by doing an interlocked // CompareExchange here. Avoids corrupting memory via freeing the // NativeOverlapped class or GCHandle twice. if (1 == Interlocked.CompareExchange(ref afsar._EndXxxCalled, 1, 0)) { throw __Error.GetEndReadCalledTwice(); } ReadWriteAsyncParams readWriteParams = asyncResult.AsyncState as ReadWriteAsyncParams; IOCancellationHelper cancellationHelper = null; if (readWriteParams != null) { cancellationHelper = readWriteParams.CancellationHelper; if (cancellationHelper != null) { readWriteParams.CancellationHelper.SetOperationCompleted(); } } // Obtain the WaitHandle, but don't use public property in case we // delay initialize the manual reset event in the future. WaitHandle wh = afsar._waitHandle; if (wh != null) { // We must block to ensure that AsyncPSCallback has completed, // and we should close the WaitHandle in here. AsyncPSCallback // and the hand-ported imitation version in COMThreadPool.cpp // are the only places that set this event. using (wh) { wh.WaitOne(); Debug.Assert(afsar._isComplete == true, "FileStream::EndRead - AsyncPSCallback didn't set _isComplete to true!"); } } // Free memory & GC handles. NativeOverlapped *overlappedPtr = afsar._overlapped; if (overlappedPtr != null) { _threadPoolBinding.FreeNativeOverlapped(overlappedPtr); } // Now check for any error during the read. if (afsar._errorCode != 0) { if (afsar._errorCode == Interop.mincore.Errors.ERROR_OPERATION_ABORTED) { if (cancellationHelper != null) { cancellationHelper.ThrowIOOperationAborted(); } } WinIOError(afsar._errorCode); } // set message complete to true if the pipe is broken as well; need this to signal to readers // to stop reading _isMessageComplete = _state == PipeState.Broken || afsar._isMessageComplete; return(afsar._numBytes); }
unsafe private PipeStreamAsyncResult BeginReadCore(byte[] buffer, int offset, int count, AsyncCallback callback, Object state) { 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, "BeginReadCore doesn't work on synchronous file streams!"); Debug.Assert(offset >= 0, "offset is negative"); Debug.Assert(count >= 0, "count is negative"); // Create and store async stream class library specific data in the async result PipeStreamAsyncResult asyncResult = new PipeStreamAsyncResult(); asyncResult._handle = _handle; asyncResult._userCallback = callback; asyncResult._userStateObject = state; asyncResult._isWrite = false; // handle zero-length buffers separately; fixed keyword ReadFileNative doesn't like // 0-length buffers. Call user callback and we're done if (buffer.Length == 0) { asyncResult.CallUserCallback(); } else { // For Synchronous IO, I could go with either a userCallback and using // the managed Monitor class, or I could create a handle and wait on it. ManualResetEvent waitHandle = new ManualResetEvent(false); asyncResult._waitHandle = waitHandle; NativeOverlapped *intOverlapped = _threadPoolBinding.AllocateNativeOverlapped(s_IOCallback, asyncResult, buffer); asyncResult._overlapped = intOverlapped; // Queue an async ReadFile operation and pass in a packed overlapped int errorCode = 0; int r = ReadFileNative(_handle, buffer, offset, count, intOverlapped, 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) { // One side has closed its handle or server disconnected. Set the state to Broken // and do some cleanup work if (errorCode == Interop.mincore.Errors.ERROR_BROKEN_PIPE || errorCode == Interop.mincore.Errors.ERROR_PIPE_NOT_CONNECTED) { State = PipeState.Broken; // Clear the overlapped status bit for this special case. Failure to do so looks // like we are freeing a pending overlapped. intOverlapped->InternalLow = IntPtr.Zero; // EndRead will free the Overlapped struct asyncResult.CallUserCallback(); } else if (errorCode != Interop.mincore.Errors.ERROR_IO_PENDING) { throw Win32Marshal.GetExceptionForWin32Error(errorCode); } } ReadWriteAsyncParams readWriteParams = state as ReadWriteAsyncParams; if (readWriteParams != null) { if (readWriteParams.CancellationHelper != null) { readWriteParams.CancellationHelper.AllowCancellation(_handle, intOverlapped); } } } return(asyncResult); }
private unsafe void EndWrite(IAsyncResult asyncResult) { if (asyncResult == null) { throw new ArgumentNullException("asyncResult"); } if (!_isAsync) { _streamAsyncHelper.EndWrite(asyncResult); return; } PipeStreamAsyncResult afsar = asyncResult as PipeStreamAsyncResult; if (afsar == null || !afsar._isWrite) { throw __Error.GetWrongAsyncResult(); } // Ensure we can't get into any races by doing an interlocked // CompareExchange here. Avoids corrupting memory via freeing the // NativeOverlapped class or GCHandle twice. -- if (1 == Interlocked.CompareExchange(ref afsar._EndXxxCalled, 1, 0)) { throw __Error.GetEndWriteCalledTwice(); } ReadWriteAsyncParams readWriteParams = afsar.AsyncState as ReadWriteAsyncParams; IOCancellationHelper cancellationHelper = null; if (readWriteParams != null) { cancellationHelper = readWriteParams.CancellationHelper; if (cancellationHelper != null) { cancellationHelper.SetOperationCompleted(); } } // Obtain the WaitHandle, but don't use public property in case we // delay initialize the manual reset event in the future. WaitHandle wh = afsar._waitHandle; if (wh != null) { // We must block to ensure that AsyncPSCallback has completed, // and we should close the WaitHandle in here. AsyncPSCallback // and the hand-ported imitation version in COMThreadPool.cpp // are the only places that set this event. using (wh) { wh.WaitOne(); Debug.Assert(afsar._isComplete == true, "PipeStream::EndWrite - AsyncPSCallback didn't set _isComplete to true!"); } } // Free memory & GC handles. NativeOverlapped *overlappedPtr = afsar._overlapped; if (overlappedPtr != null) { _threadPoolBinding.FreeNativeOverlapped(overlappedPtr); } // Now check for any error during the write. if (afsar._errorCode != 0) { if (afsar._errorCode == Interop.mincore.Errors.ERROR_OPERATION_ABORTED) { if (cancellationHelper != null) { cancellationHelper.ThrowIOOperationAborted(); } } WinIOError(afsar._errorCode); } // Number of buffer written is afsar._numBytes. return; }
unsafe private PipeStreamAsyncResult BeginWriteCore(byte[] buffer, int offset, int count, AsyncCallback callback, Object state) { 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, "BeginWriteCore doesn't work on synchronous file streams!"); Debug.Assert(offset >= 0, "offset is negative"); Debug.Assert(count >= 0, "count is negative"); // Create and store async stream class library specific data in the async result PipeStreamAsyncResult asyncResult = new PipeStreamAsyncResult(); asyncResult._userCallback = callback; asyncResult._userStateObject = state; asyncResult._isWrite = true; asyncResult._handle = _handle; // fixed doesn't work well with zero length arrays. Set the zero-byte flag in case // caller needs to do any cleanup if (buffer.Length == 0) { //intOverlapped->InternalLow = IntPtr.Zero; // EndRead will free the Overlapped struct asyncResult.CallUserCallback(); } else { // For Synchronous IO, I could go with either a userCallback and using the managed // Monitor class, or I could create a handle and wait on it. ManualResetEvent waitHandle = new ManualResetEvent(false); asyncResult._waitHandle = waitHandle; NativeOverlapped *intOverlapped = _threadPoolBinding.AllocateNativeOverlapped(s_IOCallback, asyncResult, buffer); asyncResult._overlapped = intOverlapped; int errorCode = 0; // Queue an async WriteFile operation and pass in a packed overlapped int r = WriteFileNative(_handle, buffer, offset, count, intOverlapped, 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) { // Clean up if (intOverlapped != null) { _threadPoolBinding.FreeNativeOverlapped(intOverlapped); } WinIOError(errorCode); } ReadWriteAsyncParams readWriteParams = state as ReadWriteAsyncParams; if (readWriteParams != null) { if (readWriteParams.CancellationHelper != null) { readWriteParams.CancellationHelper.AllowCancellation(_handle, intOverlapped); } } } return(asyncResult); }
private Task<int> ReadAsyncCore(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { ReadWriteAsyncParams state = new ReadWriteAsyncParams(buffer, offset, count, cancellationToken); return Task.Factory.FromAsync<int>(BeginRead, EndRead, state); }
private Task <int> ReadAsyncCore(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { ReadWriteAsyncParams state = new ReadWriteAsyncParams(buffer, offset, count, cancellationToken); return(Task.Factory.FromAsync <int>(BeginRead, EndRead, state)); }