< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 79
Coverable lines: 79
Total lines: 154
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 18
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)0%220%
Dispose(...)0%660%
ReadMemoryBlockNoLock(...)0%220%
TryGetUnderlyingStream(...)100%110%
GetMemoryBlockImpl(...)0%440%
CreateMemoryMappedFileBlock(...)0%440%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/MemoryBlocks/StreamMemoryBlockProvider.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Diagnostics;
 5using System.Diagnostics.CodeAnalysis;
 6using System.IO;
 7using System.IO.MemoryMappedFiles;
 8using System.Threading;
 9
 10namespace System.Reflection.Internal
 11{
 12    /// <summary>
 13    /// Represents data read from a stream.
 14    /// </summary>
 15    /// <remarks>
 16    /// Uses memory map to load data from streams backed by files that are bigger than <see cref="MemoryMapThreshold"/>.
 17    /// </remarks>
 18    internal sealed class StreamMemoryBlockProvider : MemoryBlockProvider
 19    {
 20        // We're trying to balance total VM usage (which is a minimum of 64KB for a memory mapped file)
 21        // with private working set (since heap memory will be backed by the paging file and non-sharable).
 22        // Internal for testing.
 23        internal const int MemoryMapThreshold = 16 * 1024;
 24
 25        // The stream is user specified and might not be thread-safe.
 26        // Any read from the stream must be protected by streamGuard.
 27        private Stream _stream;
 28        private readonly object _streamGuard;
 29
 30        private readonly bool _leaveOpen;
 31        private readonly bool _useMemoryMap;
 32
 33        private readonly long _imageStart;
 34        private readonly int _imageSize;
 35
 36        private MemoryMappedFile? _lazyMemoryMap;
 37
 038        public StreamMemoryBlockProvider(Stream stream, long imageStart, int imageSize, bool leaveOpen)
 039        {
 040            Debug.Assert(stream.CanSeek && stream.CanRead);
 041            _stream = stream;
 042            _streamGuard = new object();
 043            _imageStart = imageStart;
 044            _imageSize = imageSize;
 045            _leaveOpen = leaveOpen;
 046            _useMemoryMap = stream is FileStream;
 047        }
 48
 49        protected override void Dispose(bool disposing)
 050        {
 051            Debug.Assert(disposing);
 052            if (!_leaveOpen)
 053            {
 054                Interlocked.Exchange(ref _stream, null!)?.Dispose();
 055            }
 56
 057            Interlocked.Exchange(ref _lazyMemoryMap, null)?.Dispose();
 058        }
 59
 60        public override int Size
 61        {
 62            get
 063            {
 064                return _imageSize;
 065            }
 66        }
 67
 68        /// <exception cref="IOException">Error reading from the stream.</exception>
 69        internal static unsafe NativeHeapMemoryBlock ReadMemoryBlockNoLock(Stream stream, long start, int size)
 070        {
 071            var block = new NativeHeapMemoryBlock(size);
 072            bool fault = true;
 73            try
 074            {
 075                stream.Seek(start, SeekOrigin.Begin);
 076                stream.ReadExactly(block.Pointer, size);
 77
 078                fault = false;
 079            }
 80            finally
 081            {
 082                if (fault)
 083                {
 084                    block.Dispose();
 085                }
 086            }
 87
 088            return block;
 089        }
 90
 91        public override bool TryGetUnderlyingStream([NotNullWhen(true)] out Stream? stream, out long imageStart, out int
 092        {
 093            stream = _stream;
 094            imageStart = _imageStart;
 095            imageSize = _imageSize;
 096            streamGuard = _streamGuard;
 097            return true;
 098        }
 99
 100        /// <exception cref="IOException">Error while reading from the stream.</exception>
 101        protected override AbstractMemoryBlock GetMemoryBlockImpl(int start, int size)
 0102        {
 0103            long absoluteStart = _imageStart + start;
 104
 0105            if (_useMemoryMap && size > MemoryMapThreshold)
 0106            {
 0107                return CreateMemoryMappedFileBlock(absoluteStart, size);
 108            }
 109
 0110            lock (_streamGuard)
 0111            {
 0112                return ReadMemoryBlockNoLock(_stream!, absoluteStart, size);
 113            }
 0114        }
 115
 116        /// <exception cref="IOException">IO error while mapping memory or not enough memory to create the mapping.</exc
 117        private MemoryMappedFileBlock CreateMemoryMappedFileBlock(long start, int size)
 0118        {
 0119            if (_lazyMemoryMap == null)
 0120            {
 121                // CreateMemoryMap might modify the stream (calls FileStream.Flush)
 0122                lock (_streamGuard)
 0123                {
 124                    try
 0125                    {
 126                        // leave the underlying stream open. It will be closed by the Dispose method.
 0127                        _lazyMemoryMap ??=
 0128                            MemoryMappedFile.CreateFromFile(
 0129                                fileStream: (FileStream)_stream,
 0130                                mapName: null,
 0131                                capacity: 0,
 0132                                access: MemoryMappedFileAccess.Read,
 0133                                inheritability: HandleInheritability.None,
 0134                                leaveOpen: true);
 0135                    }
 0136                    catch (UnauthorizedAccessException e)
 0137                    {
 0138                        throw new IOException(e.Message, e);
 139                    }
 0140                }
 0141            }
 142
 143            MemoryMappedViewAccessor accessor;
 144
 0145            lock (_streamGuard)
 0146            {
 0147                accessor = _lazyMemoryMap.CreateViewAccessor(start, size, MemoryMappedFileAccess.Read);
 0148            }
 149
 0150            return new MemoryMappedFileBlock(accessor, accessor.SafeMemoryMappedViewHandle, accessor.PointerOffset, size
 0151        }
 152    }
 153}
 154