Example #1
0
        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);
                }
            }
        }
Example #2
0
        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);
                }
            }
        }