private unsafe ValueTask <int> ReadAsyncInternal(Memory <byte> destination, CancellationToken cancellationToken = default) { if (!CanRead) { ThrowHelper.ThrowNotSupportedException_UnreadableStream(); } long positionBefore = _filePosition; if (CanSeek) { long len = Length; if (positionBefore + destination.Length > len) { destination = positionBefore <= len? destination.Slice(0, (int)(len - positionBefore)) : default; } // When using overlapped IO, the OS is not supposed to // touch the file pointer location at all. We will adjust it // ourselves, but only in memory. This isn't threadsafe. _filePosition += destination.Length; } (SafeFileHandle.ValueTaskSource? vts, int errorCode) = RandomAccess.QueueAsyncReadFile(_fileHandle, destination, positionBefore, cancellationToken); return(vts != null ? new ValueTask <int>(vts, vts.Version) : (errorCode == 0) ? ValueTask.FromResult(0) : ValueTask.FromException <int>(HandleIOError(positionBefore, errorCode))); }
public override ValueTask <int> ReadAsync(Memory <byte> destination, CancellationToken cancellationToken = default) { if (!CanSeek) { return(RandomAccess.ReadAtOffsetAsync(_fileHandle, destination, fileOffset: -1, cancellationToken)); } if (LengthCachingSupported && _length >= 0 && Volatile.Read(ref _filePosition) >= _length) { // We know for sure that the file length can be safely cached and it has already been obtained. // If we have reached EOF we just return here and avoid a sys-call. return(ValueTask.FromResult(0)); } // This implementation updates the file position before the operation starts and updates it after incomplete read. // This is done to keep backward compatibility for concurrent reads. // It uses Interlocked as there can be multiple concurrent incomplete reads updating position at the same time. long readOffset = Interlocked.Add(ref _filePosition, destination.Length) - destination.Length; (SafeFileHandle.OverlappedValueTaskSource? vts, int errorCode) = RandomAccess.QueueAsyncReadFile(_fileHandle, destination, readOffset, cancellationToken, this); return(vts != null ? new ValueTask <int>(vts, vts.Version) : (errorCode == 0) ? ValueTask.FromResult(0) : ValueTask.FromException <int>(HandleIOError(readOffset, errorCode))); }