Ver código fonte

Merge pull request #8165 from bunnei/ensure-session-port-cleanup

Kernel: Track open references to KServerPort and KServerSession.
bunnei 4 anos atrás
pai
commit
ca2accfb25

+ 4 - 1
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;
     }
@@ -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) {

+ 2 - 3
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();
         }
     }
 

+ 6 - 0
src/core/hle/kernel/k_server_port.cpp

@@ -62,6 +62,12 @@ void KServerPort::Destroy() {
 
     // Close our reference to our parent.
     parent->Close();
+
+    // 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 {

+ 3 - 0
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() {

+ 28 - 13
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);

+ 8 - 0
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);

+ 2 - 6
src/core/hle/service/sm/sm.cpp

@@ -153,7 +153,7 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext&
     auto& port = port_result.Unwrap();
     SCOPE_EXIT({ port->GetClientPort().Close(); });
 
-    server_ports.emplace_back(&port->GetServerPort());
+    kernel.RegisterServerObject(&port->GetServerPort());
 
     // Create a new session.
     Kernel::KClientSession* session{};
@@ -224,10 +224,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

+ 0 - 2
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 {