|
@@ -13,10 +13,10 @@ namespace Ryujinx.Memory.WindowsShared
|
|
|
[SupportedOSPlatform("windows")]
|
|
[SupportedOSPlatform("windows")]
|
|
|
class PlaceholderManager
|
|
class PlaceholderManager
|
|
|
{
|
|
{
|
|
|
- private const ulong MinimumPageSize = 0x1000;
|
|
|
|
|
|
|
+ private const int InitialOverlapsSize = 10;
|
|
|
|
|
|
|
|
- private readonly IntervalTree<ulong, ulong> _mappings;
|
|
|
|
|
- private readonly IntervalTree<ulong, MemoryPermission> _protections;
|
|
|
|
|
|
|
+ private readonly MappingTree<ulong> _mappings;
|
|
|
|
|
+ private readonly MappingTree<MemoryPermission> _protections;
|
|
|
private readonly IntPtr _partialUnmapStatePtr;
|
|
private readonly IntPtr _partialUnmapStatePtr;
|
|
|
private readonly Thread _partialUnmapTrimThread;
|
|
private readonly Thread _partialUnmapTrimThread;
|
|
|
|
|
|
|
@@ -25,8 +25,8 @@ namespace Ryujinx.Memory.WindowsShared
|
|
|
/// </summary>
|
|
/// </summary>
|
|
|
public PlaceholderManager()
|
|
public PlaceholderManager()
|
|
|
{
|
|
{
|
|
|
- _mappings = new IntervalTree<ulong, ulong>();
|
|
|
|
|
- _protections = new IntervalTree<ulong, MemoryPermission>();
|
|
|
|
|
|
|
+ _mappings = new MappingTree<ulong>();
|
|
|
|
|
+ _protections = new MappingTree<MemoryPermission>();
|
|
|
|
|
|
|
|
_partialUnmapStatePtr = PartialUnmapState.GlobalState;
|
|
_partialUnmapStatePtr = PartialUnmapState.GlobalState;
|
|
|
|
|
|
|
@@ -67,7 +67,7 @@ namespace Ryujinx.Memory.WindowsShared
|
|
|
{
|
|
{
|
|
|
lock (_mappings)
|
|
lock (_mappings)
|
|
|
{
|
|
{
|
|
|
- _mappings.Add(address, address + size, ulong.MaxValue);
|
|
|
|
|
|
|
+ _mappings.Add(new RangeNode<ulong>(address, address + size, ulong.MaxValue));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -81,12 +81,12 @@ namespace Ryujinx.Memory.WindowsShared
|
|
|
{
|
|
{
|
|
|
ulong endAddress = address + size;
|
|
ulong endAddress = address + size;
|
|
|
|
|
|
|
|
- var overlaps = Array.Empty<IntervalTreeNode<ulong, ulong>>();
|
|
|
|
|
|
|
+ var overlaps = new RangeNode<ulong>[InitialOverlapsSize];
|
|
|
int count;
|
|
int count;
|
|
|
|
|
|
|
|
lock (_mappings)
|
|
lock (_mappings)
|
|
|
{
|
|
{
|
|
|
- count = _mappings.Get(address, endAddress, ref overlaps);
|
|
|
|
|
|
|
+ count = _mappings.GetNodes(address, endAddress, ref overlaps);
|
|
|
|
|
|
|
|
for (int index = 0; index < count; index++)
|
|
for (int index = 0; index < count; index++)
|
|
|
{
|
|
{
|
|
@@ -178,11 +178,11 @@ namespace Ryujinx.Memory.WindowsShared
|
|
|
{
|
|
{
|
|
|
ulong endAddress = address + size;
|
|
ulong endAddress = address + size;
|
|
|
|
|
|
|
|
- var overlaps = Array.Empty<IntervalTreeNode<ulong, ulong>>();
|
|
|
|
|
|
|
+ var overlaps = new RangeNode<ulong>[InitialOverlapsSize];
|
|
|
|
|
|
|
|
lock (_mappings)
|
|
lock (_mappings)
|
|
|
{
|
|
{
|
|
|
- int count = _mappings.Get(address, endAddress, ref overlaps);
|
|
|
|
|
|
|
+ int count = _mappings.GetNodes(address, endAddress, ref overlaps);
|
|
|
|
|
|
|
|
Debug.Assert(count == 1);
|
|
Debug.Assert(count == 1);
|
|
|
Debug.Assert(!IsMapped(overlaps[0].Value));
|
|
Debug.Assert(!IsMapped(overlaps[0].Value));
|
|
@@ -206,8 +206,8 @@ namespace Ryujinx.Memory.WindowsShared
|
|
|
(IntPtr)size,
|
|
(IntPtr)size,
|
|
|
AllocationType.Release | AllocationType.PreservePlaceholder));
|
|
AllocationType.Release | AllocationType.PreservePlaceholder));
|
|
|
|
|
|
|
|
- _mappings.Add(overlapStart, address, overlapValue);
|
|
|
|
|
- _mappings.Add(endAddress, overlapEnd, AddBackingOffset(overlapValue, endAddress - overlapStart));
|
|
|
|
|
|
|
+ _mappings.Add(new RangeNode<ulong>(overlapStart, address, overlapValue));
|
|
|
|
|
+ _mappings.Add(new RangeNode<ulong>(endAddress, overlapEnd, AddBackingOffset(overlapValue, endAddress - overlapStart)));
|
|
|
}
|
|
}
|
|
|
else if (overlapStartsBefore)
|
|
else if (overlapStartsBefore)
|
|
|
{
|
|
{
|
|
@@ -218,7 +218,7 @@ namespace Ryujinx.Memory.WindowsShared
|
|
|
(IntPtr)overlappedSize,
|
|
(IntPtr)overlappedSize,
|
|
|
AllocationType.Release | AllocationType.PreservePlaceholder));
|
|
AllocationType.Release | AllocationType.PreservePlaceholder));
|
|
|
|
|
|
|
|
- _mappings.Add(overlapStart, address, overlapValue);
|
|
|
|
|
|
|
+ _mappings.Add(new RangeNode<ulong>(overlapStart, address, overlapValue));
|
|
|
}
|
|
}
|
|
|
else if (overlapEndsAfter)
|
|
else if (overlapEndsAfter)
|
|
|
{
|
|
{
|
|
@@ -229,10 +229,10 @@ namespace Ryujinx.Memory.WindowsShared
|
|
|
(IntPtr)overlappedSize,
|
|
(IntPtr)overlappedSize,
|
|
|
AllocationType.Release | AllocationType.PreservePlaceholder));
|
|
AllocationType.Release | AllocationType.PreservePlaceholder));
|
|
|
|
|
|
|
|
- _mappings.Add(endAddress, overlapEnd, AddBackingOffset(overlapValue, overlappedSize));
|
|
|
|
|
|
|
+ _mappings.Add(new RangeNode<ulong>(endAddress, overlapEnd, AddBackingOffset(overlapValue, overlappedSize)));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- _mappings.Add(address, endAddress, backingOffset);
|
|
|
|
|
|
|
+ _mappings.Add(new RangeNode<ulong>(address, endAddress, backingOffset));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -280,12 +280,12 @@ namespace Ryujinx.Memory.WindowsShared
|
|
|
ulong unmapSize = (ulong)size;
|
|
ulong unmapSize = (ulong)size;
|
|
|
ulong endAddress = startAddress + unmapSize;
|
|
ulong endAddress = startAddress + unmapSize;
|
|
|
|
|
|
|
|
- var overlaps = Array.Empty<IntervalTreeNode<ulong, ulong>>();
|
|
|
|
|
|
|
+ var overlaps = new RangeNode<ulong>[InitialOverlapsSize];
|
|
|
int count;
|
|
int count;
|
|
|
|
|
|
|
|
lock (_mappings)
|
|
lock (_mappings)
|
|
|
{
|
|
{
|
|
|
- count = _mappings.Get(startAddress, endAddress, ref overlaps);
|
|
|
|
|
|
|
+ count = _mappings.GetNodes(startAddress, endAddress, ref overlaps);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
for (int index = 0; index < count; index++)
|
|
for (int index = 0; index < count; index++)
|
|
@@ -302,7 +302,7 @@ namespace Ryujinx.Memory.WindowsShared
|
|
|
lock (_mappings)
|
|
lock (_mappings)
|
|
|
{
|
|
{
|
|
|
_mappings.Remove(overlap);
|
|
_mappings.Remove(overlap);
|
|
|
- _mappings.Add(overlapStart, overlapEnd, ulong.MaxValue);
|
|
|
|
|
|
|
+ _mappings.Add(new RangeNode<ulong>(overlapStart, overlapEnd, ulong.MaxValue));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
bool overlapStartsBefore = overlapStart < startAddress;
|
|
bool overlapStartsBefore = overlapStart < startAddress;
|
|
@@ -374,44 +374,53 @@ namespace Ryujinx.Memory.WindowsShared
|
|
|
ulong endAddress = address + size;
|
|
ulong endAddress = address + size;
|
|
|
ulong blockAddress = (ulong)owner.Pointer;
|
|
ulong blockAddress = (ulong)owner.Pointer;
|
|
|
ulong blockEnd = blockAddress + owner.Size;
|
|
ulong blockEnd = blockAddress + owner.Size;
|
|
|
- var overlaps = Array.Empty<IntervalTreeNode<ulong, ulong>>();
|
|
|
|
|
|
|
+ var overlaps = new RangeNode<ulong>[InitialOverlapsSize];
|
|
|
int unmappedCount = 0;
|
|
int unmappedCount = 0;
|
|
|
|
|
|
|
|
lock (_mappings)
|
|
lock (_mappings)
|
|
|
{
|
|
{
|
|
|
- int count = _mappings.Get(
|
|
|
|
|
- Math.Max(address - MinimumPageSize, blockAddress),
|
|
|
|
|
- Math.Min(endAddress + MinimumPageSize, blockEnd), ref overlaps);
|
|
|
|
|
|
|
+ int count = _mappings.GetNodes(address, endAddress, ref overlaps);
|
|
|
|
|
|
|
|
- if (count < 2)
|
|
|
|
|
|
|
+ if (count == 0)
|
|
|
{
|
|
{
|
|
|
- // Nothing to coalesce if we only have 1 or no overlaps.
|
|
|
|
|
|
|
+ // Nothing to coalesce if we no overlaps.
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ RangeNode<ulong> predecessor = overlaps[0].Predecessor;
|
|
|
|
|
+ RangeNode<ulong> successor = overlaps[count - 1].Successor;
|
|
|
|
|
+
|
|
|
for (int index = 0; index < count; index++)
|
|
for (int index = 0; index < count; index++)
|
|
|
{
|
|
{
|
|
|
var overlap = overlaps[index];
|
|
var overlap = overlaps[index];
|
|
|
|
|
|
|
|
if (!IsMapped(overlap.Value))
|
|
if (!IsMapped(overlap.Value))
|
|
|
{
|
|
{
|
|
|
- if (address > overlap.Start)
|
|
|
|
|
- {
|
|
|
|
|
- address = overlap.Start;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (endAddress < overlap.End)
|
|
|
|
|
- {
|
|
|
|
|
- endAddress = overlap.End;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ address = Math.Min(address, overlap.Start);
|
|
|
|
|
+ endAddress = Math.Max(endAddress, overlap.End);
|
|
|
|
|
|
|
|
_mappings.Remove(overlap);
|
|
_mappings.Remove(overlap);
|
|
|
-
|
|
|
|
|
unmappedCount++;
|
|
unmappedCount++;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- _mappings.Add(address, endAddress, ulong.MaxValue);
|
|
|
|
|
|
|
+ if (predecessor != null && !IsMapped(predecessor.Value) && predecessor.Start >= blockAddress)
|
|
|
|
|
+ {
|
|
|
|
|
+ address = Math.Min(address, predecessor.Start);
|
|
|
|
|
+
|
|
|
|
|
+ _mappings.Remove(predecessor);
|
|
|
|
|
+ unmappedCount++;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (successor != null && !IsMapped(successor.Value) && successor.End <= blockEnd)
|
|
|
|
|
+ {
|
|
|
|
|
+ endAddress = Math.Max(endAddress, successor.End);
|
|
|
|
|
+
|
|
|
|
|
+ _mappings.Remove(successor);
|
|
|
|
|
+ unmappedCount++;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ _mappings.Add(new RangeNode<ulong>(address, endAddress, ulong.MaxValue));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (unmappedCount > 1)
|
|
if (unmappedCount > 1)
|
|
@@ -462,12 +471,12 @@ namespace Ryujinx.Memory.WindowsShared
|
|
|
ulong reprotectSize = (ulong)size;
|
|
ulong reprotectSize = (ulong)size;
|
|
|
ulong endAddress = reprotectAddress + reprotectSize;
|
|
ulong endAddress = reprotectAddress + reprotectSize;
|
|
|
|
|
|
|
|
- var overlaps = Array.Empty<IntervalTreeNode<ulong, ulong>>();
|
|
|
|
|
|
|
+ var overlaps = new RangeNode<ulong>[InitialOverlapsSize];
|
|
|
int count;
|
|
int count;
|
|
|
|
|
|
|
|
lock (_mappings)
|
|
lock (_mappings)
|
|
|
{
|
|
{
|
|
|
- count = _mappings.Get(reprotectAddress, endAddress, ref overlaps);
|
|
|
|
|
|
|
+ count = _mappings.GetNodes(reprotectAddress, endAddress, ref overlaps);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
bool success = true;
|
|
bool success = true;
|
|
@@ -567,12 +576,12 @@ namespace Ryujinx.Memory.WindowsShared
|
|
|
private void AddProtection(ulong address, ulong size, MemoryPermission permission)
|
|
private void AddProtection(ulong address, ulong size, MemoryPermission permission)
|
|
|
{
|
|
{
|
|
|
ulong endAddress = address + size;
|
|
ulong endAddress = address + size;
|
|
|
- var overlaps = Array.Empty<IntervalTreeNode<ulong, MemoryPermission>>();
|
|
|
|
|
|
|
+ var overlaps = new RangeNode<MemoryPermission>[InitialOverlapsSize];
|
|
|
int count;
|
|
int count;
|
|
|
|
|
|
|
|
lock (_protections)
|
|
lock (_protections)
|
|
|
{
|
|
{
|
|
|
- count = _protections.Get(address, endAddress, ref overlaps);
|
|
|
|
|
|
|
+ count = _protections.GetNodes(address, endAddress, ref overlaps);
|
|
|
|
|
|
|
|
if (count == 1 &&
|
|
if (count == 1 &&
|
|
|
overlaps[0].Start <= address &&
|
|
overlaps[0].Start <= address &&
|
|
@@ -610,17 +619,17 @@ namespace Ryujinx.Memory.WindowsShared
|
|
|
{
|
|
{
|
|
|
if (startAddress > protAddress)
|
|
if (startAddress > protAddress)
|
|
|
{
|
|
{
|
|
|
- _protections.Add(protAddress, startAddress, protPermission);
|
|
|
|
|
|
|
+ _protections.Add(new RangeNode<MemoryPermission>(protAddress, startAddress, protPermission));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (endAddress < protEndAddress)
|
|
if (endAddress < protEndAddress)
|
|
|
{
|
|
{
|
|
|
- _protections.Add(endAddress, protEndAddress, protPermission);
|
|
|
|
|
|
|
+ _protections.Add(new RangeNode<MemoryPermission>(endAddress, protEndAddress, protPermission));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- _protections.Add(startAddress, endAddress, permission);
|
|
|
|
|
|
|
+ _protections.Add(new RangeNode<MemoryPermission>(startAddress, endAddress, permission));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -632,12 +641,12 @@ namespace Ryujinx.Memory.WindowsShared
|
|
|
private void RemoveProtection(ulong address, ulong size)
|
|
private void RemoveProtection(ulong address, ulong size)
|
|
|
{
|
|
{
|
|
|
ulong endAddress = address + size;
|
|
ulong endAddress = address + size;
|
|
|
- var overlaps = Array.Empty<IntervalTreeNode<ulong, MemoryPermission>>();
|
|
|
|
|
|
|
+ var overlaps = new RangeNode<MemoryPermission>[InitialOverlapsSize];
|
|
|
int count;
|
|
int count;
|
|
|
|
|
|
|
|
lock (_protections)
|
|
lock (_protections)
|
|
|
{
|
|
{
|
|
|
- count = _protections.Get(address, endAddress, ref overlaps);
|
|
|
|
|
|
|
+ count = _protections.GetNodes(address, endAddress, ref overlaps);
|
|
|
|
|
|
|
|
for (int index = 0; index < count; index++)
|
|
for (int index = 0; index < count; index++)
|
|
|
{
|
|
{
|
|
@@ -651,12 +660,12 @@ namespace Ryujinx.Memory.WindowsShared
|
|
|
|
|
|
|
|
if (address > protAddress)
|
|
if (address > protAddress)
|
|
|
{
|
|
{
|
|
|
- _protections.Add(protAddress, address, protPermission);
|
|
|
|
|
|
|
+ _protections.Add(new RangeNode<MemoryPermission>(protAddress, address, protPermission));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (endAddress < protEndAddress)
|
|
if (endAddress < protEndAddress)
|
|
|
{
|
|
{
|
|
|
- _protections.Add(endAddress, protEndAddress, protPermission);
|
|
|
|
|
|
|
+ _protections.Add(new RangeNode<MemoryPermission>(endAddress, protEndAddress, protPermission));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -670,12 +679,12 @@ namespace Ryujinx.Memory.WindowsShared
|
|
|
private void RestoreRangeProtection(ulong address, ulong size)
|
|
private void RestoreRangeProtection(ulong address, ulong size)
|
|
|
{
|
|
{
|
|
|
ulong endAddress = address + size;
|
|
ulong endAddress = address + size;
|
|
|
- var overlaps = Array.Empty<IntervalTreeNode<ulong, MemoryPermission>>();
|
|
|
|
|
|
|
+ var overlaps = new RangeNode<MemoryPermission>[InitialOverlapsSize];
|
|
|
int count;
|
|
int count;
|
|
|
|
|
|
|
|
lock (_protections)
|
|
lock (_protections)
|
|
|
{
|
|
{
|
|
|
- count = _protections.Get(address, endAddress, ref overlaps);
|
|
|
|
|
|
|
+ count = _protections.GetNodes(address, endAddress, ref overlaps);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ulong startAddress = address;
|
|
ulong startAddress = address;
|