示例#1
0
        public override IAsyncResult BeginWrite(byte[] array, int offset, int numBytes, AsyncCallback userCallback, Object stateObject)
        { 
            if (array==null)
                throw new ArgumentNullException("array"); 
            if (offset < 0) 
                throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
            if (numBytes < 0) 
                throw new ArgumentOutOfRangeException("numBytes", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
            if (array.Length - offset < numBytes)
                throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
            Contract.EndContractBlock(); 

            if (_handle.IsClosed) __Error.FileNotOpen(); 
 
#if !FEATURE_PAL && FEATURE_ASYNC_IO
            if (!_isAsync) 
                return base.BeginWrite(array, offset, numBytes, userCallback, stateObject);

            if (!CanWrite) __Error.WriteNotSupported();
 
            Contract.Assert((_readPos==0 && _readLen==0 && _writePos >= 0) || (_writePos==0 && _readPos <= _readLen), "We're either reading or writing, but not both.");
 
            if (_isPipe) { 
                // Pipes are ----ed up, at least when you have 2 different pipes
                // that you want to use simultaneously.  When redirecting stdout 
                // & stderr with the Process class, it's easy to deadlock your
                // parent & child processes when doing writes 4K at a time.  The
                // OS appears to use a 4K buffer internally.  If you write to a
                // pipe that is full, you will block until someone read from 
                // that pipe.  If you try reading from an empty pipe and
                // FileStream's BeginRead blocks waiting for data to fill it's 
                // internal buffer, you will be blocked.  In a case where a child 
                // process writes to stdout & stderr while a parent process tries
                // reading from both, you can easily get into a deadlock here. 
                // To avoid this deadlock, don't buffer when doing async IO on
                // pipes.
                Contract.Assert(_readPos == 0 && _readLen == 0, "FileStream must not have buffered data here!  Pipes should be unidirectional.");
                if (_writePos > 0) 
                    FlushWrite(false);
                return BeginWriteCore(array, offset, numBytes, userCallback, stateObject); 
            } 

            // Handle buffering. 
            FileStreamAsyncResult asyncResult;
            if (_writePos==0) {
                if (_readPos < _readLen) FlushRead();
                _readPos = 0; 
                _readLen = 0;
            } 
            int n = _bufferSize - _writePos; 
            if (numBytes <= n) {
                if (_writePos==0) _buffer = new byte[_bufferSize]; 
                Buffer.InternalBlockCopy(array, offset, _buffer, _writePos, numBytes);
                _writePos += numBytes;
                asyncResult = new FileStreamAsyncResult();
                asyncResult._userCallback = userCallback; 
                asyncResult._userStateObject = stateObject;
                asyncResult._waitHandle = null; 
                asyncResult._isWrite = true; 
                asyncResult._numBufferedBytes = numBytes;
                asyncResult.CallUserCallback(); 
                return asyncResult;
            }
            if (_writePos > 0) FlushWrite(false);
            return BeginWriteCore(array, offset, numBytes, userCallback, stateObject); 
#else
            return base.BeginWrite(array, offset, numBytes, userCallback, stateObject); 
#endif // !FEATURE_PAL && FEATURE_ASYNC_IO 
        }
示例#2
0
        unsafe private FileStreamAsyncResult BeginWriteCore(byte[] bytes, int offset, int numBytes, AsyncCallback userCallback, Object stateObject)
        { 
            Contract.Assert(!_handle.IsClosed, "!_handle.IsClosed"); 
            Contract.Assert(CanWrite, "CanWrite");
            Contract.Assert(bytes != null, "bytes != null"); 
            Contract.Assert(_readPos == _readLen, "_readPos == _readLen");
            Contract.Assert(_isAsync, "BeginWriteCore doesn't work on synchronous file streams!");
            Contract.Assert(offset >= 0, "offset is negative");
            Contract.Assert(numBytes >= 0, "numBytes is negative"); 

            // Create and store async stream class library specific data in the 
            // async result 
            FileStreamAsyncResult asyncResult = new FileStreamAsyncResult();
            asyncResult._handle = _handle; 
            asyncResult._userCallback = userCallback;
            asyncResult._userStateObject = stateObject;
            asyncResult._isWrite = true;
 
            // For Synchronous IO, I could go with either a callback and using
            // the managed Monitor class, or I could create a handle and wait on it. 
            ManualResetEvent waitHandle = new ManualResetEvent(false); 
            asyncResult._waitHandle = waitHandle;
 
            // Create a managed overlapped class
            // We will set the file offsets later
            Overlapped overlapped = new Overlapped(0, 0, IntPtr.Zero, asyncResult);
 
            // Pack the Overlapped class, and store it in the async result
            NativeOverlapped* intOverlapped; 
            if (userCallback != null) 
                intOverlapped = overlapped.Pack(IOCallback, bytes);
            else 
                intOverlapped = overlapped.UnsafePack(null, bytes);
            asyncResult._overlapped = intOverlapped;

            if (CanSeek) { 
                // Make sure we set the length of the file appropriately.
                long len = Length; 
                //Console.WriteLine("BeginWrite - Calculating end pos.  pos: "+pos+"  len: "+len+"  numBytes: "+numBytes); 

                // Make sure we are writing to the position that we think we are 
                if (_exposedHandle)
                    VerifyOSHandlePosition();

                if (_pos + numBytes > len) { 
                    //Console.WriteLine("BeginWrite - Setting length to: "+(pos + numBytes));
                    SetLengthCore(_pos + numBytes); 
                } 

                // Now set the position to read from in the NativeOverlapped struct 
                // For pipes, we should leave the offset fields set to 0.
                intOverlapped->OffsetLow = (int)_pos;
                intOverlapped->OffsetHigh = (int)(_pos>>32);
 
                // When using overlapped IO, the OS is not supposed to
                // touch the file pointer location at all.  We will adjust it 
                // ourselves.  This isn't threadsafe. 

                // 



 

 
 
                SeekCore(numBytes, SeekOrigin.Current);
            } 

            //Console.WriteLine("BeginWrite finishing.  pos: "+pos+"  numBytes: "+numBytes+"  _pos: "+_pos+"  Position: "+Position);

            int hr = 0; 
            // queue an async WriteFile operation and pass in a packed overlapped
            int r = WriteFileNative(_handle, bytes, offset, numBytes, intOverlapped, out hr); 
 
            // WriteFile, the OS version, will return 0 on failure.  But
            // my WriteFileNative wrapper returns -1.  My wrapper 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 bytes
            // written back from this call when using overlapped IO!  You must 
            // not pass in a non-null lpNumBytesWritten to WriteFile when using 
            // overlapped structures!  This is ByDesign NT behavior.
            if (r==-1 && numBytes!=-1) { 
                //Console.WriteLine("WriteFile returned 0;  Write will complete asynchronously (if hr==3e5)  hr: 0x{0:x}", hr);

                // For pipes, when they are closed on the other side, they will come here.
                if (hr == ERROR_NO_DATA) { 
                    // Not an error, but EOF.  AsyncFSCallback will NOT be
                    // called.  Call the user callback here. 
                    asyncResult.CallUserCallback(); 
                    // EndWrite will free the Overlapped struct correctly.
                } 
                else if (hr != ERROR_IO_PENDING) {
                    if (!_handle.IsClosed && CanSeek)  // Update Position - It could be anywhere.
                        SeekCore(0, SeekOrigin.Current);
 
                    if (hr == ERROR_HANDLE_EOF)
                        __Error.EndOfFile(); 
                    else 
                        __Error.WinIOError(hr, String.Empty);
                } 
            }
            else {
                // Due to a workaround for a race condition in NT's ReadFile &
                // WriteFile routines, we will always be returning 0 from WriteFileNative 
                // when we do async IO instead of the number of bytes written,
                // irregardless of whether the operation completed 
                // synchronously or asynchronously.  We absolutely must not 
                // set asyncResult._numBytes here, since will never have correct
                // results. 
                //Console.WriteLine("WriteFile returned: "+r+" (0x"+Int32.Format(r, "x")+")  The IO completed synchronously, but the user callback was called on another thread.");
            }

            return asyncResult; 
        }
示例#3
0
        unsafe private FileStreamAsyncResult BeginReadCore(byte[] bytes, int offset, int numBytes, AsyncCallback userCallback, Object stateObject, int numBufferedBytesRead)
        { 
            Contract.Assert(!_handle.IsClosed, "!_handle.IsClosed");
            Contract.Assert(CanRead, "CanRead"); 
            Contract.Assert(bytes != null, "bytes != null"); 
            Contract.Assert(_writePos == 0, "_writePos == 0");
            Contract.Assert(_isAsync, "BeginReadCore doesn't work on synchronous file streams!"); 
            Contract.Assert(offset >= 0, "offset is negative");
            Contract.Assert(numBytes >= 0, "numBytes is negative");

            // Create and store async stream class library specific data in the 
            // async result
            FileStreamAsyncResult asyncResult = new FileStreamAsyncResult(); 
            asyncResult._handle = _handle; 
            asyncResult._userCallback = userCallback;
            asyncResult._userStateObject = stateObject; 
            asyncResult._isWrite = false;

            // Must set this here to ensure all the state on the IAsyncResult
            // object is set before we call ReadFile, which gives the OS an 
            // opportunity to run our callback (including the user callback &
            // the call to EndRead) before ReadFile has returned. 
            asyncResult._numBufferedBytes = numBufferedBytesRead; 

            // For Synchronous IO, I could go with either a callback and using 
            // the managed Monitor class, or I could create a handle and wait on it.
            ManualResetEvent waitHandle = new ManualResetEvent(false);
            asyncResult._waitHandle = waitHandle;
 
            // Create a managed overlapped class
            // We will set the file offsets later 
            Overlapped overlapped = new Overlapped(0, 0, IntPtr.Zero, asyncResult); 

            // Pack the Overlapped class, and store it in the async result 
            NativeOverlapped* intOverlapped;
            if (userCallback != null)
                intOverlapped = overlapped.Pack(IOCallback, bytes);
            else 
                intOverlapped = overlapped.UnsafePack(null, bytes);
 
            asyncResult._overlapped = intOverlapped; 

            // Calculate position in the file we should be at after the read is done 
            if (CanSeek) {
                long len = Length;

                // Make sure we are reading from the position that we think we are 
                if (_exposedHandle)
                    VerifyOSHandlePosition(); 
 
                if (_pos + numBytes > len) {
                    if (_pos <= len) 
                        numBytes = (int) (len - _pos);
                    else
                        numBytes = 0;
                } 

                // Now set the position to read from in the NativeOverlapped struct 
                // For pipes, we should leave the offset fields set to 0. 
                intOverlapped->OffsetLow = unchecked((int)_pos);
                intOverlapped->OffsetHigh = (int)(_pos>>32); 

                // When using overlapped IO, the OS is not supposed to
                // touch the file pointer location at all.  We will adjust it
                // ourselves. This isn't threadsafe. 

                // WriteFile should not update the file pointer when writing 
                // in overlapped mode, according to MSDN.  But it does update 
                // the file pointer when writing to a UNC path!
                // So changed the code below to seek to an absolute 
                // location, not a relative one.  ReadFile seems consistent though.
                SeekCore(numBytes, SeekOrigin.Current);
            }
 
            // queue an async ReadFile operation and pass in a packed overlapped
            int hr = 0; 
            int r = ReadFileNative(_handle, bytes, offset, numBytes, intOverlapped, out hr); 
            // ReadFile, the OS version, will return 0 on failure.  But
            // my ReadFileNative wrapper returns -1.  My wrapper 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 bytes
            // 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 && numBytes!=-1) { 

                // For pipes, when they hit EOF, they will come here.
                if (hr == ERROR_BROKEN_PIPE) {
                    // Not an error, but EOF.  AsyncFSCallback will NOT be 
                    // called.  Call the user callback here.
 
                    // We clear the overlapped status bit for this special case. 
                    // Failure to do so looks like we are freeing a pending overlapped later.
                    intOverlapped->InternalLow = IntPtr.Zero; 
                    asyncResult.CallUserCallback();
                    // EndRead will free the Overlapped struct correctly.
                }
                else if (hr != ERROR_IO_PENDING) { 
                    if (!_handle.IsClosed && CanSeek)  // Update Position - It could be anywhere.
                        SeekCore(0, SeekOrigin.Current); 
 
                    if (hr == ERROR_HANDLE_EOF)
                        __Error.EndOfFile(); 
                    else
                        __Error.WinIOError(hr, String.Empty);
                }
            } 
            else {
                // Due to a workaround for a race condition in NT's ReadFile & 
                // WriteFile routines, we will always be returning 0 from ReadFileNative 
                // when we do async IO instead of the number of bytes read,
                // irregardless of whether the operation completed 
                // synchronously or asynchronously.  We absolutely must not
                // set asyncResult._numBytes here, since will never have correct
                // results.
                //Console.WriteLine("ReadFile returned: "+r+" (0x"+Int32.Format(r, "x")+")  The IO completed synchronously, but the user callback was called on a separate thread"); 
            }
 
            return asyncResult; 
        }