Explorar el Código

Added a framework for partially handling Session disconnections.

Further implementation will happen in a future commit.

Fixes a regression.
Subv hace 9 años
padre
commit
386112da32

+ 6 - 2
src/core/hle/kernel/client_port.cpp

@@ -19,9 +19,10 @@ ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() {
     // AcceptSession before returning from this call.
 
     if (active_sessions >= max_sessions) {
-        return ResultCode(ErrorDescription::MaxConnectionsReached,
+        // TODO(Subv): Return an error code in this situation after session disconnection is implemented.
+        /*return ResultCode(ErrorDescription::MaxConnectionsReached,
                           ErrorModule::OS, ErrorSummary::WouldBlock,
-                          ErrorLevel::Temporary);
+                          ErrorLevel::Temporary);*/
     }
     active_sessions++;
 
@@ -30,6 +31,9 @@ ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() {
     auto client_session = std::get<SharedPtr<ClientSession>>(sessions);
     auto server_session = std::get<SharedPtr<ServerSession>>(sessions);
 
+    if (server_port->hle_handler)
+        server_port->hle_handler->ClientConnected(server_session);
+
     server_port->pending_sessions.push_back(std::move(server_session));
 
     // Wake the threads waiting on the ServerPort

+ 12 - 3
src/core/hle/kernel/client_session.cpp

@@ -10,13 +10,22 @@
 namespace Kernel {
 
 ClientSession::ClientSession() = default;
-ClientSession::~ClientSession() = default;
+ClientSession::~ClientSession() {
+    // This destructor will be called automatically when the last ClientSession handle is closed by the emulated application.
 
-ResultVal<SharedPtr<ClientSession>> ClientSession::Create(SharedPtr<ServerSession> server_session, std::string name) {
+    if (server_session->hle_handler)
+        server_session->hle_handler->ClientDisconnected(server_session);
+
+    // TODO(Subv): If the session is still open, set the connection status to 2 (Closed by client),
+    // wake up all the ServerSession's waiting threads and set the WaitSynchronization result to 0xC920181A.
+}
+
+ResultVal<SharedPtr<ClientSession>> ClientSession::Create(ServerSession* server_session, std::string name) {
     SharedPtr<ClientSession> client_session(new ClientSession);
 
     client_session->name = std::move(name);
-    client_session->server_session = std::move(server_session);
+    client_session->server_session = server_session;
+    client_session->session_status = SessionStatus::Open;
     return MakeResult<SharedPtr<ClientSession>>(std::move(client_session));
 }
 

+ 9 - 2
src/core/hle/kernel/client_session.h

@@ -15,6 +15,12 @@ namespace Kernel {
 
 class ServerSession;
 
+enum class SessionStatus {
+    Open = 1,
+    ClosedByClient = 2,
+    ClosedBYServer = 3,
+};
+
 class ClientSession final : public Object {
 public:
     friend class ServerSession;
@@ -39,7 +45,8 @@ public:
     ResultCode SendSyncRequest();
 
     std::string name;                           ///< Name of client port (optional)
-    SharedPtr<ServerSession> server_session;    ///< The server session associated with this client session.
+    ServerSession* server_session;              ///< The server session associated with this client session.
+    SessionStatus session_status;               ///< The session's current status.
 
 private:
     ClientSession();
@@ -51,7 +58,7 @@ private:
      * @param name Optional name of client session
      * @return The created client session
      */
-    static ResultVal<SharedPtr<ClientSession>> Create(SharedPtr<ServerSession> server_session, std::string name = "Unknown");
+    static ResultVal<SharedPtr<ClientSession>> Create(ServerSession* server_session, std::string name = "Unknown");
 };
 
 } // namespace

+ 8 - 2
src/core/hle/kernel/server_session.cpp

@@ -11,7 +11,11 @@
 namespace Kernel {
 
 ServerSession::ServerSession() = default;
-ServerSession::~ServerSession() = default;
+ServerSession::~ServerSession() {
+    // This destructor will be called automatically when the last ServerSession handle is closed by the emulated application.
+    // TODO(Subv): Reduce the ClientPort's connection count,
+    // if the session is still open, set the connection status to 3 (Closed by server),
+}
 
 ResultVal<SharedPtr<ServerSession>> ServerSession::Create(std::string name, std::shared_ptr<Service::SessionRequestHandler> hle_handler) {
     SharedPtr<ServerSession> server_session(new ServerSession);
@@ -49,7 +53,9 @@ ResultCode ServerSession::HandleSyncRequest() {
 ServerSession::SessionPair ServerSession::CreateSessionPair(const std::string& name,
                                                             std::shared_ptr<Service::SessionRequestHandler> hle_handler) {
     auto server_session = ServerSession::Create(name + "_Server", std::move(hle_handler)).MoveFrom();
-    auto client_session = ClientSession::Create(server_session, name + "_Client").MoveFrom();
+    // We keep a non-owning pointer to the ServerSession in the ClientSession because we don't want to prevent the
+    // ServerSession's destructor from being called when the emulated application closes the last ServerSession handle.
+    auto client_session = ClientSession::Create(server_session.get(), name + "_Client").MoveFrom();
 
     return std::make_tuple(std::move(server_session), std::move(client_session));
 }

+ 1 - 0
src/core/hle/service/fs/archive.cpp

@@ -174,6 +174,7 @@ void File::HandleSyncRequestImpl(Kernel::SharedPtr<Kernel::ServerSession> server
     case FileCommand::OpenLinkFile: {
         LOG_WARNING(Service_FS, "(STUBBED) File command OpenLinkFile %s", GetName().c_str());
         auto sessions = Kernel::ServerSession::CreateSessionPair(GetName(), shared_from_this());
+        ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions));
         cmd_buff[3] = Kernel::g_handle_table.Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)).ValueOr(INVALID_HANDLE);
         break;
     }

+ 3 - 0
src/core/hle/service/fs/fs_user.cpp

@@ -73,6 +73,7 @@ static void OpenFile(Service::Interface* self) {
     if (file_res.Succeeded()) {
         std::shared_ptr<File> file = *file_res;
         auto sessions = ServerSession::CreateSessionPair(file->GetName(), file);
+        file->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions));
         cmd_buff[3] = Kernel::g_handle_table.Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)).MoveFrom();
     } else {
         cmd_buff[3] = 0;
@@ -135,6 +136,7 @@ static void OpenFileDirectly(Service::Interface* self) {
     if (file_res.Succeeded()) {
         std::shared_ptr<File> file = *file_res;
         auto sessions = ServerSession::CreateSessionPair(file->GetName(), file);
+        file->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions));
         cmd_buff[3] = Kernel::g_handle_table.Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)).MoveFrom();
     } else {
         cmd_buff[3] = 0;
@@ -398,6 +400,7 @@ static void OpenDirectory(Service::Interface* self) {
     if (dir_res.Succeeded()) {
         std::shared_ptr<Directory> directory = *dir_res;
         auto sessions = ServerSession::CreateSessionPair(directory->GetName(), directory);
+        directory->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions));
         cmd_buff[3] = Kernel::g_handle_table.Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)).MoveFrom();
     } else {
         LOG_ERROR(Service_FS, "failed to get a handle for directory type=%d size=%d data=%s",

+ 10 - 0
src/core/hle/service/service.cpp

@@ -2,6 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include <boost/range/algorithm_ext/erase.hpp>
+
 #include "common/logging/log.h"
 #include "common/string_util.h"
 
@@ -79,6 +81,14 @@ ResultCode SessionRequestHandler::HandleSyncRequest(Kernel::SharedPtr<Kernel::Se
     return RESULT_SUCCESS;
 }
 
+void SessionRequestHandler::ClientConnected(Kernel::SharedPtr<Kernel::ServerSession> server_session) {
+    connected_sessions.push_back(server_session);
+}
+
+void SessionRequestHandler::ClientDisconnected(Kernel::SharedPtr<Kernel::ServerSession> server_session) {
+    boost::range::remove_erase(connected_sessions, server_session);
+}
+
 ResultCode SessionRequestHandler::TranslateRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) {
     // TODO(Subv): Implement this function once multiple concurrent processes are supported.
     return RESULT_SUCCESS;

+ 18 - 0
src/core/hle/service/service.h

@@ -38,6 +38,20 @@ public:
      */
     ResultCode HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session);
 
+    /**
+     * Signals that a client has just connected to this HLE handler and keeps the
+     * associated ServerSession alive for the duration of the connection.
+     * @param server_session Owning pointer to the ServerSession associated with the connection.
+     */
+    void ClientConnected(Kernel::SharedPtr<Kernel::ServerSession> server_session);
+
+    /**
+     * Signals that a client has just disconnected from this HLE handler and releases the
+     * associated ServerSession.
+     * @param server_session ServerSession associated with the connection.
+     */
+    void ClientDisconnected(Kernel::SharedPtr<Kernel::ServerSession> server_session);
+
 protected:
     /**
      * Handles a sync request from the emulated application and writes the response to the command buffer.
@@ -55,6 +69,10 @@ private:
      * but once that is implemented we'll need to properly translate all descriptors in the command buffer.
      */
     ResultCode TranslateRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session);
+
+    /// List of sessions that are connected to this handler.
+    /// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list for the duration of the connection.
+    std::vector<Kernel::SharedPtr<Kernel::ServerSession>> connected_sessions;
 };
 
 /**