/// <summary> /// Coalesces adjacent placeholders after unmap. /// </summary> /// <param name="address">Address of the region that was unmapped</param> /// <param name="size">Size of the region that was unmapped in bytes</param> /// <param name="owner">Memory block that owns the mapping</param> private void CoalesceForUnmap(ulong address, ulong size, MemoryBlock owner) { ulong endAddress = address + size; ulong blockAddress = (ulong)owner.Pointer; ulong blockEnd = blockAddress + owner.Size; var overlaps = Array.Empty <IntervalTreeNode <ulong, ulong> >(); int unmappedCount = 0; lock (_mappings) { int count = _mappings.Get( Math.Max(address - MinimumPageSize, blockAddress), Math.Min(endAddress + MinimumPageSize, blockEnd), ref overlaps); if (count < 2) { // Nothing to coalesce if we only have 1 or no overlaps. return; } for (int index = 0; index < count; index++) { var overlap = overlaps[index]; if (!IsMapped(overlap.Value)) { if (address > overlap.Start) { address = overlap.Start; } if (endAddress < overlap.End) { endAddress = overlap.End; } _mappings.Remove(overlap); unmappedCount++; } } _mappings.Add(address, endAddress, ulong.MaxValue); } if (unmappedCount > 1) { size = endAddress - address; CheckFreeResult(WindowsApi.VirtualFree( (IntPtr)address, (IntPtr)size, AllocationType.Release | AllocationType.CoalescePlaceholders)); } }
/// <summary> /// Unreserves a range of memory that has been previously reserved with <see cref="ReserveRange"/>. /// </summary> /// <param name="address">Start address of the region to unreserve</param> /// <param name="size">Size in bytes of the region to unreserve</param> /// <exception cref="WindowsApiException">Thrown when the Windows API returns an error unreserving the memory</exception> public void UnreserveRange(ulong address, ulong size) { ulong endAddress = address + size; var overlaps = Array.Empty <IntervalTreeNode <ulong, ulong> >(); int count; lock (_mappings) { count = _mappings.Get(address, endAddress, ref overlaps); for (int index = 0; index < count; index++) { var overlap = overlaps[index]; if (IsMapped(overlap.Value)) { if (!WindowsApi.UnmapViewOfFile2(WindowsApi.CurrentProcessHandle, (IntPtr)overlap.Start, 2)) { throw new WindowsApiException("UnmapViewOfFile2"); } } _mappings.Remove(overlap); } } if (count > 1) { CheckFreeResult(WindowsApi.VirtualFree( (IntPtr)address, (IntPtr)size, AllocationType.Release | AllocationType.CoalescePlaceholders)); } RemoveProtection(address, size); }
/// <summary> /// Splits a larger placeholder, slicing at the start and end address, for a new memory mapping. /// </summary> /// <param name="address">Address to split</param> /// <param name="size">Size of the new region</param> /// <param name="backingOffset">Offset in the shared memory that will be mapped</param> private void SplitForMap(ulong address, ulong size, ulong backingOffset) { ulong endAddress = address + size; var overlaps = Array.Empty <IntervalTreeNode <ulong, ulong> >(); lock (_mappings) { int count = _mappings.Get(address, endAddress, ref overlaps); Debug.Assert(count == 1); Debug.Assert(!IsMapped(overlaps[0].Value)); var overlap = overlaps[0]; // Tree operations might modify the node start/end values, so save a copy before we modify the tree. ulong overlapStart = overlap.Start; ulong overlapEnd = overlap.End; ulong overlapValue = overlap.Value; _mappings.Remove(overlap); bool overlapStartsBefore = overlapStart < address; bool overlapEndsAfter = overlapEnd > endAddress; if (overlapStartsBefore && overlapEndsAfter) { CheckFreeResult(WindowsApi.VirtualFree( (IntPtr)address, (IntPtr)size, AllocationType.Release | AllocationType.PreservePlaceholder)); _mappings.Add(overlapStart, address, overlapValue); _mappings.Add(endAddress, overlapEnd, AddBackingOffset(overlapValue, endAddress - overlapStart)); } else if (overlapStartsBefore) { ulong overlappedSize = overlapEnd - address; CheckFreeResult(WindowsApi.VirtualFree( (IntPtr)address, (IntPtr)overlappedSize, AllocationType.Release | AllocationType.PreservePlaceholder)); _mappings.Add(overlapStart, address, overlapValue); } else if (overlapEndsAfter) { ulong overlappedSize = endAddress - overlapStart; CheckFreeResult(WindowsApi.VirtualFree( (IntPtr)overlapStart, (IntPtr)overlappedSize, AllocationType.Release | AllocationType.PreservePlaceholder)); _mappings.Add(endAddress, overlapEnd, AddBackingOffset(overlapValue, overlappedSize)); } _mappings.Add(address, endAddress, backingOffset); } }