/// <summary> /// Marks a range of memory as free by adding it to the tree. /// This function will automatically compact the tree when it determines there are multiple ranges of free memory adjacent to each other. /// </summary> /// <param name="va">Virtual address at which to deallocate</param> /// <param name="size">Size of the allocation in bytes</param> public void DeallocateRange(ulong va, ulong size) { lock (_tree) { Logger.Debug?.Print(LogClass.ServiceNv, $"Deallocating address range from 0x{va:X} to 0x{(va + size):X}."); ulong freeAddressStartPosition = _tree.Floor(va); if (freeAddressStartPosition != InvalidAddress) { LinkedListNode <ulong> node = _dictionary[freeAddressStartPosition]; ulong targetPrevAddress = _dictionary[freeAddressStartPosition].Previous != null ? _dictionary[_dictionary[freeAddressStartPosition].Previous.Value].Value : InvalidAddress; ulong targetNextAddress = _dictionary[freeAddressStartPosition].Next != null ? _dictionary[_dictionary[freeAddressStartPosition].Next.Value].Value : InvalidAddress; ulong expandedStart = va; ulong expandedEnd = va + size; while (targetPrevAddress != InvalidAddress) { ulong prevAddress = targetPrevAddress; ulong prevEndAddress = _tree.Get(targetPrevAddress); if (prevEndAddress >= expandedStart) { expandedStart = targetPrevAddress; LinkedListNode <ulong> prevPtr = _dictionary[prevAddress]; if (prevPtr.Previous != null) { targetPrevAddress = prevPtr.Previous.Value; } else { targetPrevAddress = InvalidAddress; } node = node.Previous; _tree.Remove(prevAddress); _list.Remove(_dictionary[prevAddress]); _dictionary.Remove(prevAddress); } else { break; } } while (targetNextAddress != InvalidAddress) { ulong nextAddress = targetNextAddress; ulong nextEndAddress = _tree.Get(targetNextAddress); if (nextAddress <= expandedEnd) { expandedEnd = Math.Max(expandedEnd, nextEndAddress); LinkedListNode <ulong> nextPtr = _dictionary[nextAddress]; if (nextPtr.Next != null) { targetNextAddress = nextPtr.Next.Value; } else { targetNextAddress = InvalidAddress; } _tree.Remove(nextAddress); _list.Remove(_dictionary[nextAddress]); _dictionary.Remove(nextAddress); } else { break; } } Logger.Debug?.Print(LogClass.ServiceNv, $"Deallocation resulted in new free range from 0x{expandedStart:X} to 0x{expandedEnd:X}."); _tree.Add(expandedStart, expandedEnd); LinkedListNode <ulong> nodePtr = _list.AddAfter(node, expandedStart); _dictionary[expandedStart] = nodePtr; } } }