From 929994132a4f39ca4ab2975caf47a2a99a19b518 Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 28 Jun 2021 14:38:14 -0700 Subject: hle: kernel: Provide methods for tracking dangling kernel objects. --- src/core/hle/kernel/k_auto_object.cpp | 9 +++++++++ src/core/hle/kernel/k_auto_object.h | 12 ++++++++++-- src/core/hle/kernel/kernel.cpp | 16 ++++++++++++++++ src/core/hle/kernel/kernel.h | 8 ++++++++ 4 files changed, 43 insertions(+), 2 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_auto_object.cpp b/src/core/hle/kernel/k_auto_object.cpp index dbe237f09..c99a9ebb7 100644 --- a/src/core/hle/kernel/k_auto_object.cpp +++ b/src/core/hle/kernel/k_auto_object.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include "core/hle/kernel/k_auto_object.h" +#include "core/hle/kernel/kernel.h" namespace Kernel { @@ -11,4 +12,12 @@ KAutoObject* KAutoObject::Create(KAutoObject* obj) { return obj; } +void KAutoObject::RegisterWithKernel() { + kernel.RegisterKernelObject(this); +} + +void KAutoObject::UnregisterWithKernel() { + kernel.UnregisterKernelObject(this); +} + } // namespace Kernel diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h index 88a052f65..e4fcdbc67 100644 --- a/src/core/hle/kernel/k_auto_object.h +++ b/src/core/hle/kernel/k_auto_object.h @@ -85,8 +85,12 @@ private: KERNEL_AUTOOBJECT_TRAITS(KAutoObject, KAutoObject); public: - explicit KAutoObject(KernelCore& kernel_) : kernel(kernel_) {} - virtual ~KAutoObject() = default; + explicit KAutoObject(KernelCore& kernel_) : kernel(kernel_) { + RegisterWithKernel(); + } + virtual ~KAutoObject() { + UnregisterWithKernel(); + } static KAutoObject* Create(KAutoObject* ptr); @@ -166,6 +170,10 @@ public: } } +private: + void RegisterWithKernel(); + void UnregisterWithKernel(); + protected: KernelCore& kernel; std::string name; diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 64bd0c494..ee60072c2 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -142,6 +142,13 @@ struct KernelCore::Impl { // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others next_host_thread_id = Core::Hardware::NUM_CPU_CORES; + + // Track kernel objects that were not freed on shutdown + if (registered_objects.size()) { + LOG_WARNING(Kernel, "{} kernel objects were dangling on shutdown!", + registered_objects.size()); + registered_objects.clear(); + } } void InitializePhysicalCores() { @@ -656,6 +663,7 @@ struct KernelCore::Impl { /// the ConnectToPort SVC. std::unordered_map service_interface_factory; NamedPortTable named_ports; + std::unordered_set registered_objects; std::unique_ptr exclusive_monitor; std::vector cores; @@ -852,6 +860,14 @@ KClientPort* KernelCore::CreateNamedServicePort(std::string name) { return &search->second(impl->system.ServiceManager(), impl->system); } +void KernelCore::RegisterKernelObject(KAutoObject* object) { + impl->registered_objects.insert(object); +} + +void KernelCore::UnregisterKernelObject(KAutoObject* object) { + impl->registered_objects.erase(object); +} + bool KernelCore::IsValidNamedPort(NamedPortTable::const_iterator port) const { return port != impl->named_ports.cend(); } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 2d01e1ae0..b669ca74e 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -185,6 +185,14 @@ public: /// Opens a port to a service previously registered with RegisterNamedService. KClientPort* CreateNamedServicePort(std::string name); + /// Registers all kernel objects with the global emulation state, this is purely for tracking + /// leaks after emulation has been shutdown. + void RegisterKernelObject(KAutoObject* object); + + /// Unregisters a kernel object previously registered with RegisterKernelObject when it was + /// destroyed during the current emulation session. + void UnregisterKernelObject(KAutoObject* object); + /// Determines whether or not the given port is a valid named port. bool IsValidNamedPort(NamedPortTable::const_iterator port) const; -- cgit v1.2.3 From fe402d350650de50bf9a0aa70c04bec986863978 Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 28 Jun 2021 16:38:13 -0700 Subject: hle: kernel: Ensure global handle table is initialized. --- src/core/hle/kernel/kernel.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index ee60072c2..e180db791 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -61,6 +61,7 @@ struct KernelCore::Impl { void Initialize(KernelCore& kernel) { global_scheduler_context = std::make_unique(kernel); global_handle_table = std::make_unique(kernel); + global_handle_table->Initialize(KHandleTable::MaxTableSize); is_phantom_mode_for_singlecore = false; -- cgit v1.2.3 From 6020723e77585835eddcc5675385f5e7dd3072ac Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 28 Jun 2021 16:58:40 -0700 Subject: hle: kernel: k_process: Close main thread reference after it is inserted into handle table. --- src/core/hle/kernel/k_process.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index d1bd98051..c309ae563 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -10,6 +10,7 @@ #include "common/alignment.h" #include "common/assert.h" #include "common/logging/log.h" +#include "common/scope_exit.h" #include "common/settings.h" #include "core/core.h" #include "core/device_memory.h" @@ -43,6 +44,8 @@ void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::Threads, 1)); KThread* thread = KThread::Create(system.Kernel()); + SCOPE_EXIT({ thread->Close(); }); + ASSERT(KThread::InitializeUserThread(system, thread, entry_point, 0, stack_top, priority, owner_process.GetIdealCoreId(), &owner_process) .IsSuccess()); -- cgit v1.2.3 From b119363fc27994a4eb68405011235c4a1b3cdf8f Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 28 Jun 2021 16:59:49 -0700 Subject: hle: kernel: k_process: Close the handle table on shutdown. --- src/core/hle/kernel/k_process.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index c309ae563..87171b1c8 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -409,6 +409,9 @@ void KProcess::Finalize() { resource_limit->Close(); } + // Finalize the handle table and close any open handles. + handle_table.Finalize(); + // Perform inherited finalization. KAutoObjectWithSlabHeapAndContainer::Finalize(); } -- cgit v1.2.3 From 24540e0ad9b81092aa3f60fa843bfe45ebd25b8b Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 1 Jul 2021 20:05:10 -0700 Subject: kernel: svc: ConnectToNamedPort: Close extra reference to port. --- src/core/hle/kernel/svc.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 8339e11a0..e1e556370 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -298,6 +298,7 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out, VAddr po // Create a session. KClientSession* session{}; R_TRY(port->CreateSession(std::addressof(session))); + port->Close(); // Register the session in the table, close the extra reference. handle_table.Register(*out, session); -- cgit v1.2.3 From ecf36534446df97bbe18042a098f25069dfd8648 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 1 Jul 2021 21:44:50 -0700 Subject: hle: kernel: Ensure global handle table is finalized before closing. --- src/core/hle/kernel/kernel.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index e180db791..b7f9eb5c1 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -117,6 +117,7 @@ struct KernelCore::Impl { current_process = nullptr; } + global_handle_table->Finalize(); global_handle_table.reset(); preemption_event = nullptr; -- cgit v1.2.3 From 854c7a3c2826b769d9d41c79570c4dae57e0b3eb Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 1 Jul 2021 21:50:42 -0700 Subject: hle: kernel: Ensure current running process is closed. --- src/core/hle/kernel/kernel.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index b7f9eb5c1..2d5525839 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -91,6 +91,12 @@ struct KernelCore::Impl { } void Shutdown() { + if (current_process) { + current_process->Finalize(); + current_process->Close(); + current_process = nullptr; + } + process_list.clear(); // Ensures all service threads gracefully shutdown @@ -112,11 +118,6 @@ struct KernelCore::Impl { cores.clear(); - if (current_process) { - current_process->Close(); - current_process = nullptr; - } - global_handle_table->Finalize(); global_handle_table.reset(); -- cgit v1.2.3 From 8d755147d8fbe664d78b3e78514b64804505d6d7 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 2 Jul 2021 15:04:08 -0700 Subject: hle: kernel: KProcess: Change process termination assert to a warning. - Since we do not implement multiprocess right now, this should not be a crashing assert. --- src/core/hle/kernel/k_process.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index 87171b1c8..8ead1a769 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -165,7 +165,7 @@ void KProcess::DecrementThreadCount() { ASSERT(num_threads > 0); if (const auto count = --num_threads; count == 0) { - UNIMPLEMENTED_MSG("Process termination is not implemented!"); + LOG_WARNING(Kernel, "Process termination is not fully implemented."); } } -- cgit v1.2.3 From 52caa52cc2e47d426b5af38fd8439da237836e0e Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 2 Jul 2021 15:19:04 -0700 Subject: hle: kernel: Track and release server sessions, and protect methods with locks. --- src/core/hle/kernel/hle_ipc.cpp | 3 ++ src/core/hle/kernel/k_server_session.cpp | 5 +- src/core/hle/kernel/kernel.cpp | 78 +++++++++++++++++++++++++++----- src/core/hle/kernel/kernel.h | 9 ++++ 4 files changed, 82 insertions(+), 13 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 28ed6265a..ca68fc325 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -58,6 +58,9 @@ bool SessionRequestManager::HasSessionRequestHandler(const HLERequestContext& co void SessionRequestHandler::ClientConnected(KServerSession* session) { session->ClientConnected(shared_from_this()); + + // Ensure our server session is tracked globally. + kernel.RegisterServerSession(session); } void SessionRequestHandler::ClientDisconnected(KServerSession* session) { diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index 5c3c13ce6..b9f24475c 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp @@ -28,7 +28,10 @@ namespace Kernel { KServerSession::KServerSession(KernelCore& kernel_) : KSynchronizationObject{kernel_} {} -KServerSession::~KServerSession() {} +KServerSession::~KServerSession() { + // Ensure that the global list tracking server sessions does not hold on to a reference. + kernel.UnregisterServerSession(this); +} void KServerSession::Initialize(KSession* parent_session_, std::string&& name_, std::shared_ptr manager_) { diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 2d5525839..92fbc5532 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -91,15 +91,39 @@ struct KernelCore::Impl { } void Shutdown() { + // Shutdown all processes. if (current_process) { current_process->Finalize(); current_process->Close(); current_process = nullptr; } - process_list.clear(); - // Ensures all service threads gracefully shutdown + // Close all open server ports. + std::unordered_set server_ports_; + { + std::lock_guard lk(server_ports_lock); + server_ports_ = server_ports; + server_ports.clear(); + } + for (auto* server_port : server_ports_) { + server_port->Close(); + } + // Close all open server sessions. + std::unordered_set server_sessions_; + { + std::lock_guard lk(server_sessions_lock); + server_sessions_ = server_sessions; + server_sessions.clear(); + } + for (auto* server_session : server_sessions_) { + server_session->Close(); + } + + // Ensure that the object list container is finalized and properly shutdown. + object_list_container.Finalize(); + + // Ensures all service threads gracefully shutdown. service_threads.clear(); next_object_id = 0; @@ -147,10 +171,13 @@ struct KernelCore::Impl { next_host_thread_id = Core::Hardware::NUM_CPU_CORES; // Track kernel objects that were not freed on shutdown - if (registered_objects.size()) { - LOG_WARNING(Kernel, "{} kernel objects were dangling on shutdown!", - registered_objects.size()); - registered_objects.clear(); + { + std::lock_guard lk(registered_objects_lock); + if (registered_objects.size()) { + LOG_WARNING(Kernel, "{} kernel objects were dangling on shutdown!", + registered_objects.size()); + registered_objects.clear(); + } } } @@ -640,6 +667,21 @@ struct KernelCore::Impl { user_slab_heap_size); } + KClientPort* CreateNamedServicePort(std::string name) { + auto search = service_interface_factory.find(name); + if (search == service_interface_factory.end()) { + UNIMPLEMENTED(); + return {}; + } + + KClientPort* port = &search->second(system.ServiceManager(), system); + { + std::lock_guard lk(server_ports_lock); + server_ports.insert(&port->GetParent()->GetServerPort()); + } + return port; + } + std::atomic next_object_id{0}; std::atomic next_kernel_process_id{KProcess::InitialKIPIDMin}; std::atomic next_user_process_id{KProcess::ProcessIDMin}; @@ -666,7 +708,12 @@ struct KernelCore::Impl { /// the ConnectToPort SVC. std::unordered_map service_interface_factory; NamedPortTable named_ports; + std::unordered_set server_ports; + std::unordered_set server_sessions; std::unordered_set registered_objects; + std::mutex server_ports_lock; + std::mutex server_sessions_lock; + std::mutex registered_objects_lock; std::unique_ptr exclusive_monitor; std::vector cores; @@ -855,19 +902,26 @@ void KernelCore::RegisterNamedService(std::string name, ServiceInterfaceFactory& } KClientPort* KernelCore::CreateNamedServicePort(std::string name) { - auto search = impl->service_interface_factory.find(name); - if (search == impl->service_interface_factory.end()) { - UNIMPLEMENTED(); - return {}; - } - return &search->second(impl->system.ServiceManager(), impl->system); + return impl->CreateNamedServicePort(std::move(name)); +} + +void KernelCore::RegisterServerSession(KServerSession* server_session) { + std::lock_guard lk(impl->server_sessions_lock); + impl->server_sessions.insert(server_session); +} + +void KernelCore::UnregisterServerSession(KServerSession* server_session) { + std::lock_guard lk(impl->server_sessions_lock); + impl->server_sessions.erase(server_session); } void KernelCore::RegisterKernelObject(KAutoObject* object) { + std::lock_guard lk(impl->registered_objects_lock); impl->registered_objects.insert(object); } void KernelCore::UnregisterKernelObject(KAutoObject* object) { + std::lock_guard lk(impl->registered_objects_lock); impl->registered_objects.erase(object); } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index b669ca74e..3a6db0b1c 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -45,6 +45,7 @@ class KPort; class KProcess; class KResourceLimit; class KScheduler; +class KServerSession; class KSession; class KSharedMemory; class KThread; @@ -185,6 +186,14 @@ public: /// Opens a port to a service previously registered with RegisterNamedService. KClientPort* CreateNamedServicePort(std::string name); + /// Registers a server session with the gobal emulation state, to be freed on shutdown. This is + /// necessary because we do not emulate processes for HLE sessions. + void RegisterServerSession(KServerSession* server_session); + + /// Unregisters a server session previously registered with RegisterServerSession when it was + /// destroyed during the current emulation session. + void UnregisterServerSession(KServerSession* server_session); + /// Registers all kernel objects with the global emulation state, this is purely for tracking /// leaks after emulation has been shutdown. void RegisterKernelObject(KAutoObject* object); -- cgit v1.2.3 From f3db3dcc8d5941bf09d682c9d22c865701e8160f Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 20 Jul 2021 18:53:43 -0700 Subject: hle: kernel: svc: Remove part of ExitProcess. - ExitProcess is not actually implemented either way, and this needs more work before we implement. --- src/core/hle/kernel/svc.cpp | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index e1e556370..2eb532472 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1440,11 +1440,6 @@ static void ExitProcess(Core::System& system) { LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->GetProcessID()); ASSERT_MSG(current_process->GetStatus() == ProcessStatus::Running, "Process has already exited"); - - current_process->PrepareForTermination(); - - // Kill the current thread - system.Kernel().CurrentScheduler()->GetCurrentThread()->Exit(); } static void ExitProcess32(Core::System& system) { -- cgit v1.2.3