From dc39d06950de246094be9643313970125e0c49ee Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Fri, 17 Jul 2015 02:24:13 -0300 Subject: [PATCH] Ensure all kernel objects are released during shutdown This commit fixes several kernel object leaks. The most severe of them was threads not being removed from the private handle table used for CoreTiming events. This resulted in Threads never being released, which in turn held references to Process, causing CodeSets to never be freed when loading other applications. --- src/core/hle/kernel/thread.cpp | 21 ++++++++++++++------- src/core/hle/service/apt/apt.cpp | 3 +++ src/core/hle/service/dsp_dsp.cpp | 5 +++++ src/core/hle/service/dsp_dsp.h | 1 + src/core/hle/service/gsp_gpu.cpp | 7 ++++++- src/core/hle/service/gsp_gpu.h | 1 + src/core/hle/service/nwm_uds.cpp | 4 ++++ src/core/hle/service/nwm_uds.h | 1 + src/core/hle/service/srv.cpp | 4 ++++ src/core/hle/service/srv.h | 1 + src/core/hle/service/y2r_u.cpp | 4 ++++ src/core/hle/service/y2r_u.h | 1 + 12 files changed, 45 insertions(+), 8 deletions(-) diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 4729a7fe03..64166ab993 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -37,6 +37,10 @@ void Thread::Acquire() { ASSERT_MSG(!ShouldWait(), "object unavailable!"); } +// TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, allowing +// us to simply use a pool index or similar. +static Kernel::HandleTable wakeup_callback_handle_table; + // Lists all thread ids that aren't deleted/etc. static std::vector> thread_list; @@ -93,6 +97,8 @@ void Thread::Stop() { // Cancel any outstanding wakeup events for this thread CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); + wakeup_callback_handle_table.Close(callback_handle); + callback_handle = 0; // Clean up thread from ready queue // This is only needed when the thread is termintated forcefully (SVC TerminateProcess) @@ -108,6 +114,7 @@ void Thread::Stop() { for (auto& wait_object : wait_objects) { wait_object->RemoveWaitingThread(this); } + wait_objects.clear(); Kernel::g_current_process->used_tls_slots[tls_index] = false; @@ -268,10 +275,6 @@ void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) { thread->status = THREADSTATUS_WAIT_ARB; } -// TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, allowing -// us to simply use a pool index or similar. -static Kernel::HandleTable wakeup_callback_handle_table; - /** * Callback that will wake up the thread it was scheduled for * @param thread_handle The handle of the thread that's been awoken @@ -503,12 +506,16 @@ void ThreadingInit() { current_thread = nullptr; next_thread_id = 1; +} +void ThreadingShutdown() { + current_thread = nullptr; + + for (auto& t : thread_list) { + t->Stop(); + } thread_list.clear(); ready_queue.clear(); } -void ThreadingShutdown() { -} - } // namespace diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index b364beed92..7b6ab4ce01 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -406,6 +406,9 @@ void Shutdown() { lock = nullptr; notification_event = nullptr; parameter_event = nullptr; + + next_parameter.object = nullptr; + HLE::Applets::Shutdown(); } diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp index fafb43a2fa..a8cb15d603 100644 --- a/src/core/hle/service/dsp_dsp.cpp +++ b/src/core/hle/service/dsp_dsp.cpp @@ -310,4 +310,9 @@ Interface::Interface() { Register(FunctionTable); } +Interface::~Interface() { + semaphore_event = nullptr; + interrupt_event = nullptr; +} + } // namespace diff --git a/src/core/hle/service/dsp_dsp.h b/src/core/hle/service/dsp_dsp.h index 54109b2a9e..b6f611db5c 100644 --- a/src/core/hle/service/dsp_dsp.h +++ b/src/core/hle/service/dsp_dsp.h @@ -16,6 +16,7 @@ namespace DSP_DSP { class Interface : public Service::Interface { public: Interface(); + ~Interface() override; std::string GetPortName() const override { return "dsp::DSP"; diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index 3910d02270..8b40ba3760 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp @@ -584,7 +584,7 @@ const Interface::FunctionInfo FunctionTable[] = { Interface::Interface() { Register(FunctionTable); - g_interrupt_event = 0; + g_interrupt_event = nullptr; using Kernel::MemoryPermission; g_shared_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite, @@ -593,4 +593,9 @@ Interface::Interface() { g_thread_id = 0; } +Interface::~Interface() { + g_interrupt_event = nullptr; + g_shared_memory = nullptr; +} + } // namespace diff --git a/src/core/hle/service/gsp_gpu.h b/src/core/hle/service/gsp_gpu.h index 268089fdd3..c89d0a4679 100644 --- a/src/core/hle/service/gsp_gpu.h +++ b/src/core/hle/service/gsp_gpu.h @@ -161,6 +161,7 @@ static_assert(sizeof(CommandBuffer) == 0x200, "CommandBuffer struct has incorrec class Interface : public Service::Interface { public: Interface(); + ~Interface() override; std::string GetPortName() const override { return "gsp::Gpu"; diff --git a/src/core/hle/service/nwm_uds.cpp b/src/core/hle/service/nwm_uds.cpp index 25b01860e5..18b22956ff 100644 --- a/src/core/hle/service/nwm_uds.cpp +++ b/src/core/hle/service/nwm_uds.cpp @@ -125,4 +125,8 @@ Interface::Interface() { Register(FunctionTable); } +Interface::~Interface() { + handle_event = nullptr; +} + } // namespace diff --git a/src/core/hle/service/nwm_uds.h b/src/core/hle/service/nwm_uds.h index 82abdff28a..0ced2359ce 100644 --- a/src/core/hle/service/nwm_uds.h +++ b/src/core/hle/service/nwm_uds.h @@ -16,6 +16,7 @@ namespace NWM_UDS { class Interface : public Service::Interface { public: Interface(); + ~Interface() override; std::string GetPortName() const override { return "nwm::UDS"; diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index 6c49fa6cf0..3b8c7c0e44 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp @@ -68,4 +68,8 @@ Interface::Interface() { Register(FunctionTable); } +Interface::~Interface() { + event_handle = nullptr; +} + } // namespace diff --git a/src/core/hle/service/srv.h b/src/core/hle/service/srv.h index 653aba5cb3..96c89b0255 100644 --- a/src/core/hle/service/srv.h +++ b/src/core/hle/service/srv.h @@ -13,6 +13,7 @@ namespace SRV { class Interface : public Service::Interface { public: Interface(); + ~Interface() override; std::string GetPortName() const override { return "srv:"; diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp index e121a54e33..6e7dafaad4 100644 --- a/src/core/hle/service/y2r_u.cpp +++ b/src/core/hle/service/y2r_u.cpp @@ -410,4 +410,8 @@ Interface::Interface() { Register(FunctionTable); } +Interface::~Interface() { + completion_event = nullptr; +} + } // namespace diff --git a/src/core/hle/service/y2r_u.h b/src/core/hle/service/y2r_u.h index 9454e5aabe..3965a55456 100644 --- a/src/core/hle/service/y2r_u.h +++ b/src/core/hle/service/y2r_u.h @@ -112,6 +112,7 @@ struct ConversionConfiguration { class Interface : public Service::Interface { public: Interface(); + ~Interface() override; std::string GetPortName() const override { return "y2r:u";