Remove unused physical region tracking (#2085)
* Remove unused physical region tracking * Update comments
This commit is contained in:
parent
8d36681bf1
commit
a539303e71
7 changed files with 24 additions and 316 deletions
|
@ -115,9 +115,9 @@ namespace Ryujinx.Cpu
|
||||||
AssertValidAddressAndSize(va, size);
|
AssertValidAddressAndSize(va, size);
|
||||||
|
|
||||||
UnmapEvent?.Invoke(va, size);
|
UnmapEvent?.Invoke(va, size);
|
||||||
|
Tracking.Unmap(va, size);
|
||||||
|
|
||||||
ulong remainingSize = size;
|
ulong remainingSize = size;
|
||||||
ulong oVa = va;
|
|
||||||
while (remainingSize != 0)
|
while (remainingSize != 0)
|
||||||
{
|
{
|
||||||
_pageTable.Write((va / PageSize) * PteSize, 0UL);
|
_pageTable.Write((va / PageSize) * PteSize, 0UL);
|
||||||
|
@ -125,7 +125,6 @@ namespace Ryujinx.Cpu
|
||||||
va += PageSize;
|
va += PageSize;
|
||||||
remainingSize -= PageSize;
|
remainingSize -= PageSize;
|
||||||
}
|
}
|
||||||
Tracking.Unmap(oVa, size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -256,12 +256,12 @@ namespace Ryujinx.Memory.Tests
|
||||||
const int pageCount = 32;
|
const int pageCount = 32;
|
||||||
const int overlapStart = 16;
|
const int overlapStart = 16;
|
||||||
|
|
||||||
Assert.AreEqual((0, 0), _tracking.GetRegionCounts());
|
Assert.AreEqual(0, _tracking.GetRegionCount());
|
||||||
|
|
||||||
IMultiRegionHandle handleLow = GetGranular(smart, 0, PageSize * pageCount, PageSize);
|
IMultiRegionHandle handleLow = GetGranular(smart, 0, PageSize * pageCount, PageSize);
|
||||||
PreparePages(handleLow, pageCount);
|
PreparePages(handleLow, pageCount);
|
||||||
|
|
||||||
Assert.AreEqual((pageCount, pageCount), _tracking.GetRegionCounts());
|
Assert.AreEqual(pageCount, _tracking.GetRegionCount());
|
||||||
|
|
||||||
IMultiRegionHandle handleHigh = GetGranular(smart, PageSize * overlapStart, PageSize * pageCount, PageSize);
|
IMultiRegionHandle handleHigh = GetGranular(smart, PageSize * overlapStart, PageSize * pageCount, PageSize);
|
||||||
PreparePages(handleHigh, pageCount, PageSize * overlapStart);
|
PreparePages(handleHigh, pageCount, PageSize * overlapStart);
|
||||||
|
@ -269,15 +269,15 @@ namespace Ryujinx.Memory.Tests
|
||||||
// Combined pages (and assuming overlapStart <= pageCount) should be pageCount after overlapStart.
|
// Combined pages (and assuming overlapStart <= pageCount) should be pageCount after overlapStart.
|
||||||
int totalPages = overlapStart + pageCount;
|
int totalPages = overlapStart + pageCount;
|
||||||
|
|
||||||
Assert.AreEqual((totalPages, totalPages), _tracking.GetRegionCounts());
|
Assert.AreEqual(totalPages, _tracking.GetRegionCount());
|
||||||
|
|
||||||
handleLow.Dispose(); // After disposing one, the pages for the other remain.
|
handleLow.Dispose(); // After disposing one, the pages for the other remain.
|
||||||
|
|
||||||
Assert.AreEqual((pageCount, pageCount), _tracking.GetRegionCounts());
|
Assert.AreEqual(pageCount, _tracking.GetRegionCount());
|
||||||
|
|
||||||
handleHigh.Dispose(); // After disposing the other, there are no pages left.
|
handleHigh.Dispose(); // After disposing the other, there are no pages left.
|
||||||
|
|
||||||
Assert.AreEqual((0, 0), _tracking.GetRegionCounts());
|
Assert.AreEqual(0, _tracking.GetRegionCount());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,17 +32,12 @@ namespace Ryujinx.Memory.Tests
|
||||||
_memoryBlock.Dispose();
|
_memoryBlock.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TestSingleWrite(RegionHandle handle, ulong address, ulong size, bool physical = false)
|
private bool TestSingleWrite(RegionHandle handle, ulong address, ulong size)
|
||||||
{
|
{
|
||||||
handle.Reprotect();
|
handle.Reprotect();
|
||||||
if (physical)
|
|
||||||
{
|
_tracking.VirtualMemoryEvent(address, size, true);
|
||||||
_tracking.PhysicalMemoryEvent(address, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_tracking.VirtualMemoryEvent(address, size, true);
|
|
||||||
}
|
|
||||||
return handle.Dirty;
|
return handle.Dirty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,9 +92,6 @@ namespace Ryujinx.Memory.Tests
|
||||||
|
|
||||||
bool dirtyAfterDispose = TestSingleWrite(handle, 0, 4);
|
bool dirtyAfterDispose = TestSingleWrite(handle, 0, 4);
|
||||||
Assert.False(dirtyAfterDispose); // Handle cannot be triggered when disposed
|
Assert.False(dirtyAfterDispose); // Handle cannot be triggered when disposed
|
||||||
|
|
||||||
bool dirtyAfterDispose2 = TestSingleWrite(handle, 0, 4, true);
|
|
||||||
Assert.False(dirtyAfterDispose2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -362,33 +354,6 @@ namespace Ryujinx.Memory.Tests
|
||||||
Assert.AreEqual(registeredCount, triggeredCount + 1);
|
Assert.AreEqual(registeredCount, triggeredCount + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void PhysicalMemoryMapping()
|
|
||||||
{
|
|
||||||
// Tracking is done in the virtual space usually, but we also support tracking on physical regions.
|
|
||||||
// The physical regions that make up a virtual region are determined when the region is created,
|
|
||||||
// or when a mapping changes.
|
|
||||||
|
|
||||||
// These tests verify that the region cannot be signalled after unmapping, and can after remapping.
|
|
||||||
|
|
||||||
RegionHandle handle = _tracking.BeginTracking(PageSize, PageSize);
|
|
||||||
|
|
||||||
Assert.True(handle.Dirty);
|
|
||||||
|
|
||||||
bool trackedWriteTriggers = TestSingleWrite(handle, PageSize, 1, true);
|
|
||||||
Assert.True(trackedWriteTriggers);
|
|
||||||
|
|
||||||
_memoryManager.NoMappings = true;
|
|
||||||
_tracking.Unmap(PageSize, PageSize);
|
|
||||||
bool unmappedWriteTriggers = TestSingleWrite(handle, PageSize, 1, true);
|
|
||||||
Assert.False(unmappedWriteTriggers);
|
|
||||||
|
|
||||||
_memoryManager.NoMappings = false;
|
|
||||||
_tracking.Map(PageSize, PageSize, PageSize);
|
|
||||||
bool remappedWriteTriggers = TestSingleWrite(handle, PageSize, 1, true);
|
|
||||||
Assert.True(remappedWriteTriggers);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void DisposeHandles()
|
public void DisposeHandles()
|
||||||
{
|
{
|
||||||
|
@ -397,11 +362,11 @@ namespace Ryujinx.Memory.Tests
|
||||||
RegionHandle handle = _tracking.BeginTracking(0, PageSize);
|
RegionHandle handle = _tracking.BeginTracking(0, PageSize);
|
||||||
handle.Reprotect();
|
handle.Reprotect();
|
||||||
|
|
||||||
Assert.AreEqual((1, 1), _tracking.GetRegionCounts());
|
Assert.AreEqual(1, _tracking.GetRegionCount());
|
||||||
|
|
||||||
handle.Dispose();
|
handle.Dispose();
|
||||||
|
|
||||||
Assert.AreEqual((0, 0), _tracking.GetRegionCounts());
|
Assert.AreEqual(0, _tracking.GetRegionCount());
|
||||||
|
|
||||||
// Two handles, small entirely contains big.
|
// Two handles, small entirely contains big.
|
||||||
// We expect there to be three regions after creating both, one for the small region and two covering the big one around it.
|
// We expect there to be three regions after creating both, one for the small region and two covering the big one around it.
|
||||||
|
@ -410,16 +375,16 @@ namespace Ryujinx.Memory.Tests
|
||||||
RegionHandle handleSmall = _tracking.BeginTracking(PageSize, PageSize);
|
RegionHandle handleSmall = _tracking.BeginTracking(PageSize, PageSize);
|
||||||
RegionHandle handleBig = _tracking.BeginTracking(0, PageSize * 4);
|
RegionHandle handleBig = _tracking.BeginTracking(0, PageSize * 4);
|
||||||
|
|
||||||
Assert.AreEqual((3, 3), _tracking.GetRegionCounts());
|
Assert.AreEqual(3, _tracking.GetRegionCount());
|
||||||
|
|
||||||
// After disposing the big region, only the small one will remain.
|
// After disposing the big region, only the small one will remain.
|
||||||
handleBig.Dispose();
|
handleBig.Dispose();
|
||||||
|
|
||||||
Assert.AreEqual((1, 1), _tracking.GetRegionCounts());
|
Assert.AreEqual(1, _tracking.GetRegionCount());
|
||||||
|
|
||||||
handleSmall.Dispose();
|
handleSmall.Dispose();
|
||||||
|
|
||||||
Assert.AreEqual((0, 0), _tracking.GetRegionCounts());
|
Assert.AreEqual(0, _tracking.GetRegionCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
|
|
@ -13,11 +13,9 @@ namespace Ryujinx.Memory.Tracking
|
||||||
|
|
||||||
// Only use these from within the lock.
|
// Only use these from within the lock.
|
||||||
private readonly NonOverlappingRangeList<VirtualRegion> _virtualRegions;
|
private readonly NonOverlappingRangeList<VirtualRegion> _virtualRegions;
|
||||||
private readonly NonOverlappingRangeList<PhysicalRegion> _physicalRegions;
|
|
||||||
|
|
||||||
// Only use these from within the lock.
|
// Only use these from within the lock.
|
||||||
private readonly VirtualRegion[] _virtualResults = new VirtualRegion[10];
|
private readonly VirtualRegion[] _virtualResults = new VirtualRegion[10];
|
||||||
private readonly PhysicalRegion[] _physicalResults = new PhysicalRegion[10];
|
|
||||||
|
|
||||||
private readonly int _pageSize;
|
private readonly int _pageSize;
|
||||||
|
|
||||||
|
@ -43,7 +41,6 @@ namespace Ryujinx.Memory.Tracking
|
||||||
_pageSize = pageSize;
|
_pageSize = pageSize;
|
||||||
|
|
||||||
_virtualRegions = new NonOverlappingRangeList<VirtualRegion>();
|
_virtualRegions = new NonOverlappingRangeList<VirtualRegion>();
|
||||||
_physicalRegions = new NonOverlappingRangeList<PhysicalRegion>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private (ulong address, ulong size) PageAlign(ulong address, ulong size)
|
private (ulong address, ulong size) PageAlign(ulong address, ulong size)
|
||||||
|
@ -82,7 +79,6 @@ namespace Ryujinx.Memory.Tracking
|
||||||
region.SignalMappingChanged(true);
|
region.SignalMappingChanged(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
region.RecalculatePhysicalChildren();
|
|
||||||
region.UpdateProtection();
|
region.UpdateProtection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,14 +86,14 @@ namespace Ryujinx.Memory.Tracking
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicate that a virtual region has been unmapped.
|
/// Indicate that a virtual region has been unmapped.
|
||||||
/// Should be called after the unmapping is complete.
|
/// Should be called before the unmapping is complete.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="va">Virtual memory address</param>
|
/// <param name="va">Virtual memory address</param>
|
||||||
/// <param name="size">Size to be unmapped</param>
|
/// <param name="size">Size to be unmapped</param>
|
||||||
public void Unmap(ulong va, ulong size)
|
public void Unmap(ulong va, ulong size)
|
||||||
{
|
{
|
||||||
// An unmapping may mean we need to re-evaluate each VirtualRegion's affected area.
|
// An unmapping may mean we need to re-evaluate each VirtualRegion's affected area.
|
||||||
// Find all handles that overlap with the range, we need to recalculate their physical regions
|
// Find all handles that overlap with the range, we need to notify them that the region was unmapped.
|
||||||
|
|
||||||
lock (TrackingLock)
|
lock (TrackingLock)
|
||||||
{
|
{
|
||||||
|
@ -107,8 +103,8 @@ namespace Ryujinx.Memory.Tracking
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
VirtualRegion region = results[i];
|
VirtualRegion region = results[i];
|
||||||
|
|
||||||
region.SignalMappingChanged(false);
|
region.SignalMappingChanged(false);
|
||||||
region.RecalculatePhysicalChildren();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,31 +123,6 @@ namespace Ryujinx.Memory.Tracking
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get a list of physical regions that a virtual region covers.
|
|
||||||
/// Note that this becomes outdated if the virtual or physical regions are unmapped or remapped.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="va">Virtual memory address</param>
|
|
||||||
/// <param name="size">Size of the virtual region</param>
|
|
||||||
/// <returns>A list of physical regions the virtual region covers</returns>
|
|
||||||
internal List<PhysicalRegion> GetPhysicalRegionsForVirtual(ulong va, ulong size)
|
|
||||||
{
|
|
||||||
List<PhysicalRegion> result = new List<PhysicalRegion>();
|
|
||||||
|
|
||||||
// Get a list of physical regions for this virtual region, from our injected virtual mapping function.
|
|
||||||
(ulong Address, ulong Size)[] physicalRegions = _memoryManager.GetPhysicalRegions(va, size);
|
|
||||||
|
|
||||||
if (physicalRegions != null)
|
|
||||||
{
|
|
||||||
foreach (var region in physicalRegions)
|
|
||||||
{
|
|
||||||
_physicalRegions.GetOrAddRegions(result, region.Address, region.Size, (pa, size) => new PhysicalRegion(this, pa, size));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Remove a virtual region from the range list. This assumes that the lock has been acquired.
|
/// Remove a virtual region from the range list. This assumes that the lock has been acquired.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -161,15 +132,6 @@ namespace Ryujinx.Memory.Tracking
|
||||||
_virtualRegions.Remove(region);
|
_virtualRegions.Remove(region);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Remove a physical region from the range list. This assumes that the lock has been acquired.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="region">Region to remove</param>
|
|
||||||
internal void RemovePhysical(PhysicalRegion region)
|
|
||||||
{
|
|
||||||
_physicalRegions.Remove(region);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Obtains a memory tracking handle for the given virtual region, with a specified granularity. This should be disposed when finished with.
|
/// Obtains a memory tracking handle for the given virtual region, with a specified granularity. This should be disposed when finished with.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -216,38 +178,6 @@ namespace Ryujinx.Memory.Tracking
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Signal that a physical memory event happened at the given location.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="address">Physical address accessed</param>
|
|
||||||
/// <param name="write">Whether the region was written to or read</param>
|
|
||||||
/// <returns>True if the event triggered any tracking regions, false otherwise</returns>
|
|
||||||
public bool PhysicalMemoryEvent(ulong address, bool write)
|
|
||||||
{
|
|
||||||
// Look up the physical region using the region list.
|
|
||||||
// Signal up the chain to relevant handles.
|
|
||||||
|
|
||||||
lock (TrackingLock)
|
|
||||||
{
|
|
||||||
var results = _physicalResults;
|
|
||||||
int count = _physicalRegions.FindOverlapsNonOverlapping(address, 1, ref results); // TODO: get/use the actual access size?
|
|
||||||
|
|
||||||
if (count == 0)
|
|
||||||
{
|
|
||||||
_block.Reprotect(address & ~(ulong)(_pageSize - 1), (ulong)_pageSize, MemoryPermission.ReadAndWrite);
|
|
||||||
return false; // We can't handle this - unprotect and return.
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
PhysicalRegion region = results[i];
|
|
||||||
region.Signal(address, 1, write);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Signal that a virtual memory event happened at the given location (one byte).
|
/// Signal that a virtual memory event happened at the given location (one byte).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -292,19 +222,6 @@ namespace Ryujinx.Memory.Tracking
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reprotect a given physical region, if enabled. This is protected on the memory block provided during initialization.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="region">Region to reprotect</param>
|
|
||||||
/// <param name="permission">Memory permission to protect with</param>
|
|
||||||
internal void ProtectPhysicalRegion(PhysicalRegion region, MemoryPermission permission)
|
|
||||||
{
|
|
||||||
if (EnablePhysicalProtection)
|
|
||||||
{
|
|
||||||
_block.Reprotect(region.Address, region.Size, permission);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reprotect a given virtual region. The virtual memory manager will handle this.
|
/// Reprotect a given virtual region. The virtual memory manager will handle this.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -316,15 +233,15 @@ namespace Ryujinx.Memory.Tracking
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the number of virtual and physical regions currently being tracked.
|
/// Returns the number of virtual regions currently being tracked.
|
||||||
/// Useful for tests and metrics.
|
/// Useful for tests and metrics.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The number of virtual regions, and the number of physical regions</returns>
|
/// <returns>The number of virtual regions</returns>
|
||||||
public (int VirtualCount, int PhysicalCount) GetRegionCounts()
|
public int GetRegionCount()
|
||||||
{
|
{
|
||||||
lock (TrackingLock)
|
lock (TrackingLock)
|
||||||
{
|
{
|
||||||
return (_virtualRegions.Count, _physicalRegions.Count);
|
return _virtualRegions.Count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,97 +0,0 @@
|
||||||
using Ryujinx.Memory.Range;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Ryujinx.Memory.Tracking
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A region of physical memory.
|
|
||||||
/// </summary>
|
|
||||||
class PhysicalRegion : AbstractRegion
|
|
||||||
{
|
|
||||||
public List<VirtualRegion> VirtualParents = new List<VirtualRegion>();
|
|
||||||
public MemoryPermission Protection { get; private set; }
|
|
||||||
public MemoryTracking Tracking;
|
|
||||||
|
|
||||||
public PhysicalRegion(MemoryTracking tracking, ulong address, ulong size) : base(address, size)
|
|
||||||
{
|
|
||||||
Tracking = tracking;
|
|
||||||
Protection = MemoryPermission.ReadAndWrite;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Signal(ulong address, ulong size, bool write)
|
|
||||||
{
|
|
||||||
Protection = MemoryPermission.ReadAndWrite;
|
|
||||||
Tracking.ProtectPhysicalRegion(this, MemoryPermission.ReadAndWrite); // Remove our protection immedately.
|
|
||||||
foreach (var parent in VirtualParents)
|
|
||||||
{
|
|
||||||
parent.Signal(address, size, write);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Update the protection of this region, based on our parent's requested protection.
|
|
||||||
/// </summary>
|
|
||||||
public void UpdateProtection()
|
|
||||||
{
|
|
||||||
// Re-evaluate protection, and commit to the block.
|
|
||||||
|
|
||||||
lock (Tracking.TrackingLock)
|
|
||||||
{
|
|
||||||
MemoryPermission result = MemoryPermission.ReadAndWrite;
|
|
||||||
foreach (var parent in VirtualParents)
|
|
||||||
{
|
|
||||||
result &= parent.GetRequiredPermission();
|
|
||||||
if (result == 0) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Protection != result)
|
|
||||||
{
|
|
||||||
Protection = result;
|
|
||||||
Tracking.ProtectPhysicalRegion(this, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override INonOverlappingRange Split(ulong splitAddress)
|
|
||||||
{
|
|
||||||
PhysicalRegion newRegion = new PhysicalRegion(Tracking, splitAddress, EndAddress - splitAddress);
|
|
||||||
Size = splitAddress - Address;
|
|
||||||
|
|
||||||
// The new region inherits all of our parents.
|
|
||||||
newRegion.VirtualParents = new List<VirtualRegion>(VirtualParents);
|
|
||||||
foreach (var parent in VirtualParents)
|
|
||||||
{
|
|
||||||
parent.AddChild(newRegion);
|
|
||||||
}
|
|
||||||
|
|
||||||
return newRegion;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Remove a parent virtual region from this physical region. Assumes that the tracking lock has been obtained.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="region">Region to remove</param>
|
|
||||||
/// <returns>True if there are no more parents and we should be removed, false otherwise.</returns>
|
|
||||||
public bool RemoveParent(VirtualRegion region)
|
|
||||||
{
|
|
||||||
VirtualParents.Remove(region);
|
|
||||||
UpdateProtection();
|
|
||||||
if (VirtualParents.Count == 0)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Deletes this physical region if there are no more virtual parents.
|
|
||||||
/// </summary>
|
|
||||||
public void TryDelete()
|
|
||||||
{
|
|
||||||
if (VirtualParents.Count == 0)
|
|
||||||
{
|
|
||||||
Tracking.RemovePhysical(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -159,7 +159,7 @@ namespace Ryujinx.Memory.Tracking
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dispose the handle. Within the tracking lock, this removes references from virtual and physical regions.
|
/// Dispose the handle. Within the tracking lock, this removes references from virtual regions.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,15 +9,12 @@ namespace Ryujinx.Memory.Tracking
|
||||||
class VirtualRegion : AbstractRegion
|
class VirtualRegion : AbstractRegion
|
||||||
{
|
{
|
||||||
public List<RegionHandle> Handles = new List<RegionHandle>();
|
public List<RegionHandle> Handles = new List<RegionHandle>();
|
||||||
private List<PhysicalRegion> _physicalChildren;
|
|
||||||
|
|
||||||
private readonly MemoryTracking _tracking;
|
private readonly MemoryTracking _tracking;
|
||||||
|
|
||||||
public VirtualRegion(MemoryTracking tracking, ulong address, ulong size) : base(address, size)
|
public VirtualRegion(MemoryTracking tracking, ulong address, ulong size) : base(address, size)
|
||||||
{
|
{
|
||||||
_tracking = tracking;
|
_tracking = tracking;
|
||||||
|
|
||||||
UpdatePhysicalChildren();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Signal(ulong address, ulong size, bool write)
|
public override void Signal(ulong address, ulong size, bool write)
|
||||||
|
@ -30,42 +27,6 @@ namespace Ryujinx.Memory.Tracking
|
||||||
UpdateProtection();
|
UpdateProtection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Clears all physical children of this region. Assumes that the tracking lock has been obtained.
|
|
||||||
/// </summary>
|
|
||||||
private void ClearPhysicalChildren()
|
|
||||||
{
|
|
||||||
if (_physicalChildren != null)
|
|
||||||
{
|
|
||||||
foreach (PhysicalRegion child in _physicalChildren)
|
|
||||||
{
|
|
||||||
child.RemoveParent(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the physical children of this region, assuming that they are clear and that the tracking lock has been obtained.
|
|
||||||
/// </summary>
|
|
||||||
private void UpdatePhysicalChildren()
|
|
||||||
{
|
|
||||||
_physicalChildren = _tracking.GetPhysicalRegionsForVirtual(Address, Size);
|
|
||||||
|
|
||||||
foreach (PhysicalRegion child in _physicalChildren)
|
|
||||||
{
|
|
||||||
child.VirtualParents.Add(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Recalculates the physical children for this virtual region. Assumes that the tracking lock has been obtained.
|
|
||||||
/// </summary>
|
|
||||||
public void RecalculatePhysicalChildren()
|
|
||||||
{
|
|
||||||
ClearPhysicalChildren();
|
|
||||||
UpdatePhysicalChildren();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Signal that this region has been mapped or unmapped.
|
/// Signal that this region has been mapped or unmapped.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -98,20 +59,11 @@ namespace Ryujinx.Memory.Tracking
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the protection for this virtual region, and all child physical regions.
|
/// Updates the protection for this virtual region.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void UpdateProtection()
|
public void UpdateProtection()
|
||||||
{
|
{
|
||||||
// Re-evaluate protection for all physical children.
|
|
||||||
|
|
||||||
_tracking.ProtectVirtualRegion(this, GetRequiredPermission());
|
_tracking.ProtectVirtualRegion(this, GetRequiredPermission());
|
||||||
lock (_tracking.TrackingLock)
|
|
||||||
{
|
|
||||||
foreach (var child in _physicalChildren)
|
|
||||||
{
|
|
||||||
child.UpdateProtection();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -120,7 +72,6 @@ namespace Ryujinx.Memory.Tracking
|
||||||
/// <param name="handle">Handle to remove</param>
|
/// <param name="handle">Handle to remove</param>
|
||||||
public void RemoveHandle(RegionHandle handle)
|
public void RemoveHandle(RegionHandle handle)
|
||||||
{
|
{
|
||||||
bool removedRegions = false;
|
|
||||||
lock (_tracking.TrackingLock)
|
lock (_tracking.TrackingLock)
|
||||||
{
|
{
|
||||||
Handles.Remove(handle);
|
Handles.Remove(handle);
|
||||||
|
@ -128,41 +79,14 @@ namespace Ryujinx.Memory.Tracking
|
||||||
if (Handles.Count == 0)
|
if (Handles.Count == 0)
|
||||||
{
|
{
|
||||||
_tracking.RemoveVirtual(this);
|
_tracking.RemoveVirtual(this);
|
||||||
foreach (var child in _physicalChildren)
|
|
||||||
{
|
|
||||||
removedRegions |= child.RemoveParent(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (removedRegions)
|
|
||||||
{
|
|
||||||
// The first lock will unprotect any regions that have been removed. This second lock will remove them.
|
|
||||||
lock (_tracking.TrackingLock)
|
|
||||||
{
|
|
||||||
foreach (var child in _physicalChildren)
|
|
||||||
{
|
|
||||||
child.TryDelete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Add a child physical region to this virtual region. Assumes that the tracking lock has been obtained.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="region">Physical region to add as a child</param>
|
|
||||||
public void AddChild(PhysicalRegion region)
|
|
||||||
{
|
|
||||||
_physicalChildren.Add(region);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override INonOverlappingRange Split(ulong splitAddress)
|
public override INonOverlappingRange Split(ulong splitAddress)
|
||||||
{
|
{
|
||||||
ClearPhysicalChildren();
|
|
||||||
VirtualRegion newRegion = new VirtualRegion(_tracking, splitAddress, EndAddress - splitAddress);
|
VirtualRegion newRegion = new VirtualRegion(_tracking, splitAddress, EndAddress - splitAddress);
|
||||||
Size = splitAddress - Address;
|
Size = splitAddress - Address;
|
||||||
UpdatePhysicalChildren();
|
|
||||||
|
|
||||||
// The new region inherits all of our parents.
|
// The new region inherits all of our parents.
|
||||||
newRegion.Handles = new List<RegionHandle>(Handles);
|
newRegion.Handles = new List<RegionHandle>(Handles);
|
||||||
|
|
Reference in a new issue