Beispiel #1
0
 private void FlushWriteBufferForWriteByte()
 {
     _asyncState?.Wait();
     try { FlushWriteBuffer(); }
     finally { _asyncState?.Release(); }
 }
        /// <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));
        }