Description
// The always synchronous data transfer between the OS and the internal buffer is intentional
// because this is needed to allow concurrent async IO requests. Concurrent data transfer
// between the OS and the internal buffer will result in race conditions. Since FlushWrite and
// FlushRead modify internal state of the stream and transfer data between the OS and the
// internal buffer, they cannot be truly async. We will, however, flush the OS file buffers
// asynchronously because it doesn't modify any internal state of the stream and is potentially
// a long running process.
try
{
FlushInternalBuffer();
}
catch (Exception e)
{
return Task.FromException(e);
}
and
private void FlushInternalBuffer()
{
AssertBufferInvariants();
if (_writePos > 0)
{
FlushWriteBuffer();
}
else if (_readPos < _readLength && CanSeek)
{
FlushReadBuffer();
}
}
This is particularly problematic when the FileStream is configured to use async I/O on Windows, as then FlushWriteBuffer needs to use sync-over-async to do the write, queueing the overlapped I/O and then blocking waiting for the operation to complete... so we have the asynchronous FlushAsync synchronously blocking waiting for the overlapped I/O to complete. Ugh.
Related to https://github.com/dotnet/corefx/issues/31914#issuecomment-427120612
Related to https://github.com/dotnet/corefx/issues/6007
Related to https://github.com/dotnet/corefx/issues/6039
Related to https://github.com/dotnet/corefx/issues/29129
Related to https://github.com/dotnet/corefx/issues/27226
cc: @JeremyKuhne, @danmosemsft