kernel: optimize page free on shutdown

master
Liam 2024-01-12 19:19:07 +07:00
parent f90a022d3a
commit 2f0b57ca13
3 changed files with 18 additions and 63 deletions

@ -28,14 +28,14 @@ Result KMemoryBlockManager::Initialize(KProcessAddress st, KProcessAddress nd,
} }
void KMemoryBlockManager::Finalize(KMemoryBlockSlabManager* slab_manager, void KMemoryBlockManager::Finalize(KMemoryBlockSlabManager* slab_manager,
HostUnmapCallback&& host_unmap_callback) { BlockCallback&& block_callback) {
// Erase every block until we have none left. // Erase every block until we have none left.
auto it = m_memory_block_tree.begin(); auto it = m_memory_block_tree.begin();
while (it != m_memory_block_tree.end()) { while (it != m_memory_block_tree.end()) {
KMemoryBlock* block = std::addressof(*it); KMemoryBlock* block = std::addressof(*it);
it = m_memory_block_tree.erase(it); it = m_memory_block_tree.erase(it);
block_callback(block->GetAddress(), block->GetSize());
slab_manager->Free(block); slab_manager->Free(block);
host_unmap_callback(block->GetAddress(), block->GetSize());
} }
ASSERT(m_memory_block_tree.empty()); ASSERT(m_memory_block_tree.empty());

@ -85,11 +85,11 @@ public:
public: public:
KMemoryBlockManager(); KMemoryBlockManager();
using HostUnmapCallback = std::function<void(Common::ProcessAddress, u64)>; using BlockCallback = std::function<void(Common::ProcessAddress, u64)>;
Result Initialize(KProcessAddress st, KProcessAddress nd, Result Initialize(KProcessAddress st, KProcessAddress nd,
KMemoryBlockSlabManager* slab_manager); KMemoryBlockSlabManager* slab_manager);
void Finalize(KMemoryBlockSlabManager* slab_manager, HostUnmapCallback&& host_unmap_callback); void Finalize(KMemoryBlockSlabManager* slab_manager, BlockCallback&& block_callback);
iterator end() { iterator end() {
return m_memory_block_tree.end(); return m_memory_block_tree.end();

@ -435,69 +435,14 @@ Result KPageTableBase::FinalizeProcess() {
// Only process tables should be finalized. // Only process tables should be finalized.
ASSERT(!this->IsKernel()); ASSERT(!this->IsKernel());
// HLE processes don't have memory mapped.
R_SUCCEED_IF(m_impl == nullptr);
// NOTE: Here Nintendo calls an unknown OnFinalize function. // NOTE: Here Nintendo calls an unknown OnFinalize function.
// this->OnFinalize(); // this->OnFinalize();
// NOTE: Here Nintendo calls a second unknown OnFinalize function. // NOTE: Here Nintendo calls a second unknown OnFinalize function.
// this->OnFinalize2(); // this->OnFinalize2();
// Get implementation objects. // NOTE: Here Nintendo does a page table walk to discover heap pages to free.
auto& impl = this->GetImpl(); // We will use the block manager finalization below to free them.
auto& mm = m_kernel.MemoryManager();
// Traverse, freeing all pages.
{
// Get the address space size.
const size_t as_size = this->GetAddressSpaceSize();
// Begin the traversal.
TraversalContext context;
TraversalEntry cur_entry = {
.phys_addr = 0,
.block_size = 0,
};
bool cur_valid = false;
TraversalEntry next_entry;
bool next_valid;
size_t tot_size = 0;
next_valid = impl.BeginTraversal(std::addressof(next_entry), std::addressof(context),
this->GetAddressSpaceStart());
// Iterate over entries.
while (true) {
if ((!next_valid && !cur_valid) ||
(next_valid && cur_valid &&
next_entry.phys_addr == cur_entry.phys_addr + cur_entry.block_size)) {
cur_entry.block_size += next_entry.block_size;
} else {
if (cur_valid && IsHeapPhysicalAddressForFinalize(cur_entry.phys_addr)) {
mm.Close(cur_entry.phys_addr, cur_entry.block_size / PageSize);
}
// Update tracking variables.
tot_size += cur_entry.block_size;
cur_entry = next_entry;
cur_valid = next_valid;
}
if (cur_entry.block_size + tot_size >= as_size) {
break;
}
next_valid =
impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context));
}
// Handle the last block.
if (cur_valid && IsHeapPhysicalAddressForFinalize(cur_entry.phys_addr)) {
mm.Close(cur_entry.phys_addr, cur_entry.block_size / PageSize);
}
}
R_SUCCEED(); R_SUCCEED();
} }
@ -505,14 +450,24 @@ Result KPageTableBase::FinalizeProcess() {
void KPageTableBase::Finalize() { void KPageTableBase::Finalize() {
this->FinalizeProcess(); this->FinalizeProcess();
auto HostUnmapCallback = [&](KProcessAddress addr, u64 size) { auto BlockCallback = [&](KProcessAddress addr, u64 size) {
if (m_impl->fastmem_arena) { if (m_impl->fastmem_arena) {
m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size, false); m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size, false);
} }
// Get physical pages.
KPageGroup pg(m_kernel, m_block_info_manager);
this->MakePageGroup(pg, addr, size / PageSize);
// Free the pages.
pg.CloseAndReset();
}; };
// Finalize memory blocks. // Finalize memory blocks.
m_memory_block_manager.Finalize(m_memory_block_slab_manager, std::move(HostUnmapCallback)); {
KScopedLightLock lk(m_general_lock);
m_memory_block_manager.Finalize(m_memory_block_slab_manager, std::move(BlockCallback));
}
// Free any unsafe mapped memory. // Free any unsafe mapped memory.
if (m_mapped_unsafe_physical_memory) { if (m_mapped_unsafe_physical_memory) {