forked from suyu/suyu
Merge pull request #7227 from vonchenplus/fix_memory_leak_v2
Fix memory leak v2
This commit is contained in:
commit
b118fa8698
6 changed files with 54 additions and 24 deletions
|
@ -83,12 +83,6 @@ FileSys::StorageId GetStorageIdForFrontendSlot(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KProcessDeleter(Kernel::KProcess* process) {
|
|
||||||
process->Destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
using KProcessPtr = std::unique_ptr<Kernel::KProcess, decltype(&KProcessDeleter)>;
|
|
||||||
|
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
|
FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
|
||||||
|
@ -261,11 +255,10 @@ struct System::Impl {
|
||||||
}
|
}
|
||||||
|
|
||||||
telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider);
|
telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider);
|
||||||
main_process = KProcessPtr{Kernel::KProcess::Create(system.Kernel()), KProcessDeleter};
|
auto main_process = Kernel::KProcess::Create(system.Kernel());
|
||||||
ASSERT(Kernel::KProcess::Initialize(main_process.get(), system, "main",
|
ASSERT(Kernel::KProcess::Initialize(main_process, system, "main",
|
||||||
Kernel::KProcess::ProcessType::Userland)
|
Kernel::KProcess::ProcessType::Userland)
|
||||||
.IsSuccess());
|
.IsSuccess());
|
||||||
main_process->Open();
|
|
||||||
const auto [load_result, load_parameters] = app_loader->Load(*main_process, system);
|
const auto [load_result, load_parameters] = app_loader->Load(*main_process, system);
|
||||||
if (load_result != Loader::ResultStatus::Success) {
|
if (load_result != Loader::ResultStatus::Success) {
|
||||||
LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", load_result);
|
LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", load_result);
|
||||||
|
@ -275,7 +268,7 @@ struct System::Impl {
|
||||||
static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result));
|
static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result));
|
||||||
}
|
}
|
||||||
AddGlueRegistrationForProcess(*app_loader, *main_process);
|
AddGlueRegistrationForProcess(*app_loader, *main_process);
|
||||||
kernel.MakeCurrentProcess(main_process.get());
|
kernel.MakeCurrentProcess(main_process);
|
||||||
kernel.InitializeCores();
|
kernel.InitializeCores();
|
||||||
|
|
||||||
// Initialize cheat engine
|
// Initialize cheat engine
|
||||||
|
@ -340,8 +333,6 @@ struct System::Impl {
|
||||||
kernel.Shutdown();
|
kernel.Shutdown();
|
||||||
memory.Reset();
|
memory.Reset();
|
||||||
applet_manager.ClearAll();
|
applet_manager.ClearAll();
|
||||||
// TODO: The main process should be freed based on KAutoObject ref counting.
|
|
||||||
main_process.reset();
|
|
||||||
|
|
||||||
LOG_DEBUG(Core, "Shutdown OK");
|
LOG_DEBUG(Core, "Shutdown OK");
|
||||||
}
|
}
|
||||||
|
@ -403,7 +394,6 @@ struct System::Impl {
|
||||||
std::unique_ptr<Tegra::GPU> gpu_core;
|
std::unique_ptr<Tegra::GPU> gpu_core;
|
||||||
std::unique_ptr<Hardware::InterruptManager> interrupt_manager;
|
std::unique_ptr<Hardware::InterruptManager> interrupt_manager;
|
||||||
std::unique_ptr<Core::DeviceMemory> device_memory;
|
std::unique_ptr<Core::DeviceMemory> device_memory;
|
||||||
KProcessPtr main_process{nullptr, KProcessDeleter};
|
|
||||||
Core::Memory::Memory memory;
|
Core::Memory::Memory memory;
|
||||||
CpuManager cpu_manager;
|
CpuManager cpu_manager;
|
||||||
std::atomic_bool is_powered_on{};
|
std::atomic_bool is_powered_on{};
|
||||||
|
|
|
@ -56,6 +56,7 @@ bool KHandleTable::Remove(Handle handle) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the object.
|
// Close the object.
|
||||||
|
kernel.UnregisterInUseObject(obj);
|
||||||
obj->Close();
|
obj->Close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -434,11 +434,6 @@ void KProcess::PrepareForTermination() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void KProcess::Finalize() {
|
void KProcess::Finalize() {
|
||||||
// Release memory to the resource limit.
|
|
||||||
if (resource_limit != nullptr) {
|
|
||||||
resource_limit->Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finalize the handle table and close any open handles.
|
// Finalize the handle table and close any open handles.
|
||||||
handle_table.Finalize();
|
handle_table.Finalize();
|
||||||
|
|
||||||
|
@ -460,6 +455,12 @@ void KProcess::Finalize() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Release memory to the resource limit.
|
||||||
|
if (resource_limit != nullptr) {
|
||||||
|
resource_limit->Close();
|
||||||
|
resource_limit = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// Perform inherited finalization.
|
// Perform inherited finalization.
|
||||||
KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject>::Finalize();
|
KAutoObjectWithSlabHeapAndContainer<KProcess, KSynchronizationObject>::Finalize();
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,12 +91,6 @@ struct KernelCore::Impl {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown() {
|
void Shutdown() {
|
||||||
// Shutdown all processes.
|
|
||||||
if (current_process) {
|
|
||||||
current_process->Finalize();
|
|
||||||
current_process->Close();
|
|
||||||
current_process = nullptr;
|
|
||||||
}
|
|
||||||
process_list.clear();
|
process_list.clear();
|
||||||
|
|
||||||
// Close all open server ports.
|
// Close all open server ports.
|
||||||
|
@ -170,6 +164,24 @@ struct KernelCore::Impl {
|
||||||
// Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
|
// Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
|
||||||
next_host_thread_id = Core::Hardware::NUM_CPU_CORES;
|
next_host_thread_id = Core::Hardware::NUM_CPU_CORES;
|
||||||
|
|
||||||
|
// Close kernel objects that were not freed on shutdown
|
||||||
|
{
|
||||||
|
std::lock_guard lk(registered_in_use_objects_lock);
|
||||||
|
if (registered_in_use_objects.size()) {
|
||||||
|
for (auto& object : registered_in_use_objects) {
|
||||||
|
object->Close();
|
||||||
|
}
|
||||||
|
registered_in_use_objects.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shutdown all processes.
|
||||||
|
if (current_process) {
|
||||||
|
current_process->Finalize();
|
||||||
|
current_process->Close();
|
||||||
|
current_process = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// Track kernel objects that were not freed on shutdown
|
// Track kernel objects that were not freed on shutdown
|
||||||
{
|
{
|
||||||
std::lock_guard lk(registered_objects_lock);
|
std::lock_guard lk(registered_objects_lock);
|
||||||
|
@ -714,9 +726,11 @@ struct KernelCore::Impl {
|
||||||
std::unordered_set<KServerPort*> server_ports;
|
std::unordered_set<KServerPort*> server_ports;
|
||||||
std::unordered_set<KServerSession*> server_sessions;
|
std::unordered_set<KServerSession*> server_sessions;
|
||||||
std::unordered_set<KAutoObject*> registered_objects;
|
std::unordered_set<KAutoObject*> registered_objects;
|
||||||
|
std::unordered_set<KAutoObject*> registered_in_use_objects;
|
||||||
std::mutex server_ports_lock;
|
std::mutex server_ports_lock;
|
||||||
std::mutex server_sessions_lock;
|
std::mutex server_sessions_lock;
|
||||||
std::mutex registered_objects_lock;
|
std::mutex registered_objects_lock;
|
||||||
|
std::mutex registered_in_use_objects_lock;
|
||||||
|
|
||||||
std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
|
std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
|
||||||
std::vector<Kernel::PhysicalCore> cores;
|
std::vector<Kernel::PhysicalCore> cores;
|
||||||
|
@ -928,6 +942,16 @@ void KernelCore::UnregisterKernelObject(KAutoObject* object) {
|
||||||
impl->registered_objects.erase(object);
|
impl->registered_objects.erase(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KernelCore::RegisterInUseObject(KAutoObject* object) {
|
||||||
|
std::lock_guard lk(impl->registered_in_use_objects_lock);
|
||||||
|
impl->registered_in_use_objects.insert(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KernelCore::UnregisterInUseObject(KAutoObject* object) {
|
||||||
|
std::lock_guard lk(impl->registered_in_use_objects_lock);
|
||||||
|
impl->registered_in_use_objects.erase(object);
|
||||||
|
}
|
||||||
|
|
||||||
bool KernelCore::IsValidNamedPort(NamedPortTable::const_iterator port) const {
|
bool KernelCore::IsValidNamedPort(NamedPortTable::const_iterator port) const {
|
||||||
return port != impl->named_ports.cend();
|
return port != impl->named_ports.cend();
|
||||||
}
|
}
|
||||||
|
|
|
@ -204,6 +204,14 @@ public:
|
||||||
/// destroyed during the current emulation session.
|
/// destroyed during the current emulation session.
|
||||||
void UnregisterKernelObject(KAutoObject* object);
|
void UnregisterKernelObject(KAutoObject* object);
|
||||||
|
|
||||||
|
/// Registers kernel objects with guest in use state, this is purely for close
|
||||||
|
/// after emulation has been shutdown.
|
||||||
|
void RegisterInUseObject(KAutoObject* object);
|
||||||
|
|
||||||
|
/// Unregisters a kernel object previously registered with RegisterInUseObject when it was
|
||||||
|
/// destroyed during the current emulation session.
|
||||||
|
void UnregisterInUseObject(KAutoObject* object);
|
||||||
|
|
||||||
/// Determines whether or not the given port is a valid named port.
|
/// Determines whether or not the given port is a valid named port.
|
||||||
bool IsValidNamedPort(NamedPortTable::const_iterator port) const;
|
bool IsValidNamedPort(NamedPortTable::const_iterator port) const;
|
||||||
|
|
||||||
|
|
|
@ -427,11 +427,15 @@ static ResultCode WaitSynchronization(Core::System& system, s32* index, VAddr ha
|
||||||
R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles,
|
R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles,
|
||||||
num_handles),
|
num_handles),
|
||||||
ResultInvalidHandle);
|
ResultInvalidHandle);
|
||||||
|
for (const auto& obj : objs) {
|
||||||
|
kernel.RegisterInUseObject(obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure handles are closed when we're done.
|
// Ensure handles are closed when we're done.
|
||||||
SCOPE_EXIT({
|
SCOPE_EXIT({
|
||||||
for (u64 i = 0; i < num_handles; ++i) {
|
for (u64 i = 0; i < num_handles; ++i) {
|
||||||
|
kernel.UnregisterInUseObject(objs[i]);
|
||||||
objs[i]->Close();
|
objs[i]->Close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1561,6 +1565,7 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) {
|
||||||
|
|
||||||
// If we succeeded, persist a reference to the thread.
|
// If we succeeded, persist a reference to the thread.
|
||||||
thread->Open();
|
thread->Open();
|
||||||
|
system.Kernel().RegisterInUseObject(thread.GetPointerUnsafe());
|
||||||
|
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
@ -1576,6 +1581,7 @@ static void ExitThread(Core::System& system) {
|
||||||
auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread();
|
auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread();
|
||||||
system.GlobalSchedulerContext().RemoveThread(current_thread);
|
system.GlobalSchedulerContext().RemoveThread(current_thread);
|
||||||
current_thread->Exit();
|
current_thread->Exit();
|
||||||
|
system.Kernel().UnregisterInUseObject(current_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ExitThread32(Core::System& system) {
|
static void ExitThread32(Core::System& system) {
|
||||||
|
|
Loading…
Reference in a new issue