From f55fc850a245921cc2e89d281ff8bf81380f007b Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Wed, 6 Apr 2022 17:36:19 -0700
Subject: [PATCH 1/5] hle: kernel: hle_ipc: HasSessionRequestHandler: Check if
 domain handler is expired rather than locking.

---
 src/core/hle/kernel/hle_ipc.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index b547a34631..7692d02e16 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -51,7 +51,7 @@ bool SessionRequestManager::HasSessionRequestHandler(const HLERequestContext& co
             LOG_CRITICAL(IPC, "object_id {} is too big!", object_id);
             return false;
         }
-        return DomainHandler(object_id - 1).lock() != nullptr;
+        return !DomainHandler(object_id - 1).expired();
     } else {
         return session_handler != nullptr;
     }

From d737652d08ad40ff235772f0ff3daaa9a4478cef Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Wed, 6 Apr 2022 17:37:00 -0700
Subject: [PATCH 2/5] hle: service: sm: Remove manual tracking of KServerPorts.

---
 src/core/hle/service/sm/sm.cpp | 7 +------
 src/core/hle/service/sm/sm.h   | 2 --
 2 files changed, 1 insertion(+), 8 deletions(-)

diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 97f8958528..2ac6dc5969 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -153,7 +153,6 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext&
     auto& port = port_result.Unwrap();
     SCOPE_EXIT({ port->GetClientPort().Close(); });
 
-    server_ports.emplace_back(&port->GetServerPort());
 
     // Create a new session.
     Kernel::KClientSession* session{};
@@ -224,10 +223,6 @@ SM::SM(ServiceManager& service_manager_, Core::System& system_)
     });
 }
 
-SM::~SM() {
-    for (auto& server_port : server_ports) {
-        server_port->Close();
-    }
-}
+SM::~SM() = default;
 
 } // namespace Service::SM
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index 021eb51b40..f3ff7b27e9 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -22,7 +22,6 @@ class KClientPort;
 class KClientSession;
 class KernelCore;
 class KPort;
-class KServerPort;
 class SessionRequestHandler;
 } // namespace Kernel
 
@@ -48,7 +47,6 @@ private:
     ServiceManager& service_manager;
     bool is_initialized{};
     Kernel::KernelCore& kernel;
-    std::vector<Kernel::KServerPort*> server_ports;
 };
 
 class ServiceManager {

From 788bebb160e0f6002a225eac365252a493a92f77 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Wed, 6 Apr 2022 17:41:11 -0700
Subject: [PATCH 3/5] hle: kernel: k_auto_object: Move unregister with kernel
 to after Destroy.

- Destructor is no longer invoked, so our object counting was off.
---
 src/core/hle/kernel/k_auto_object.h | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h
index 05779f2d55..c097373a8c 100644
--- a/src/core/hle/kernel/k_auto_object.h
+++ b/src/core/hle/kernel/k_auto_object.h
@@ -89,9 +89,7 @@ public:
     explicit KAutoObject(KernelCore& kernel_) : kernel(kernel_) {
         RegisterWithKernel();
     }
-    virtual ~KAutoObject() {
-        UnregisterWithKernel();
-    }
+    virtual ~KAutoObject() = default;
 
     static KAutoObject* Create(KAutoObject* ptr);
 
@@ -168,6 +166,7 @@ public:
         // If ref count hits zero, destroy the object.
         if (cur_ref_count - 1 == 0) {
             this->Destroy();
+            this->UnregisterWithKernel();
         }
     }
 

From b44a564792dc391aa2012b424b04ea50c83e27d1 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Wed, 6 Apr 2022 17:42:23 -0700
Subject: [PATCH 4/5] hle: kernel: k_server_port: Release ref-counted host
 emulation members on Destroy.

---
 src/core/hle/kernel/k_server_port.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/core/hle/kernel/k_server_port.cpp b/src/core/hle/kernel/k_server_port.cpp
