diff options
Diffstat (limited to 'Ryujinx.Memory')
| -rw-r--r-- | Ryujinx.Memory/MemoryAllocationFlags.cs | 8 | ||||
| -rw-r--r-- | Ryujinx.Memory/MemoryBlock.cs | 10 | ||||
| -rw-r--r-- | Ryujinx.Memory/MemoryManagement.cs | 37 | ||||
| -rw-r--r-- | Ryujinx.Memory/MemoryManagementWindows.cs | 80 | ||||
| -rw-r--r-- | Ryujinx.Memory/Tracking/MemoryTracking.cs | 30 | ||||
| -rw-r--r-- | Ryujinx.Memory/WindowsShared/PlaceholderManager.cs | 139 | ||||
| -rw-r--r-- | Ryujinx.Memory/WindowsShared/PlaceholderManager4KB.cs | 170 | ||||
| -rw-r--r-- | Ryujinx.Memory/WindowsShared/WindowsApi.cs | 3 |
8 files changed, 100 insertions, 377 deletions
diff --git a/Ryujinx.Memory/MemoryAllocationFlags.cs b/Ryujinx.Memory/MemoryAllocationFlags.cs index 8706a25b..313f33e5 100644 --- a/Ryujinx.Memory/MemoryAllocationFlags.cs +++ b/Ryujinx.Memory/MemoryAllocationFlags.cs @@ -35,12 +35,6 @@ namespace Ryujinx.Memory /// Indicates that the memory block should support mapping views of a mirrorable memory block. /// The block that is to have their views mapped should be created with the <see cref="Mirrorable"/> flag. /// </summary> - ViewCompatible = 1 << 3, - - /// <summary> - /// Forces views to be mapped page by page on Windows. When partial unmaps are done, this avoids the need - /// to unmap the full range and remap sub-ranges, which creates a time window with incorrectly unmapped memory. - /// </summary> - ForceWindows4KBViewMapping = 1 << 4 + ViewCompatible = 1 << 3 } } diff --git a/Ryujinx.Memory/MemoryBlock.cs b/Ryujinx.Memory/MemoryBlock.cs index b68a1000..79a5cfe7 100644 --- a/Ryujinx.Memory/MemoryBlock.cs +++ b/Ryujinx.Memory/MemoryBlock.cs @@ -13,14 +13,11 @@ namespace Ryujinx.Memory private readonly bool _usesSharedMemory; private readonly bool _isMirror; private readonly bool _viewCompatible; - private readonly bool _forceWindows4KBView; private IntPtr _sharedMemory; private IntPtr _pointer; private ConcurrentDictionary<MemoryBlock, byte> _viewStorages; private int _viewCount; - internal bool ForceWindows4KBView => _forceWindows4KBView; - /// <summary> /// Pointer to the memory block data. /// </summary> @@ -49,8 +46,7 @@ namespace Ryujinx.Memory else if (flags.HasFlag(MemoryAllocationFlags.Reserve)) { _viewCompatible = flags.HasFlag(MemoryAllocationFlags.ViewCompatible); - _forceWindows4KBView = flags.HasFlag(MemoryAllocationFlags.ForceWindows4KBViewMapping); - _pointer = MemoryManagement.Reserve(size, _viewCompatible, _forceWindows4KBView); + _pointer = MemoryManagement.Reserve(size, _viewCompatible); } else { @@ -173,7 +169,7 @@ namespace Ryujinx.Memory /// <exception cref="MemoryProtectionException">Throw when <paramref name="permission"/> is invalid</exception> public void Reprotect(ulong offset, ulong size, MemoryPermission permission, bool throwOnFail = true) { - MemoryManagement.Reprotect(GetPointerInternal(offset, size), size, permission, _viewCompatible, _forceWindows4KBView, throwOnFail); + MemoryManagement.Reprotect(GetPointerInternal(offset, size), size, permission, _viewCompatible, throwOnFail); } /// <summary> @@ -406,7 +402,7 @@ namespace Ryujinx.Memory } else { - MemoryManagement.Free(ptr, Size, _forceWindows4KBView); + MemoryManagement.Free(ptr, Size); } foreach (MemoryBlock viewStorage in _viewStorages.Keys) diff --git a/Ryujinx.Memory/MemoryManagement.cs b/Ryujinx.Memory/MemoryManagement.cs index 77a8a1ef..7c042eba 100644 --- a/Ryujinx.Memory/MemoryManagement.cs +++ b/Ryujinx.Memory/MemoryManagement.cs @@ -20,11 +20,11 @@ namespace Ryujinx.Memory } } - public static IntPtr Reserve(ulong size, bool viewCompatible, bool force4KBMap) + public static IntPtr Reserve(ulong size, bool viewCompatible) { if (OperatingSystem.IsWindows()) { - return MemoryManagementWindows.Reserve((IntPtr)size, viewCompatible, force4KBMap); + return MemoryManagementWindows.Reserve((IntPtr)size, viewCompatible); } else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) { @@ -72,14 +72,7 @@ namespace Ryujinx.Memory { if (OperatingSystem.IsWindows()) { - if (owner.ForceWindows4KBView) - { - MemoryManagementWindows.MapView4KB(sharedMemory, srcOffset, address, (IntPtr)size); - } - else - { - MemoryManagementWindows.MapView(sharedMemory, srcOffset, address, (IntPtr)size, owner); - } + MemoryManagementWindows.MapView(sharedMemory, srcOffset, address, (IntPtr)size, owner); } else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) { @@ -95,14 +88,7 @@ namespace Ryujinx.Memory { if (OperatingSystem.IsWindows()) { - if (owner.ForceWindows4KBView) - { - MemoryManagementWindows.UnmapView4KB(address, (IntPtr)size); - } - else - { - MemoryManagementWindows.UnmapView(sharedMemory, address, (IntPtr)size, owner); - } + MemoryManagementWindows.UnmapView(sharedMemory, address, (IntPtr)size, owner); } else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) { @@ -114,20 +100,13 @@ namespace Ryujinx.Memory } } - public static void Reprotect(IntPtr address, ulong size, MemoryPermission permission, bool forView, bool force4KBMap, bool throwOnFail) + public static void Reprotect(IntPtr address, ulong size, MemoryPermission permission, bool forView, bool throwOnFail) { bool result; if (OperatingSystem.IsWindows()) { - if (forView && force4KBMap) - { - result = MemoryManagementWindows.Reprotect4KB(address, (IntPtr)size, permission, forView); - } - else - { - result = MemoryManagementWindows.Reprotect(address, (IntPtr)size, permission, forView); - } + result = MemoryManagementWindows.Reprotect(address, (IntPtr)size, permission, forView); } else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) { @@ -144,11 +123,11 @@ namespace Ryujinx.Memory } } - public static bool Free(IntPtr address, ulong size, bool force4KBMap) + public static bool Free(IntPtr address, ulong size) { if (OperatingSystem.IsWindows()) { - return MemoryManagementWindows.Free(address, (IntPtr)size, force4KBMap); + return MemoryManagementWindows.Free(address, (IntPtr)size); } else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) { diff --git a/Ryujinx.Memory/MemoryManagementWindows.cs b/Ryujinx.Memory/MemoryManagementWindows.cs index 6b4e7fbe..2f89a921 100644 --- a/Ryujinx.Memory/MemoryManagementWindows.cs +++ b/Ryujinx.Memory/MemoryManagementWindows.cs @@ -10,23 +10,19 @@ namespace Ryujinx.Memory public const int PageSize = 0x1000; private static readonly PlaceholderManager _placeholders = new PlaceholderManager(); - private static readonly PlaceholderManager4KB _placeholders4KB = new PlaceholderManager4KB(); public static IntPtr Allocate(IntPtr size) { return AllocateInternal(size, AllocationType.Reserve | AllocationType.Commit); } - public static IntPtr Reserve(IntPtr size, bool viewCompatible, bool force4KBMap) + public static IntPtr Reserve(IntPtr size, bool viewCompatible) { if (viewCompatible) { IntPtr baseAddress = AllocateInternal2(size, AllocationType.Reserve | AllocationType.ReservePlaceholder); - if (!force4KBMap) - { - _placeholders.ReserveRange((ulong)baseAddress, (ulong)size); - } + _placeholders.ReserveRange((ulong)baseAddress, (ulong)size); return baseAddress; } @@ -73,49 +69,11 @@ namespace Ryujinx.Memory _placeholders.MapView(sharedMemory, srcOffset, location, size, owner); } - public static void MapView4KB(IntPtr sharedMemory, ulong srcOffset, IntPtr location, IntPtr size) - { - _placeholders4KB.UnmapAndMarkRangeAsMapped(location, size); - - ulong uaddress = (ulong)location; - ulong usize = (ulong)size; - IntPtr endLocation = (IntPtr)(uaddress + usize); - - while (location != endLocation) - { - WindowsApi.VirtualFree(location, (IntPtr)PageSize, AllocationType.Release | AllocationType.PreservePlaceholder); - - var ptr = WindowsApi.MapViewOfFile3( - sharedMemory, - WindowsApi.CurrentProcessHandle, - location, - srcOffset, - (IntPtr)PageSize, - 0x4000, - MemoryProtection.ReadWrite, - IntPtr.Zero, - 0); - - if (ptr == IntPtr.Zero) - { - throw new WindowsApiException("MapViewOfFile3"); - } - - location += PageSize; - srcOffset += PageSize; - } - } - public static void UnmapView(IntPtr sharedMemory, IntPtr location, IntPtr size, MemoryBlock owner) { _placeholders.UnmapView(sharedMemory, location, size, owner); } - public static void UnmapView4KB(IntPtr location, IntPtr size) - { - _placeholders4KB.UnmapView(location, size); - } - public static bool Reprotect(IntPtr address, IntPtr size, MemoryPermission permission, bool forView) { if (forView) @@ -128,34 +86,9 @@ namespace Ryujinx.Memory } } - public static bool Reprotect4KB(IntPtr address, IntPtr size, MemoryPermission permission, bool forView) + public static bool Free(IntPtr address, IntPtr size) { - ulong uaddress = (ulong)address; - ulong usize = (ulong)size; - while (usize > 0) - { - if (!WindowsApi.VirtualProtect((IntPtr)uaddress, (IntPtr)PageSize, WindowsApi.GetProtection(permission), out _)) - { - return false; - } - - uaddress += PageSize; - usize -= PageSize; - } - - return true; - } - - public static bool Free(IntPtr address, IntPtr size, bool force4KBMap) - { - if (force4KBMap) - { - _placeholders4KB.UnmapRange(address, size); - } - else - { - _placeholders.UnreserveRange((ulong)address, (ulong)size); - } + _placeholders.UnreserveRange((ulong)address, (ulong)size); return WindowsApi.VirtualFree(address, IntPtr.Zero, AllocationType.Release); } @@ -207,10 +140,5 @@ namespace Ryujinx.Memory throw new ArgumentException("Invalid address.", nameof(address)); } } - - public static bool RetryFromAccessViolation() - { - return _placeholders.RetryFromAccessViolation(); - } } }
\ No newline at end of file diff --git a/Ryujinx.Memory/Tracking/MemoryTracking.cs b/Ryujinx.Memory/Tracking/MemoryTracking.cs index c5abb576..ec75e3d0 100644 --- a/Ryujinx.Memory/Tracking/MemoryTracking.cs +++ b/Ryujinx.Memory/Tracking/MemoryTracking.cs @@ -190,30 +190,6 @@ namespace Ryujinx.Memory.Tracking /// <summary> /// Signal that a virtual memory event happened at the given location. - /// This is similar VirtualMemoryEvent, but on Windows, it might also return true after a partial unmap. - /// This should only be called from the exception handler. - /// </summary> - /// <param name="address">Virtual address accessed</param> - /// <param name="size">Size of the region affected in bytes</param> - /// <param name="write">Whether the region was written to or read</param> - /// <param name="precise">True if the access is precise, false otherwise</param> - /// <returns>True if the event triggered any tracking regions, false otherwise</returns> - public bool VirtualMemoryEventEh(ulong address, ulong size, bool write, bool precise = false) - { - // Windows has a limitation, it can't do partial unmaps. - // For this reason, we need to unmap the whole range and then remap the sub-ranges. - // When this happens, we might have caused a undesirable access violation from the time that the range was unmapped. - // In this case, try again as the memory might be mapped now. - if (OperatingSystem.IsWindows() && MemoryManagementWindows.RetryFromAccessViolation()) - { - return true; - } - - return VirtualMemoryEvent(address, size, write, precise); - } - - /// <summary> - /// Signal that a virtual memory event happened at the given location. /// This can be flagged as a precise event, which will avoid reprotection and call special handlers if possible. /// A precise event has an exact address and size, rather than triggering on page granularity. /// </summary> @@ -237,10 +213,12 @@ namespace Ryujinx.Memory.Tracking if (count == 0 && !precise) { - if (_memoryManager.IsMapped(address)) + if (_memoryManager.IsRangeMapped(address, size)) { + // TODO: There is currently the possibility that a page can be protected after its virtual region is removed. + // This code handles that case when it happens, but it would be better to find out how this happens. _memoryManager.TrackingReprotect(address & ~(ulong)(_pageSize - 1), (ulong)_pageSize, MemoryPermission.ReadAndWrite); - return false; // We can't handle this - it's probably a real invalid access. + return true; // This memory _should_ be mapped, so we need to try again. } else { diff --git a/Ryujinx.Memory/WindowsShared/PlaceholderManager.cs b/Ryujinx.Memory/WindowsShared/PlaceholderManager.cs index 1b425d66..0937d462 100644 --- a/Ryujinx.Memory/WindowsShared/PlaceholderManager.cs +++ b/Ryujinx.Memory/WindowsShared/PlaceholderManager.cs @@ -1,5 +1,7 @@ +using Ryujinx.Common.Memory.PartialUnmaps; using System; using System.Diagnostics; +using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Threading; @@ -13,13 +15,10 @@ namespace Ryujinx.Memory.WindowsShared { private const ulong MinimumPageSize = 0x1000; - [ThreadStatic] - private static int _threadLocalPartialUnmapsCount; - private readonly IntervalTree<ulong, ulong> _mappings; private readonly IntervalTree<ulong, MemoryPermission> _protections; - private readonly ReaderWriterLock _partialUnmapLock; - private int _partialUnmapsCount; + private readonly IntPtr _partialUnmapStatePtr; + private readonly Thread _partialUnmapTrimThread; /// <summary> /// Creates a new instance of the Windows memory placeholder manager. @@ -28,7 +27,35 @@ namespace Ryujinx.Memory.WindowsShared { _mappings = new IntervalTree<ulong, ulong>(); _protections = new IntervalTree<ulong, MemoryPermission>(); - _partialUnmapLock = new ReaderWriterLock(); + + _partialUnmapStatePtr = PartialUnmapState.GlobalState; + + _partialUnmapTrimThread = new Thread(TrimThreadLocalMapLoop); + _partialUnmapTrimThread.Name = "CPU.PartialUnmapTrimThread"; + _partialUnmapTrimThread.IsBackground = true; + _partialUnmapTrimThread.Start(); + } + + /// <summary> + /// Gets a reference to the partial unmap state struct. + /// </summary> + /// <returns>A reference to the partial unmap state struct</returns> + private unsafe ref PartialUnmapState GetPartialUnmapState() + { + return ref Unsafe.AsRef<PartialUnmapState>((void*)_partialUnmapStatePtr); + } + + /// <summary> + /// Trims inactive threads from the partial unmap state's thread mapping every few seconds. + /// Should be run in a Background thread so that it doesn't stop the program from closing. + /// </summary> + private void TrimThreadLocalMapLoop() + { + while (true) + { + Thread.Sleep(2000); + GetPartialUnmapState().TrimThreads(); + } } /// <summary> @@ -98,7 +125,8 @@ namespace Ryujinx.Memory.WindowsShared /// <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); + ref var partialUnmapLock = ref GetPartialUnmapState().PartialUnmapLock; + partialUnmapLock.AcquireReaderLock(); try { @@ -107,7 +135,7 @@ namespace Ryujinx.Memory.WindowsShared } finally { - _partialUnmapLock.ReleaseReaderLock(); + partialUnmapLock.ReleaseReaderLock(); } } @@ -221,7 +249,8 @@ namespace Ryujinx.Memory.WindowsShared /// <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); + ref var partialUnmapLock = ref GetPartialUnmapState().PartialUnmapLock; + partialUnmapLock.AcquireReaderLock(); try { @@ -229,7 +258,7 @@ namespace Ryujinx.Memory.WindowsShared } finally { - _partialUnmapLock.ReleaseReaderLock(); + partialUnmapLock.ReleaseReaderLock(); } } @@ -265,11 +294,6 @@ namespace Ryujinx.Memory.WindowsShared if (IsMapped(overlap.Value)) { - if (!WindowsApi.UnmapViewOfFile2(WindowsApi.CurrentProcessHandle, (IntPtr)overlap.Start, 2)) - { - throw new WindowsApiException("UnmapViewOfFile2"); - } - // 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; @@ -291,30 +315,46 @@ namespace Ryujinx.Memory.WindowsShared // This is necessary because Windows does not support partial view unmaps. // That is, you can only fully unmap a view that was previously mapped, you can't just unmap a chunck of it. - LockCookie lockCookie = _partialUnmapLock.UpgradeToWriterLock(Timeout.Infinite); - - _partialUnmapsCount++; + ref var partialUnmapState = ref GetPartialUnmapState(); + ref var partialUnmapLock = ref partialUnmapState.PartialUnmapLock; + partialUnmapLock.UpgradeToWriterLock(); - if (overlapStartsBefore) + try { - ulong remapSize = startAddress - overlapStart; - - MapViewInternal(sharedMemory, overlapValue, (IntPtr)overlapStart, (IntPtr)remapSize); - RestoreRangeProtection(overlapStart, remapSize); + partialUnmapState.PartialUnmapsCount++; + + if (!WindowsApi.UnmapViewOfFile2(WindowsApi.CurrentProcessHandle, (IntPtr)overlapStart, 2)) + { + throw new WindowsApiException("UnmapViewOfFile2"); + } + + if (overlapStartsBefore) + { + ulong remapSize = startAddress - overlapStart; + + MapViewInternal(sharedMemory, overlapValue, (IntPtr)overlapStart, (IntPtr)remapSize); + RestoreRangeProtection(overlapStart, remapSize); + } + + if (overlapEndsAfter) + { + ulong overlappedSize = endAddress - overlapStart; + ulong remapBackingOffset = overlapValue + overlappedSize; + ulong remapAddress = overlapStart + overlappedSize; + ulong remapSize = overlapEnd - endAddress; + + MapViewInternal(sharedMemory, remapBackingOffset, (IntPtr)remapAddress, (IntPtr)remapSize); + RestoreRangeProtection(remapAddress, remapSize); + } } - - if (overlapEndsAfter) + finally { - ulong overlappedSize = endAddress - overlapStart; - ulong remapBackingOffset = overlapValue + overlappedSize; - ulong remapAddress = overlapStart + overlappedSize; - ulong remapSize = overlapEnd - endAddress; - - MapViewInternal(sharedMemory, remapBackingOffset, (IntPtr)remapAddress, (IntPtr)remapSize); - RestoreRangeProtection(remapAddress, remapSize); + partialUnmapLock.DowngradeFromWriterLock(); } - - _partialUnmapLock.DowngradeFromWriterLock(ref lockCookie); + } + else if (!WindowsApi.UnmapViewOfFile2(WindowsApi.CurrentProcessHandle, (IntPtr)overlapStart, 2)) + { + throw new WindowsApiException("UnmapViewOfFile2"); } } } @@ -394,7 +434,8 @@ namespace Ryujinx.Memory.WindowsShared /// <returns>True if the reprotection was successful, false otherwise</returns> public bool ReprotectView(IntPtr address, IntPtr size, MemoryPermission permission) { - _partialUnmapLock.AcquireReaderLock(Timeout.Infinite); + ref var partialUnmapLock = ref GetPartialUnmapState().PartialUnmapLock; + partialUnmapLock.AcquireReaderLock(); try { @@ -402,7 +443,7 @@ namespace Ryujinx.Memory.WindowsShared } finally { - _partialUnmapLock.ReleaseReaderLock(); + partialUnmapLock.ReleaseReaderLock(); } } @@ -659,31 +700,5 @@ namespace Ryujinx.Memory.WindowsShared ReprotectViewInternal((IntPtr)protAddress, (IntPtr)(protEndAddress - protAddress), protection.Value, true); } } - - /// <summary> - /// Checks if an access violation handler should retry execution due to a fault caused by partial unmap. - /// </summary> - /// <remarks> - /// Due to Windows limitations, <see cref="UnmapView"/> might need to unmap more memory than requested. - /// The additional memory that was unmapped is later remapped, however this leaves a time gap where the - /// memory might be accessed but is unmapped. Users of the API must compensate for that by catching the - /// access violation and retrying if it happened between the unmap and remap operation. - /// This method can be used to decide if retrying in such cases is necessary or not. - /// </remarks> - /// <returns>True if execution should be retried, false otherwise</returns> - public bool RetryFromAccessViolation() - { - _partialUnmapLock.AcquireReaderLock(Timeout.Infinite); - - bool retry = _threadLocalPartialUnmapsCount != _partialUnmapsCount; - if (retry) - { - _threadLocalPartialUnmapsCount = _partialUnmapsCount; - } - - _partialUnmapLock.ReleaseReaderLock(); - - return retry; - } } }
\ No newline at end of file diff --git a/Ryujinx.Memory/WindowsShared/PlaceholderManager4KB.cs b/Ryujinx.Memory/WindowsShared/PlaceholderManager4KB.cs deleted file mode 100644 index fc056a2f..00000000 --- a/Ryujinx.Memory/WindowsShared/PlaceholderManager4KB.cs +++ /dev/null @@ -1,170 +0,0 @@ -using System; -using System.Runtime.Versioning; - -namespace Ryujinx.Memory.WindowsShared -{ - /// <summary> - /// Windows 4KB memory placeholder manager. - /// </summary> - [SupportedOSPlatform("windows")] - class PlaceholderManager4KB - { - private const int PageSize = MemoryManagementWindows.PageSize; - - private readonly IntervalTree<ulong, byte> _mappings; - - /// <summary> - /// Creates a new instance of the Windows 4KB memory placeholder manager. - /// </summary> - public PlaceholderManager4KB() - { - _mappings = new IntervalTree<ulong, byte>(); - } - - /// <summary> - /// Unmaps the specified range of memory and marks it as mapped internally. - /// </summary> - /// <remarks> - /// Since this marks the range as mapped, the expectation is that the range will be mapped after calling this method. - /// </remarks> - /// <param name="location">Memory address to unmap and mark as mapped</param> - /// <param name="size">Size of the range in bytes</param> - public void UnmapAndMarkRangeAsMapped(IntPtr location, IntPtr size) - { - ulong startAddress = (ulong)location; - ulong unmapSize = (ulong)size; - ulong endAddress = startAddress + unmapSize; - - var overlaps = Array.Empty<IntervalTreeNode<ulong, byte>>(); - int count = 0; - - lock (_mappings) - { - count = _mappings.Get(startAddress, endAddress, ref overlaps); - } - - for (int index = 0; index < count; index++) - { - var overlap = overlaps[index]; - - // 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); - - ulong unmapStart = Math.Max(overlapStart, startAddress); - ulong unmapEnd = Math.Min(overlapEnd, endAddress); - - if (overlapStart < startAddress) - { - startAddress = overlapStart; - } - - if (overlapEnd > endAddress) - { - endAddress = overlapEnd; - } - - ulong currentAddress = unmapStart; - while (currentAddress < unmapEnd) - { - WindowsApi.UnmapViewOfFile2(WindowsApi.CurrentProcessHandle, (IntPtr)currentAddress, 2); - currentAddress += PageSize; - } - } - - _mappings.Add(startAddress, endAddress, 0); - } - - /// <summary> - /// Unmaps views at the specified memory range. - /// </summary> - /// <param name="location">Address of the range</param> - /// <param name="size">Size of the range in bytes</param> - public void UnmapView(IntPtr location, IntPtr size) - { - ulong startAddress = (ulong)location; - ulong unmapSize = (ulong)size; - ulong endAddress = startAddress + unmapSize; - - var overlaps = Array.Empty<IntervalTreeNode<ulong, byte>>(); - int count = 0; - - lock (_mappings) - { - count = _mappings.Get(startAddress, endAddress, ref overlaps); - } - - for (int index = 0; index < count; index++) - { - var overlap = overlaps[index]; - - // 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; - - _mappings.Remove(overlap); - - if (overlapStart < startAddress) - { - _mappings.Add(overlapStart, startAddress, 0); - } - - if (overlapEnd > endAddress) - { - _mappings.Add(endAddress, overlapEnd, 0); - } - - ulong unmapStart = Math.Max(overlapStart, startAddress); - ulong unmapEnd = Math.Min(overlapEnd, endAddress); - - ulong currentAddress = unmapStart; - while (currentAddress < unmapEnd) - { - WindowsApi.UnmapViewOfFile2(WindowsApi.CurrentProcessHandle, (IntPtr)currentAddress, 2); - currentAddress += PageSize; - } - } - } - - /// <summary> - /// Unmaps mapped memory at a given range. - /// </summary> - /// <param name="location">Address of the range</param> - /// <param name="size">Size of the range in bytes</param> - public void UnmapRange(IntPtr location, IntPtr size) - { - ulong startAddress = (ulong)location; - ulong unmapSize = (ulong)size; - ulong endAddress = startAddress + unmapSize; - - var overlaps = Array.Empty<IntervalTreeNode<ulong, byte>>(); - int count = 0; - - lock (_mappings) - { - count = _mappings.Get(startAddress, endAddress, ref overlaps); - } - - for (int index = 0; index < count; index++) - { - var overlap = overlaps[index]; - - // Tree operations might modify the node start/end values, so save a copy before we modify the tree. - ulong unmapStart = Math.Max(overlap.Start, startAddress); - ulong unmapEnd = Math.Min(overlap.End, endAddress); - - _mappings.Remove(overlap); - - ulong currentAddress = unmapStart; - while (currentAddress < unmapEnd) - { - WindowsApi.UnmapViewOfFile2(WindowsApi.CurrentProcessHandle, (IntPtr)currentAddress, 2); - currentAddress += PageSize; - } - } - } - } -}
\ No newline at end of file diff --git a/Ryujinx.Memory/WindowsShared/WindowsApi.cs b/Ryujinx.Memory/WindowsShared/WindowsApi.cs index 297bd1ee..cbb7d99e 100644 --- a/Ryujinx.Memory/WindowsShared/WindowsApi.cs +++ b/Ryujinx.Memory/WindowsShared/WindowsApi.cs @@ -76,6 +76,9 @@ namespace Ryujinx.Memory.WindowsShared [DllImport("kernel32.dll")] public static extern uint GetLastError(); + [DllImport("kernel32.dll")] + public static extern int GetCurrentThreadId(); + public static MemoryProtection GetProtection(MemoryPermission permission) { return permission switch |
