From dd8f97ab9e77dde25c323feaff97cfc8f19207fa Mon Sep 17 00:00:00 2001 From: gdkchan Date: Sun, 5 Jun 2022 15:12:42 -0300 Subject: Remove freed memory range from tree on memory block disposal (#3347) * Remove freed memory range from tree on memory block disposal * PR feedback --- Ryujinx.Memory/WindowsShared/PlaceholderManager.cs | 69 +++++++++++++++++++--- 1 file changed, 61 insertions(+), 8 deletions(-) (limited to 'Ryujinx.Memory/WindowsShared') diff --git a/Ryujinx.Memory/WindowsShared/PlaceholderManager.cs b/Ryujinx.Memory/WindowsShared/PlaceholderManager.cs index d465f341..1b425d66 100644 --- a/Ryujinx.Memory/WindowsShared/PlaceholderManager.cs +++ b/Ryujinx.Memory/WindowsShared/PlaceholderManager.cs @@ -44,6 +44,50 @@ namespace Ryujinx.Memory.WindowsShared } } + /// + /// Unreserves a range of memory that has been previously reserved with . + /// + /// Start address of the region to unreserve + /// Size in bytes of the region to unreserve + /// Thrown when the Windows API returns an error unreserving the memory + public void UnreserveRange(ulong address, ulong size) + { + ulong endAddress = address + size; + + var overlaps = Array.Empty>(); + 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); + } + /// /// Maps a shared memory view on a previously reserved memory region. /// @@ -51,13 +95,14 @@ namespace Ryujinx.Memory.WindowsShared /// Offset in the shared memory to map /// Address to map the view into /// Size of the view in bytes - public void MapView(IntPtr sharedMemory, ulong srcOffset, IntPtr location, IntPtr size) + /// Memory block that owns the mapping + public void MapView(IntPtr sharedMemory, ulong srcOffset, IntPtr location, IntPtr size, MemoryBlock owner) { _partialUnmapLock.AcquireReaderLock(Timeout.Infinite); try { - UnmapViewInternal(sharedMemory, location, size); + UnmapViewInternal(sharedMemory, location, size, owner); MapViewInternal(sharedMemory, srcOffset, location, size); } finally @@ -173,13 +218,14 @@ namespace Ryujinx.Memory.WindowsShared /// Shared memory that the view being unmapped belongs to /// Address to unmap /// Size of the region to unmap in bytes - public void UnmapView(IntPtr sharedMemory, IntPtr location, IntPtr size) + /// Memory block that owns the mapping + public void UnmapView(IntPtr sharedMemory, IntPtr location, IntPtr size, MemoryBlock owner) { _partialUnmapLock.AcquireReaderLock(Timeout.Infinite); try { - UnmapViewInternal(sharedMemory, location, size); + UnmapViewInternal(sharedMemory, location, size, owner); } finally { @@ -197,8 +243,9 @@ namespace Ryujinx.Memory.WindowsShared /// Shared memory that the view being unmapped belongs to /// Address to unmap /// Size of the region to unmap in bytes + /// Memory block that owns the mapping /// Thrown when the Windows API returns an error unmapping or remapping the memory - private void UnmapViewInternal(IntPtr sharedMemory, IntPtr location, IntPtr size) + private void UnmapViewInternal(IntPtr sharedMemory, IntPtr location, IntPtr size, MemoryBlock owner) { ulong startAddress = (ulong)location; ulong unmapSize = (ulong)size; @@ -272,7 +319,7 @@ namespace Ryujinx.Memory.WindowsShared } } - CoalesceForUnmap(startAddress, unmapSize); + CoalesceForUnmap(startAddress, unmapSize, owner); RemoveProtection(startAddress, unmapSize); } @@ -281,15 +328,21 @@ namespace Ryujinx.Memory.WindowsShared /// /// Address of the region that was unmapped /// Size of the region that was unmapped in bytes - private void CoalesceForUnmap(ulong address, ulong size) + /// Memory block that owns the mapping + 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>(); int unmappedCount = 0; lock (_mappings) { - int count = _mappings.Get(address - MinimumPageSize, endAddress + MinimumPageSize, ref overlaps); + 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. -- cgit v1.2.3