Esempio n. 1
0
 protected void ValidateRead(byte[] buffer, int offset, int count)
 {
     if (buffer == null)
     {
         throw new ArgumentNullException(nameof(buffer));
     }
     if (offset < 0 || count < 0)
     {
         throw new ArgumentOutOfRangeException((offset < 0 ? "offset" : "count"), SR.ArgumentOutOfRange_NeedNonNegNum);
     }
     if (buffer.Length - offset < count)
     {
         throw new ArgumentException(SR.Argument_InvalidOffLen);
     }
     Contract.EndContractBlock();
     if (!_canRead)
     {
         throw Error.GetReadNotSupported();
     }
 }
Esempio n. 2
0
        /// <summary>
        /// Asynchronously reads a sequence of bytes from the current stream and advances
        /// the position within the stream by the number of bytes read.
        /// </summary>
        /// <param name="destination">The buffer to write the data into.</param>
        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
        /// <param name="synchronousResult">If the operation completes synchronously, the number of bytes read.</param>
        /// <returns>A task that represents the asynchronous read operation.</returns>
        private Task <int> ReadAsyncInternal(Memory <byte> destination, CancellationToken cancellationToken, out int synchronousResult)
        {
            Debug.Assert(_useAsyncIO);

            if (!CanRead) // match Windows behavior; this gets thrown synchronously
            {
                throw Error.GetReadNotSupported();
            }

            // Serialize operations using the semaphore.
            Task waitTask = _asyncState.WaitAsync();

            // If we got ownership immediately, and if there's enough data in our buffer
            // to satisfy the full request of the caller, hand back the buffered data.
            // While it would be a legal implementation of the Read contract, we don't
            // hand back here less than the amount requested so as to match the behavior
            // in ReadCore that will make a native call to try to fulfill the remainder
            // of the request.
            if (waitTask.Status == TaskStatus.RanToCompletion)
            {
                int numBytesAvailable = _readLength - _readPos;
                if (numBytesAvailable >= destination.Length)
                {
                    try
                    {
                        PrepareForReading();

                        new Span <byte>(GetBuffer(), _readPos, destination.Length).CopyTo(destination.Span);
                        _readPos += destination.Length;

                        synchronousResult = destination.Length;
                        return(null);
                    }
                    catch (Exception exc)
                    {
                        synchronousResult = 0;
                        return(Task.FromException <int>(exc));
                    }
                    finally
                    {
                        _asyncState.Release();
                    }
                }
            }

            // Otherwise, issue the whole request asynchronously.
            synchronousResult  = 0;
            _asyncState.Memory = destination;
            return(waitTask.ContinueWith((t, s) =>
            {
                // The options available on Unix for writing asynchronously to an arbitrary file
                // handle typically amount to just using another thread to do the synchronous write,
                // which is exactly  what this implementation does. This does mean there are subtle
                // differences in certain FileStream behaviors between Windows and Unix when multiple
                // asynchronous operations are issued against the stream to execute concurrently; on
                // Unix the operations will be serialized due to the usage of a semaphore, but the
                // position /length information won't be updated until after the write has completed,
                // whereas on Windows it may happen before the write has completed.

                Debug.Assert(t.Status == TaskStatus.RanToCompletion);
                var thisRef = (FileStream)s;
                try
                {
                    Memory <byte> memory = thisRef._asyncState.Memory;
                    thisRef._asyncState.Memory = default(Memory <byte>);
                    return thisRef.ReadSpan(memory.Span);
                }
                finally { thisRef._asyncState.Release(); }
            }, this, CancellationToken.None, TaskContinuationOptions.DenyChildAttach, TaskScheduler.Default));
        }
