public INonOverlappingRange Split(ulong splitAddress) { SharedMemoryMapping newRegion = new SharedMemoryMapping(splitAddress, EndAddress - splitAddress); int end = (int)((EndAddress + MappingMask) >> MappingBits); int start = (int)(Address >> MappingBits); Size = splitAddress - Address; EndAddress = splitAddress; int splitEndBlock = (int)((splitAddress + MappingMask) >> MappingBits); int splitStartBlock = (int)(splitAddress >> MappingBits); newRegion.AddBlocks(Blocks.Skip(splitStartBlock - start)); Blocks.RemoveRange(splitEndBlock - start, end - splitEndBlock); return(newRegion); }
private void Decommit(ulong address, ulong size) { (ulong granularStart, ulong granularEnd) = GetAlignedRange(address, size); ulong endAddress = address + size; lock (_lock) { int mappingCount = _mappings.FindOverlapsNonOverlapping(granularStart, granularEnd - granularStart, ref _foundMappings); int first = -1; int last = -1; for (int i = 0; i < mappingCount; i++) { SharedMemoryMapping mapping = _foundMappings[i]; if (mapping.OverlapsWith(address, size)) { if (first == -1) { first = i; } last = i; } } if (first == -1) { return; // Could not find any regions to decommit. } int lastReleasedBlock = -1; bool releasedFirst = false; bool releasedLast = false; for (int i = last; i >= first; i--) { SharedMemoryMapping mapping = _foundMappings[i]; bool releaseEnd = true; bool releaseStart = true; if (i == last) { // If this is the last region, do not release the block if there is a page ahead of us, or the block continues after us. (it is keeping the block alive) releaseEnd = last == mappingCount - 1; // If the end region starts after the decommit end address, split and readd it after modifying its base address. if (mapping.EndAddress > endAddress) { var newMapping = (SharedMemoryMapping)mapping.Split(endAddress); _mappings.UpdateEndAddress(mapping); _mappings.Add(newMapping); if ((endAddress & MappingMask) != 0) { releaseEnd = false; } } releasedLast = releaseEnd; } if (i == first) { // If this is the first region, do not release the block if there is a region behind us. (it is keeping the block alive) releaseStart = first == 0; // If the first region starts before the decommit address, split it by modifying its end address. if (mapping.Address < address) { var oldMapping = mapping; mapping = (SharedMemoryMapping)mapping.Split(address); _mappings.UpdateEndAddress(oldMapping); if ((address & MappingMask) != 0) { releaseStart = false; } } releasedFirst = releaseStart; } _mappings.Remove(mapping); ulong releasePointer = (mapping.EndAddress + MappingMask) & (~MappingMask); for (int j = mapping.Blocks.Count - 1; j >= 0; j--) { int blockId = mapping.Blocks[j]; releasePointer -= MappingGranularity; if (lastReleasedBlock == blockId) { // When committed regions are fragmented, multiple will have the same block id for their start/end granular block. // Avoid releasing these blocks twice. continue; } if ((j != 0 || releaseStart) && (j != mapping.Blocks.Count - 1 || releaseEnd)) { ReleaseBackingBlock(releasePointer, blockId); } lastReleasedBlock = blockId; } } ulong placeholderStart = (granularStart >> MappingBits) + (releasedFirst ? 0UL : 1UL); ulong placeholderEnd = (granularEnd >> MappingBits) - (releasedLast ? 0UL : 1UL); if (placeholderEnd > placeholderStart) { _placeholders.RemovePlaceholders(placeholderStart, placeholderEnd - placeholderStart, CoalescePlaceholder); } } }
private void Commit(ulong address, ulong size) { (ulong granularStart, ulong granularEnd) = GetAlignedRange(address, size); ulong endAddress = address + size; lock (_lock) { // Search a bit before and after the new mapping. // When adding our new mapping, we may need to join an existing mapping into our new mapping (or in some cases, to the other side!) ulong searchStart = granularStart == 0 ? 0 : (granularStart - 1); int mappingCount = _mappings.FindOverlapsNonOverlapping(searchStart, (granularEnd - searchStart) + 1, ref _foundMappings); int first = -1; int last = -1; SharedMemoryMapping startOverlap = null; SharedMemoryMapping endOverlap = null; int lastIndex = (int)(address >> MappingBits); int endIndex = (int)((endAddress + MappingMask) >> MappingBits); int firstBlock = -1; int endBlock = -1; for (int i = 0; i < mappingCount; i++) { SharedMemoryMapping mapping = _foundMappings[i]; if (mapping.Address < address) { if (mapping.EndAddress >= address) { startOverlap = mapping; } if ((int)((mapping.EndAddress - 1) >> MappingBits) == lastIndex) { lastIndex = (int)((mapping.EndAddress + MappingMask) >> MappingBits); firstBlock = mapping.Blocks.Last(); } } if (mapping.EndAddress > endAddress) { if (mapping.Address <= endAddress) { endOverlap = mapping; } if ((int)((mapping.Address) >> MappingBits) + 1 == endIndex) { endIndex = (int)((mapping.Address) >> MappingBits); endBlock = mapping.Blocks.First(); } } if (mapping.OverlapsWith(address, size)) { if (first == -1) { first = i; } last = i; } } if (startOverlap == endOverlap && startOverlap != null) { // Already fully committed. return; } var blocks = new List <int>(); int lastBlock = -1; if (firstBlock != -1) { blocks.Add(firstBlock); lastBlock = firstBlock; } bool hasMapped = false; Action map = () => { if (!hasMapped) { _placeholders.EnsurePlaceholders(address >> MappingBits, (granularEnd - granularStart) >> MappingBits, SplitPlaceholder); hasMapped = true; } // There's a gap between this index and the last. Allocate blocks to fill it. blocks.Add(MapBackingBlock(MappingGranularity * (ulong)lastIndex++)); }; if (first != -1) { for (int i = first; i <= last; i++) { SharedMemoryMapping mapping = _foundMappings[i]; int mapIndex = (int)(mapping.Address >> MappingBits); while (lastIndex < mapIndex) { map(); } if (lastBlock == mapping.Blocks[0]) { blocks.AddRange(mapping.Blocks.Skip(1)); } else { blocks.AddRange(mapping.Blocks); } lastIndex = (int)((mapping.EndAddress - 1) >> MappingBits) + 1; } } while (lastIndex < endIndex) { map(); } if (endBlock != -1 && endBlock != lastBlock) { blocks.Add(endBlock); } if (startOverlap != null && endOverlap != null) { // Both sides should be coalesced. Extend the start overlap to contain the end overlap, and add together their blocks. _mappings.Remove(endOverlap); startOverlap.ExtendTo(endOverlap.EndAddress, _mappings); startOverlap.AddBlocks(blocks); startOverlap.AddBlocks(endOverlap.Blocks); } else if (startOverlap != null) { startOverlap.ExtendTo(endAddress, _mappings); startOverlap.AddBlocks(blocks); } else { var mapping = new SharedMemoryMapping(address, size, blocks); if (endOverlap != null) { mapping.ExtendTo(endOverlap.EndAddress, _mappings); mapping.AddBlocks(endOverlap.Blocks); _mappings.Remove(endOverlap); } _mappings.Add(mapping); } } }