kernel/vm_manager: Handle shrinking of the heap size within SetHeapSize()

One behavior that we weren't handling properly in our heap allocation
process was the ability for the heap to be shrunk down in size if a
larger size was previously requested.

This adds the basic behavior to do so and also gets rid of HeapFree, as
it's no longer necessary now that we have allocations and deallocations
going through the same API function.

While we're at it, fully document the behavior that this function
performs.
This commit is contained in:
Lioncash 2019-03-24 16:30:45 -04:00
parent 99a163478b
commit 1e92ba2785
2 changed files with 46 additions and 24 deletions

View file

@ -274,14 +274,23 @@ ResultVal<VAddr> VMManager::SetHeapSize(u64 size) {
UnmapRange(heap_region_base, GetCurrentHeapSize()); UnmapRange(heap_region_base, GetCurrentHeapSize());
} }
// If necessary, expand backing vector to cover new heap extents. // If necessary, expand backing vector to cover new heap extents in
if (size > GetCurrentHeapSize()) { // the case of allocating. Otherwise, shrink the backing memory,
const u64 alloc_size = size - GetCurrentHeapSize(); // if a smaller heap has been requested.
const u64 old_heap_size = GetCurrentHeapSize();
if (size > old_heap_size) {
const u64 alloc_size = size - old_heap_size;
heap_memory->insert(heap_memory->end(), alloc_size, 0); heap_memory->insert(heap_memory->end(), alloc_size, 0);
heap_end = heap_region_base + size; RefreshMemoryBlockMappings(heap_memory.get());
} else if (size < old_heap_size) {
heap_memory->resize(size);
heap_memory->shrink_to_fit();
RefreshMemoryBlockMappings(heap_memory.get()); RefreshMemoryBlockMappings(heap_memory.get());
} }
heap_end = heap_region_base + size;
ASSERT(GetCurrentHeapSize() == heap_memory->size()); ASSERT(GetCurrentHeapSize() == heap_memory->size());
const auto mapping_result = const auto mapping_result =
@ -293,23 +302,6 @@ ResultVal<VAddr> VMManager::SetHeapSize(u64 size) {
return MakeResult<VAddr>(heap_region_base); return MakeResult<VAddr>(heap_region_base);
} }
ResultCode VMManager::HeapFree(VAddr target, u64 size) {
if (!IsWithinHeapRegion(target, size)) {
return ERR_INVALID_ADDRESS;
}
if (size == 0) {
return RESULT_SUCCESS;
}
const ResultCode result = UnmapRange(target, size);
if (result.IsError()) {
return result;
}
return RESULT_SUCCESS;
}
MemoryInfo VMManager::QueryMemory(VAddr address) const { MemoryInfo VMManager::QueryMemory(VAddr address) const {
const auto vma = FindVMA(address); const auto vma = FindVMA(address);
MemoryInfo memory_info{}; MemoryInfo memory_info{};

View file

@ -380,11 +380,41 @@ public:
/// Changes the permissions of a range of addresses, splitting VMAs as necessary. /// Changes the permissions of a range of addresses, splitting VMAs as necessary.
ResultCode ReprotectRange(VAddr target, u64 size, VMAPermission new_perms); ResultCode ReprotectRange(VAddr target, u64 size, VMAPermission new_perms);
ResultVal<VAddr> SetHeapSize(u64 size);
ResultCode HeapFree(VAddr target, u64 size);
ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, MemoryState state); ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, MemoryState state);
/// Attempts to allocate a heap with the given size.
///
/// @param size The size of the heap to allocate in bytes.
///
/// @note If a heap is currently allocated, and this is called
/// with a size that is equal to the size of the current heap,
/// then this function will do nothing and return the current
/// heap's starting address, as there's no need to perform
/// any additional heap allocation work.
///
/// @note If a heap is currently allocated, and this is called
/// with a size less than the current heap's size, then
/// this function will attempt to shrink the heap.
///
/// @note If a heap is currently allocated, and this is called
/// with a size larger than the current heap's size, then
/// this function will attempt to extend the size of the heap.
///
/// @returns A result indicating either success or failure.
/// <p>
/// If successful, this function will return a result
/// containing the starting address to the allocated heap.
/// <p>
/// If unsuccessful, this function will return a result
/// containing an error code.
///
/// @pre The given size must lie within the allowable heap
/// memory region managed by this VMManager instance.
/// Failure to abide by this will result in ERR_OUT_OF_MEMORY
/// being returned as the result.
///
ResultVal<VAddr> SetHeapSize(u64 size);
/// Queries the memory manager for information about the given address. /// Queries the memory manager for information about the given address.
/// ///
/// @param address The address to query the memory manager about for information. /// @param address The address to query the memory manager about for information.