/// <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> /// Adds a protection to the list of protections. /// </summary> /// <param name="address">Address of the protected region</param> /// <param name="size">Size of the protected region in bytes</param> /// <param name="permission">Memory permissions of the region</param> private void AddProtection(ulong address, ulong size, MemoryPermission permission) { ulong endAddress = address + size; var overlaps = Array.Empty <IntervalTreeNode <ulong, MemoryPermission> >(); int count = 0; lock (_protections) { count = _protections.Get(address, endAddress, ref overlaps); Debug.Assert(count > 0); if (count == 1 && overlaps[0].Start <= address && overlaps[0].End >= endAddress && overlaps[0].Value == permission) { return; } ulong startAddress = address; for (int index = 0; index < count; index++) { var protection = overlaps[index]; ulong protAddress = protection.Start; ulong protEndAddress = protection.End; MemoryPermission protPermission = protection.Value; _protections.Remove(protection); if (protection.Value == permission) { if (startAddress > protAddress) { startAddress = protAddress; } if (endAddress < protEndAddress) { endAddress = protEndAddress; } } else { if (startAddress > protAddress) { _protections.Add(protAddress, startAddress, protPermission); } if (endAddress < protEndAddress) { _protections.Add(endAddress, protEndAddress, protPermission); } } } _protections.Add(startAddress, endAddress, permission); } }
/// <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); } }