diff options
-rw-r--r-- | Ryujinx.Memory/MemoryBlock.cs | 6 | ||||
-rw-r--r-- | Ryujinx.Memory/MemoryManagement.cs | 12 | ||||
-rw-r--r-- | Ryujinx.Memory/MemoryManagementWindows.cs | 10 | ||||
-rw-r--r-- | Ryujinx.Memory/WindowsShared/PlaceholderManager.cs | 69 |
4 files changed, 76 insertions, 21 deletions
diff --git a/Ryujinx.Memory/MemoryBlock.cs b/Ryujinx.Memory/MemoryBlock.cs index c6b85b58..b68a1000 100644 --- a/Ryujinx.Memory/MemoryBlock.cs +++ b/Ryujinx.Memory/MemoryBlock.cs @@ -19,6 +19,8 @@ namespace Ryujinx.Memory private ConcurrentDictionary<MemoryBlock, byte> _viewStorages; private int _viewCount; + internal bool ForceWindows4KBView => _forceWindows4KBView; + /// <summary> /// Pointer to the memory block data. /// </summary> @@ -145,7 +147,7 @@ namespace Ryujinx.Memory srcBlock.IncrementViewCount(); } - MemoryManagement.MapView(srcBlock._sharedMemory, srcOffset, GetPointerInternal(dstOffset, size), size, _forceWindows4KBView); + MemoryManagement.MapView(srcBlock._sharedMemory, srcOffset, GetPointerInternal(dstOffset, size), size, this); } /// <summary> @@ -156,7 +158,7 @@ namespace Ryujinx.Memory /// <param name="size">Size of the range to be unmapped</param> public void UnmapView(MemoryBlock srcBlock, ulong offset, ulong size) { - MemoryManagement.UnmapView(srcBlock._sharedMemory, GetPointerInternal(offset, size), size, _forceWindows4KBView); + MemoryManagement.UnmapView(srcBlock._sharedMemory, GetPointerInternal(offset, size), size, this); } /// <summary> diff --git a/Ryujinx.Memory/MemoryManagement.cs b/Ryujinx.Memory/MemoryManagement.cs index 3b8a9664..77a8a1ef 100644 --- a/Ryujinx.Memory/MemoryManagement.cs +++ b/Ryujinx.Memory/MemoryManagement.cs @@ -68,17 +68,17 @@ namespace Ryujinx.Memory } } - public static void MapView(IntPtr sharedMemory, ulong srcOffset, IntPtr address, ulong size, bool force4KBMap) + public static void MapView(IntPtr sharedMemory, ulong srcOffset, IntPtr address, ulong size, MemoryBlock owner) { if (OperatingSystem.IsWindows()) { - if (force4KBMap) + if (owner.ForceWindows4KBView) { MemoryManagementWindows.MapView4KB(sharedMemory, srcOffset, address, (IntPtr)size); } else { - MemoryManagementWindows.MapView(sharedMemory, srcOffset, address, (IntPtr)size); + MemoryManagementWindows.MapView(sharedMemory, srcOffset, address, (IntPtr)size, owner); } } else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) @@ -91,17 +91,17 @@ namespace Ryujinx.Memory } } - public static void UnmapView(IntPtr sharedMemory, IntPtr address, ulong size, bool force4KBMap) + public static void UnmapView(IntPtr sharedMemory, IntPtr address, ulong size, MemoryBlock owner) { if (OperatingSystem.IsWindows()) { - if (force4KBMap) + if (owner.ForceWindows4KBView) { MemoryManagementWindows.UnmapView4KB(address, (IntPtr)size); } else { - MemoryManagementWindows.UnmapView(sharedMemory, address, (IntPtr)size); + MemoryManagementWindows.UnmapView(sharedMemory, address, (IntPtr)size, owner); } } else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) diff --git a/Ryujinx.Memory/MemoryManagementWindows.cs b/Ryujinx.Memory/MemoryManagementWindows.cs index 3d51b64f..6b4e7fbe 100644 --- a/Ryujinx.Memory/MemoryManagementWindows.cs +++ b/Ryujinx.Memory/MemoryManagementWindows.cs @@ -68,9 +68,9 @@ namespace Ryujinx.Memory return WindowsApi.VirtualFree(location, size, AllocationType.Decommit); } - public static void MapView(IntPtr sharedMemory, ulong srcOffset, IntPtr location, IntPtr size) + public static void MapView(IntPtr sharedMemory, ulong srcOffset, IntPtr location, IntPtr size, MemoryBlock owner) { - _placeholders.MapView(sharedMemory, srcOffset, location, size); + _placeholders.MapView(sharedMemory, srcOffset, location, size, owner); } public static void MapView4KB(IntPtr sharedMemory, ulong srcOffset, IntPtr location, IntPtr size) @@ -106,9 +106,9 @@ namespace Ryujinx.Memory } } - public static void UnmapView(IntPtr sharedMemory, IntPtr location, IntPtr size) + public static void UnmapView(IntPtr sharedMemory, IntPtr location, IntPtr size, MemoryBlock owner) { - _placeholders.UnmapView(sharedMemory, location, size); + _placeholders.UnmapView(sharedMemory, location, size, owner); } public static void UnmapView4KB(IntPtr location, IntPtr size) @@ -154,7 +154,7 @@ namespace Ryujinx.Memory } else { - _placeholders.UnmapView(IntPtr.Zero, address, size); + _placeholders.UnreserveRange((ulong)address, (ulong)size); } return WindowsApi.VirtualFree(address, IntPtr.Zero, AllocationType.Release); 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 @@ -45,19 +45,64 @@ namespace Ryujinx.Memory.WindowsShared } /// <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> /// Maps a shared memory view on a previously reserved memory region. /// </summary> /// <param name="sharedMemory">Shared memory that will be the backing storage for the view</param> /// <param name="srcOffset">Offset in the shared memory to map</param> /// <param name="location">Address to map the view into</param> /// <param name="size">Size of the view in bytes</param> - public void MapView(IntPtr sharedMemory, ulong srcOffset, IntPtr location, IntPtr size) + /// <param name="owner">Memory block that owns the mapping</param> + 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 /// <param name="sharedMemory">Shared memory that the view being unmapped belongs to</param> /// <param name="location">Address to unmap</param> /// <param name="size">Size of the region to unmap in bytes</param> - public void UnmapView(IntPtr sharedMemory, IntPtr location, IntPtr size) + /// <param name="owner">Memory block that owns the mapping</param> + 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 /// <param name="sharedMemory">Shared memory that the view being unmapped belongs to</param> /// <param name="location">Address to unmap</param> /// <param name="size">Size of the region to unmap in bytes</param> + /// <param name="owner">Memory block that owns the mapping</param> /// <exception cref="WindowsApiException">Thrown when the Windows API returns an error unmapping or remapping the memory</exception> - 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 /// </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> - private void CoalesceForUnmap(ulong address, ulong size) + /// <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(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. |