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)); }