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.
This commit is contained in:
parent
078bf29d1d
commit
dc39d06950
@ -37,6 +37,10 @@ void Thread::Acquire() {
|
|||||||
ASSERT_MSG(!ShouldWait(), "object unavailable!");
|
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.
|
// Lists all thread ids that aren't deleted/etc.
|
||||||
static std::vector<SharedPtr<Thread>> thread_list;
|
static std::vector<SharedPtr<Thread>> thread_list;
|
||||||
|
|
||||||
@ -93,6 +97,8 @@ void Thread::Stop() {
|
|||||||
|
|
||||||
// Cancel any outstanding wakeup events for this thread
|
// Cancel any outstanding wakeup events for this thread
|
||||||
CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle);
|
CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle);
|
||||||
|
wakeup_callback_handle_table.Close(callback_handle);
|
||||||
|
callback_handle = 0;
|
||||||
|
|
||||||
// Clean up thread from ready queue
|
// Clean up thread from ready queue
|
||||||
// This is only needed when the thread is termintated forcefully (SVC TerminateProcess)
|
// 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) {
|
for (auto& wait_object : wait_objects) {
|
||||||
wait_object->RemoveWaitingThread(this);
|
wait_object->RemoveWaitingThread(this);
|
||||||
}
|
}
|
||||||
|
wait_objects.clear();
|
||||||
|
|
||||||
Kernel::g_current_process->used_tls_slots[tls_index] = false;
|
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;
|
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
|
* Callback that will wake up the thread it was scheduled for
|
||||||
* @param thread_handle The handle of the thread that's been awoken
|
* @param thread_handle The handle of the thread that's been awoken
|
||||||
@ -503,12 +506,16 @@ void ThreadingInit() {
|
|||||||
|
|
||||||
current_thread = nullptr;
|
current_thread = nullptr;
|
||||||
next_thread_id = 1;
|
next_thread_id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadingShutdown() {
|
||||||
|
current_thread = nullptr;
|
||||||
|
|
||||||
|
for (auto& t : thread_list) {
|
||||||
|
t->Stop();
|
||||||
|
}
|
||||||
thread_list.clear();
|
thread_list.clear();
|
||||||
ready_queue.clear();
|
ready_queue.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadingShutdown() {
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -406,6 +406,9 @@ void Shutdown() {
|
|||||||
lock = nullptr;
|
lock = nullptr;
|
||||||
notification_event = nullptr;
|
notification_event = nullptr;
|
||||||
parameter_event = nullptr;
|
parameter_event = nullptr;
|
||||||
|
|
||||||
|
next_parameter.object = nullptr;
|
||||||
|
|
||||||
HLE::Applets::Shutdown();
|
HLE::Applets::Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,4 +310,9 @@ Interface::Interface() {
|
|||||||
Register(FunctionTable);
|
Register(FunctionTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Interface::~Interface() {
|
||||||
|
semaphore_event = nullptr;
|
||||||
|
interrupt_event = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -16,6 +16,7 @@ namespace DSP_DSP {
|
|||||||
class Interface : public Service::Interface {
|
class Interface : public Service::Interface {
|
||||||
public:
|
public:
|
||||||
Interface();
|
Interface();
|
||||||
|
~Interface() override;
|
||||||
|
|
||||||
std::string GetPortName() const override {
|
std::string GetPortName() const override {
|
||||||
return "dsp::DSP";
|
return "dsp::DSP";
|
||||||
|
@ -584,7 +584,7 @@ const Interface::FunctionInfo FunctionTable[] = {
|
|||||||
Interface::Interface() {
|
Interface::Interface() {
|
||||||
Register(FunctionTable);
|
Register(FunctionTable);
|
||||||
|
|
||||||
g_interrupt_event = 0;
|
g_interrupt_event = nullptr;
|
||||||
|
|
||||||
using Kernel::MemoryPermission;
|
using Kernel::MemoryPermission;
|
||||||
g_shared_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite,
|
g_shared_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite,
|
||||||
@ -593,4 +593,9 @@ Interface::Interface() {
|
|||||||
g_thread_id = 0;
|
g_thread_id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Interface::~Interface() {
|
||||||
|
g_interrupt_event = nullptr;
|
||||||
|
g_shared_memory = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -161,6 +161,7 @@ static_assert(sizeof(CommandBuffer) == 0x200, "CommandBuffer struct has incorrec
|
|||||||
class Interface : public Service::Interface {
|
class Interface : public Service::Interface {
|
||||||
public:
|
public:
|
||||||
Interface();
|
Interface();
|
||||||
|
~Interface() override;
|
||||||
|
|
||||||
std::string GetPortName() const override {
|
std::string GetPortName() const override {
|
||||||
return "gsp::Gpu";
|
return "gsp::Gpu";
|
||||||
|
@ -125,4 +125,8 @@ Interface::Interface() {
|
|||||||
Register(FunctionTable);
|
Register(FunctionTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Interface::~Interface() {
|
||||||
|
handle_event = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -16,6 +16,7 @@ namespace NWM_UDS {
|
|||||||
class Interface : public Service::Interface {
|
class Interface : public Service::Interface {
|
||||||
public:
|
public:
|
||||||
Interface();
|
Interface();
|
||||||
|
~Interface() override;
|
||||||
|
|
||||||
std::string GetPortName() const override {
|
std::string GetPortName() const override {
|
||||||
return "nwm::UDS";
|
return "nwm::UDS";
|
||||||
|
@ -68,4 +68,8 @@ Interface::Interface() {
|
|||||||
Register(FunctionTable);
|
Register(FunctionTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Interface::~Interface() {
|
||||||
|
event_handle = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -13,6 +13,7 @@ namespace SRV {
|
|||||||
class Interface : public Service::Interface {
|
class Interface : public Service::Interface {
|
||||||
public:
|
public:
|
||||||
Interface();
|
Interface();
|
||||||
|
~Interface() override;
|
||||||
|
|
||||||
std::string GetPortName() const override {
|
std::string GetPortName() const override {
|
||||||
return "srv:";
|
return "srv:";
|
||||||
|
@ -410,4 +410,8 @@ Interface::Interface() {
|
|||||||
Register(FunctionTable);
|
Register(FunctionTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Interface::~Interface() {
|
||||||
|
completion_event = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -112,6 +112,7 @@ struct ConversionConfiguration {
|
|||||||
class Interface : public Service::Interface {
|
class Interface : public Service::Interface {
|
||||||
public:
|
public:
|
||||||
Interface();
|
Interface();
|
||||||
|
~Interface() override;
|
||||||
|
|
||||||
std::string GetPortName() const override {
|
std::string GetPortName() const override {
|
||||||
return "y2r:u";
|
return "y2r:u";
|
||||||
|
Loading…
Reference in New Issue
Block a user