public void QueryModified(ulong address, ulong size, Action <ulong, ulong> modifiedAction) { int startHandle = (int)((address - Address) / Granularity); int lastHandle = (int)((address + (size - 1) - Address) / Granularity); ulong rgStart = _handles[startHandle].Address; ulong rgSize = 0; for (int i = startHandle; i <= lastHandle; i++) { RegionHandle handle = _handles[i]; if (handle.Dirty) { rgSize += handle.Size; handle.Reprotect(); } else { // Submit the region scanned so far as dirty if (rgSize != 0) { modifiedAction(rgStart, rgSize); rgSize = 0; } rgStart = handle.EndAddress; } } if (rgSize != 0) { modifiedAction(rgStart, rgSize); } }
private void SplitHandle(int handleIndex, int splitIndex) { RegionHandle handle = _handles[handleIndex]; ulong address = _address + HandlesToBytes(handleIndex); ulong size = HandlesToBytes(splitIndex - handleIndex); // First, the target handle must be removed. Its data can still be used to determine the new handles. RegionSignal signal = handle.PreAction; handle.Dispose(); RegionHandle splitLow = _tracking.BeginTracking(address, size); splitLow.Parent = this; if (signal != null) { splitLow.RegisterAction(signal); } _handles[handleIndex] = splitLow; RegionHandle splitHigh = _tracking.BeginTracking(address + size, handle.Size - size); splitHigh.Parent = this; if (signal != null) { splitHigh.RegisterAction(signal); } _handles[splitIndex] = splitHigh; }
/// <summary> /// Removes a handle from this virtual region. If there are no handles left, this virtual region is removed. /// </summary> /// <param name="handle">Handle to remove</param> public void RemoveHandle(RegionHandle handle) { bool removedRegions = false; lock (_tracking.TrackingLock) { Handles.Remove(handle); UpdateProtection(); if (Handles.Count == 0) { _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(); } } } }
public void QueryModified(ulong address, ulong size, Action <ulong, ulong> modifiedAction, int sequenceNumber) { int startHandle = (int)((address - _address) / _granularity); int lastHandle = (int)((address + (size - 1) - _address) / _granularity); ulong rgStart = _address + (ulong)startHandle * _granularity; ulong rgSize = 0; ulong endAddress = _address + ((ulong)lastHandle + 1) * _granularity; int i = startHandle; while (i <= lastHandle) { RegionHandle handle = _handles[i]; if (handle == null) { // Missing handle. A new handle must be created. CreateHandle(i, lastHandle); handle = _handles[i]; } if (handle.EndAddress > endAddress) { // End address of handle is beyond the end of the search. Force a split. SplitHandle(i, lastHandle + 1); handle = _handles[i]; } if (handle.Dirty && sequenceNumber != handle.SequenceNumber) { rgSize += handle.Size; handle.Reprotect(); } else { // Submit the region scanned so far as dirty if (rgSize != 0) { modifiedAction(rgStart, rgSize); rgSize = 0; } rgStart = handle.EndAddress; } handle.SequenceNumber = sequenceNumber; i += (int)(handle.Size / _granularity); } if (rgSize != 0) { modifiedAction(rgStart, rgSize); } }
/// <summary> /// Obtains a memory tracking handle for the given virtual region. This should be disposed when finished with. /// </summary> /// <param name="address">CPU virtual address of the region</param> /// <param name="size">Size of the region</param> /// <returns>The memory tracking handle</returns> public RegionHandle BeginTracking(ulong address, ulong size) { (address, size) = PageAlign(address, size); lock (TrackingLock) { RegionHandle handle = new RegionHandle(this, address, size, _memoryManager.IsRangeMapped(address, size)); return(handle); } }
/// <summary> /// Removes a handle from this virtual region. If there are no handles left, this virtual region is removed. /// </summary> /// <param name="handle">Handle to remove</param> public void RemoveHandle(RegionHandle handle) { lock (_tracking.TrackingLock) { Handles.Remove(handle); UpdateProtection(); if (Handles.Count == 0) { _tracking.RemoveVirtual(this); } } }
internal MultiRegionHandle(MemoryTracking tracking, ulong address, ulong size, ulong granularity) { _handles = new RegionHandle[size / granularity]; Granularity = granularity; for (int i = 0; i < _handles.Length; i++) { RegionHandle handle = tracking.BeginTracking(address + (ulong)i * granularity, granularity); handle.Parent = this; _handles[i] = handle; } Address = address; Size = size; }
private void CreateHandle(int startHandle, int lastHandle) { ulong startAddress = _address + HandlesToBytes(startHandle); // Scan for the first handle before us. If it's overlapping us, it must be split. for (int i = startHandle - 1; i >= 0; i--) { RegionHandle handle = _handles[i]; if (handle != null) { if (handle.EndAddress > startAddress) { SplitHandle(i, startHandle); return; // The remainer of this handle should be filled in later on. } break; } } // Scan for handles after us. We should create a handle that goes up to this handle's start point, if present. for (int i = startHandle + 1; i <= lastHandle; i++) { RegionHandle handle = _handles[i]; if (handle != null) { // Fill up to the found handle. handle = _tracking.BeginTracking(startAddress, HandlesToBytes(i - startHandle)); handle.Parent = this; _handles[startHandle] = handle; return; } } // Can fill the whole range. _handles[startHandle] = _tracking.BeginTracking(startAddress, HandlesToBytes(1 + lastHandle - startHandle)); _handles[startHandle].Parent = this; }
internal MultiRegionHandle(MemoryTracking tracking, ulong address, ulong size, IEnumerable <IRegionHandle> handles, ulong granularity) { _handles = new RegionHandle[size / granularity]; Granularity = granularity; int i = 0; if (handles != null) { // Inherit from the handles we were given. Any gaps must be filled with new handles, // and old handles larger than our granularity must copy their state onto new granular handles and dispose. // It is assumed that the provided handles do not overlap, in order, are on page boundaries, // and don't extend past the requested range. foreach (RegionHandle handle in handles) { int startIndex = (int)((handle.Address - address) / granularity); // Fill any gap left before this handle. while (i < startIndex) { RegionHandle fillHandle = tracking.BeginTracking(address + (ulong)i * granularity, granularity); fillHandle.Parent = this; _handles[i++] = fillHandle; } if (handle.Size == granularity) { handle.Parent = this; _handles[i++] = handle; } else { int endIndex = (int)((handle.EndAddress - address) / granularity); while (i < endIndex) { RegionHandle splitHandle = tracking.BeginTracking(address + (ulong)i * granularity, granularity); splitHandle.Parent = this; splitHandle.Reprotect(handle.Dirty); RegionSignal signal = handle.PreAction; if (signal != null) { splitHandle.RegisterAction(signal); } _handles[i++] = splitHandle; } handle.Dispose(); } } } // Fill any remaining space with new handles. while (i < _handles.Length) { RegionHandle handle = tracking.BeginTracking(address + (ulong)i * granularity, granularity); handle.Parent = this; _handles[i++] = handle; } Address = address; Size = size; }