index 433fc98e1d..6922a07cb0 100644
--- a/src/core/hle/kernel/k_server_port.cpp
+++ b/src/core/hle/kernel/k_server_port.cpp
@@ -62,6 +62,9 @@ void KServerPort::Destroy() {
 
     // Close our reference to our parent.
     parent->Close();
+
+    // Release host emulation members.
+    session_handler.reset();
 }
 
 bool KServerPort::IsSignaled() const {

From a7f73d606f596ab73cf794a76c06cd955033cada Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Wed, 6 Apr 2022 17:44:06 -0700
Subject: [PATCH 5/5] hle: kernel: Unify and integrate reference tracking for
 KServerPort/KServerSession.

- These are not managed elsewhere, and need to be tracked and closed on emulation shutdown.
---
 src/core/hle/kernel/hle_ipc.cpp          |  3 ++
 src/core/hle/kernel/k_server_port.cpp    |  3 ++
 src/core/hle/kernel/k_server_session.cpp |  3 ++
 src/core/hle/kernel/kernel.cpp           | 41 ++++++++++++++++--------
 src/core/hle/kernel/kernel.h             |  8 +++++
 src/core/hle/service/sm/sm.cpp           |  1 +
 6 files changed, 46 insertions(+), 13 deletions(-)

diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 7692d02e16..5828ac9230 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -59,6 +59,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.RegisterServerObject(session);
 }
 
 void SessionRequestHandler::ClientDisconnected(KServerSession* session) {
diff --git a/src/core/hle/kernel/k_server_port.cpp b/src/core/hle/kernel/k_server_port.cpp
index 6922a07cb0..e66c0c9920 100644
--- a/src/core/hle/kernel/k_server_port.cpp
+++ b/src/core/hle/kernel/k_server_port.cpp
@@ -65,6 +65,9 @@ void KServerPort::Destroy() {
 
     // Release host emulation members.
     session_handler.reset();
+
+    // Ensure that the global list tracking server objects does not hold on to a reference.
+    kernel.UnregisterServerObject(this);
 }
 
 bool KServerPort::IsSignaled() const {
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp
index 30c56ff29a..7ac2ef2547 100644
--- a/src/core/hle/kernel/k_server_session.cpp
+++ b/src/core/hle/kernel/k_server_session.cpp
@@ -49,6 +49,9 @@ void KServerSession::Destroy() {
 
     // Release host emulation members.
     manager.reset();
+
+    // Ensure that the global list tracking server objects does not hold on to a reference.
+    kernel.UnregisterServerObject(this);
 }
 
 void KServerSession::OnClientClosed() {
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 134a0b8e97..cc6ee0eae6 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -96,15 +96,15 @@ struct KernelCore::Impl {
 
         process_list.clear();
 
-        // Close all open server ports.
-        std::unordered_set<KServerPort*> server_ports_;
+        // Close all open server sessions and ports.
+        std::unordered_set<KAutoObject*> server_objects_;
         {
-            std::scoped_lock lk{server_ports_lock};
-            server_ports_ = server_ports;
-            server_ports.clear();
+            std::scoped_lock lk(server_objects_lock);
+            server_objects_ = server_objects;
+            server_objects.clear();
         }
-        for (auto* server_port : server_ports_) {
-            server_port->Close();
+        for (auto* server_object : server_objects_) {
+            server_object->Close();
         }
 
         // Ensures all service threads gracefully shutdown.
@@ -659,13 +659,20 @@ struct KernelCore::Impl {
         }
 
         KClientPort* port = &search->second(system.ServiceManager(), system);
-        {
-            std::scoped_lock lk{server_ports_lock};
-            server_ports.insert(&port->GetParent()->GetServerPort());
-        }
+        RegisterServerObject(&port->GetParent()->GetServerPort());
         return port;
     }
 
+    void RegisterServerObject(KAutoObject* server_object) {
+        std::scoped_lock lk(server_objects_lock);
+        server_objects.insert(server_object);
+    }
+
+    void UnregisterServerObject(KAutoObject* server_object) {
+        std::scoped_lock lk(server_objects_lock);
+        server_objects.erase(server_object);
+    }
+
     std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(KernelCore& kernel,
                                                              const std::string& name) {
         auto service_thread = std::make_shared<Kernel::ServiceThread>(kernel, 1, name);
@@ -693,7 +700,7 @@ struct KernelCore::Impl {
         service_threads_manager.QueueWork([this]() { service_threads.clear(); });
     }
 
-    std::mutex server_ports_lock;
+    std::mutex server_objects_lock;
     std::mutex registered_objects_lock;
     std::mutex registered_in_use_objects_lock;
 
@@ -723,7 +730,7 @@ struct KernelCore::Impl {
     /// the ConnectToPort SVC.
     std::unordered_map<std::string, ServiceInterfaceFactory> service_interface_factory;
     NamedPortTable named_ports;
-    std::unordered_set<KServerPort*> server_ports;
+    std::unordered_set<KAutoObject*> server_objects;
     std::unordered_set<KAutoObject*> registered_objects;
     std::unordered_set<KAutoObject*> registered_in_use_objects;
 
@@ -928,6 +935,14 @@ KClientPort* KernelCore::CreateNamedServicePort(std::string name) {
     return impl->CreateNamedServicePort(std::move(name));
 }
 
+void KernelCore::RegisterServerObject(KAutoObject* server_object) {
+    impl->RegisterServerObject(server_object);
+}
+
+void KernelCore::UnregisterServerObject(KAutoObject* server_object) {
+    impl->UnregisterServerObject(server_object);
+}
+
 void KernelCore::RegisterKernelObject(KAutoObject* object) {
     std::scoped_lock lk{impl->registered_objects_lock};
     impl->registered_objects.insert(object);
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 24e26fa44a..d709c368b8 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -195,6 +195,14 @@ public:
     /// Opens a port to a service previously registered with RegisterNamedService.
     KClientPort* CreateNamedServicePort(std::string name);
 
+    /// Registers a server session or port with the gobal emulation state, to be freed on shutdown.
+    /// This is necessary because we do not emulate processes for HLE sessions and ports.
+    void RegisterServerObject(KAutoObject* server_object);
+
+    /// Unregisters a server session or port previously registered with RegisterServerSession when
+    /// it was destroyed during the current emulation session.
+    void UnregisterServerObject(KAutoObject* server_object);
+
     /// Registers all kernel objects with the global emulation state, this is purely for tracking
     /// leaks after emulation has been shutdown.
     void RegisterKernelObject(KAutoObject* object);
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 2ac6dc5969..13f5e08ec0 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -153,6 +153,7 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext&
     auto& port = port_result.Unwrap();
     SCOPE_EXIT({ port->GetClientPort().Close(); });
 
+    kernel.RegisterServerObject(&port->GetServerPort());
 
     // Create a new session.
     Kernel::KClientSession* session{};