Esempio n. 3
0
        /// <summary>
        /// Reads bytes from stream and puts them into the buffer
        /// </summary>
        /// <param name="buffer">Buffer to read the bytes to.</param>
        /// <param name="offset">Starting index in the buffer.</param>
        /// <param name="count">Maximum number of bytes to read.</param>
        /// <returns>Number of bytes actually read.</returns>
        public override int Read(byte[] buffer, int offset, int count)
        {
            if (buffer == null)
            {
                throw new ArgumentNullException(nameof(buffer), SR.ArgumentNull_Buffer);
            }
            if (offset < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_NeedNonNegNum);
            }
            if (count < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum);
            }
            if (buffer.Length - offset < count)
            {
                throw new ArgumentException(SR.Argument_InvalidOffLen);
            }
            Contract.EndContractBlock();  // Keep this in sync with contract validation in ReadAsync

            if (!_isOpen)
            {
                throw Error.GetStreamIsClosed();
            }
            if (!CanRead)
            {
                throw Error.GetReadNotSupported();
            }

            // Use a local variable to avoid a race where another thread
            // changes our position after we decide we can read some bytes.
            long pos = Interlocked.Read(ref _position);
            long len = Interlocked.Read(ref _length);
            long n   = len - pos;

            if (n > count)
            {
                n = count;
            }
            if (n <= 0)
            {
                return(0);
            }

            int nInt = (int)n; // Safe because n <= count, which is an Int32

            if (nInt < 0)
            {
                return(0);                                       // _position could be beyond EOF
            }
            Debug.Assert(pos + nInt >= 0, "_position + n >= 0"); // len is less than 2^63 -1.

            unsafe
            {
                fixed(byte *pBuffer = buffer)
                {
                    if (_buffer != null)
                    {
                        byte *pointer = null;

                        RuntimeHelpers.PrepareConstrainedRegions();
                        try
                        {
                            _buffer.AcquirePointer(ref pointer);
                            Buffer.Memcpy(pBuffer + offset, pointer + pos + _offset, nInt);
                        }
                        finally
                        {
                            if (pointer != null)
                            {
                                _buffer.ReleasePointer();
                            }
                        }
                    }
                    else
                    {
                        Buffer.Memcpy(pBuffer + offset, _mem + pos, nInt);
                    }
                }
            }
            Interlocked.Exchange(ref _position, pos + n);
            return(nInt);
        }
Esempio n. 4
0
 public override int Read(Span <byte> buffer) => throw Error.GetReadNotSupported();
Esempio n. 5
0
        internal int ReadCore(Span <byte> destination)
        {
            if (!_isOpen)
            {
                throw Error.GetStreamIsClosed();
            }
            if (!CanRead)
            {
                throw Error.GetReadNotSupported();
            }

            // Use a local variable to avoid a race where another thread
            // changes our position after we decide we can read some bytes.
            long pos = Interlocked.Read(ref _position);
            long len = Interlocked.Read(ref _length);
            long n   = Math.Min(len - pos, destination.Length);

            if (n <= 0)
            {
                return(0);
            }

            int nInt = (int)n; // Safe because n <= count, which is an Int32

            if (nInt < 0)
            {
                return(0);                                       // _position could be beyond EOF
            }
            Debug.Assert(pos + nInt >= 0, "_position + n >= 0"); // len is less than 2^63 -1.

            unsafe
            {
                fixed(byte *pBuffer = &destination.DangerousGetPinnableReference())
                {
                    if (_buffer != null)
                    {
                        byte *pointer = null;

                        RuntimeHelpers.PrepareConstrainedRegions();
                        try
                        {
                            _buffer.AcquirePointer(ref pointer);
                            Buffer.Memcpy(pBuffer, pointer + pos + _offset, nInt);
                        }
                        finally
                        {
                            if (pointer != null)
                            {
                                _buffer.ReleasePointer();
                            }
                        }
                    }
                    else
                    {
                        Buffer.Memcpy(pBuffer, _mem + pos, nInt);
                    }
                }
            }
            Interlocked.Exchange(ref _position, pos + n);
            return(nInt);
        }