aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Memory
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Memory')
-rw-r--r--Ryujinx.Memory/MemoryAllocationFlags.cs8
-rw-r--r--Ryujinx.Memory/MemoryBlock.cs10
-rw-r--r--Ryujinx.Memory/MemoryManagement.cs37
-rw-r--r--Ryujinx.Memory/MemoryManagementWindows.cs80
-rw-r--r--Ryujinx.Memory/Tracking/MemoryTracking.cs30
-rw-r--r--Ryujinx.Memory/WindowsShared/PlaceholderManager.cs139
-rw-r--r--Ryujinx.Memory/WindowsShared/PlaceholderManager4KB.cs170
-rw-r--r--Ryujinx.Memory/WindowsShared/WindowsApi.cs3
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