From ac607070934c5973d84201fa4975d54b6ac7fa06 Mon Sep 17 00:00:00 2001
From: pineappleEA <pineaea@gmail.com>
Date: Fri, 28 Oct 2022 04:12:11 +0200
Subject: [PATCH] early-access version 3059

---
 README.md                                 |   2 +-
 src/core/arm/dynarmic/arm_dynarmic_32.cpp |   2 +-
 src/core/arm/dynarmic/arm_dynarmic_64.cpp |   2 +-
 src/core/hle/ipc_helpers.h                |  17 +-
 src/core/hle/kernel/hle_ipc.cpp           |  55 +++--
 src/core/hle/kernel/hle_ipc.h             |  29 +--
 src/core/hle/kernel/k_client_port.cpp     |   5 +-
 src/core/hle/kernel/k_client_port.h       |   3 +-
 src/core/hle/kernel/k_port.cpp            |   6 +
 src/core/hle/kernel/k_server_port.cpp     |   5 +-
 src/core/hle/kernel/k_server_port.h       |  19 ++
 src/core/hle/kernel/k_server_session.cpp  | 187 ++++++-----------
 src/core/hle/kernel/k_server_session.h    |  43 +++-
 src/core/hle/kernel/k_session.cpp         |   5 +-
 src/core/hle/kernel/k_session.h           |   3 +-
 src/core/hle/kernel/kernel.cpp            |  24 +--
 src/core/hle/kernel/kernel.h              |   9 -
 src/core/hle/kernel/service_thread.cpp    | 236 +++++++---------------
 src/core/hle/kernel/service_thread.h      |   6 +-
 src/core/hle/kernel/svc.cpp               |   6 +-
 src/core/hle/service/service.cpp          |  13 +-
 src/core/hle/service/service.h            |   4 -
 src/core/hle/service/sm/sm.cpp            |  15 +-
 src/core/hle/service/sm/sm.h              |   1 -
 src/core/hle/service/sm/sm_controller.cpp |  41 ++--
 25 files changed, 293 insertions(+), 445 deletions(-)

diff --git a/README.md b/README.md
index 245d3b7fe..aa9363ddd 100755
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 yuzu emulator early access
 =============
 
-This is the source code for early-access 3058.
+This is the source code for early-access 3059.
 
 ## Legal Notice
 
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index d1e70f19d..287ba102e 100755
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -450,7 +450,7 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace(Core::S
     // Frame records are two words long:
     // fp+0 : pointer to previous frame record
     // fp+4 : value of lr for frame
-    while (true) {
+    for (size_t i = 0; i < 256; i++) {
         out.push_back({"", 0, lr, 0, ""});
         if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 8)) {
             break;
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index 22b5d5656..afb7fb3a0 100755
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -517,7 +517,7 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace(Core::S
     // Frame records are two words long:
     // fp+0 : pointer to previous frame record
     // fp+8 : value of lr for frame
-    while (true) {
+    for (size_t i = 0; i < 256; i++) {
         out.push_back({"", 0, lr, 0, ""});
         if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 16)) {
             break;
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index 3bb111748..18fde8bd6 100755
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -86,13 +86,13 @@ public:
         u32 num_domain_objects{};
         const bool always_move_handles{
             (static_cast<u32>(flags) & static_cast<u32>(Flags::AlwaysMoveHandles)) != 0};
-        if (!ctx.GetManager()->IsDomain() || always_move_handles) {
+        if (!ctx.Session()->GetSessionRequestManager()->IsDomain() || always_move_handles) {
             num_handles_to_move = num_objects_to_move;
         } else {
             num_domain_objects = num_objects_to_move;
         }
 
-        if (ctx.GetManager()->IsDomain()) {
+        if (ctx.Session()->GetSessionRequestManager()->IsDomain()) {
             raw_data_size +=
                 static_cast<u32>(sizeof(DomainMessageHeader) / sizeof(u32) + num_domain_objects);
             ctx.write_size += num_domain_objects;
@@ -125,7 +125,8 @@ public:
         if (!ctx.IsTipc()) {
             AlignWithPadding();
 
-            if (ctx.GetManager()->IsDomain() && ctx.HasDomainMessageHeader()) {
+            if (ctx.Session()->GetSessionRequestManager()->IsDomain() &&
+                ctx.HasDomainMessageHeader()) {
                 IPC::DomainMessageHeader domain_header{};
                 domain_header.num_objects = num_domain_objects;
                 PushRaw(domain_header);
@@ -145,18 +146,18 @@ public:
 
     template <class T>
     void PushIpcInterface(std::shared_ptr<T> iface) {
-        if (context->GetManager()->IsDomain()) {
+        if (context->Session()->GetSessionRequestManager()->IsDomain()) {
             context->AddDomainObject(std::move(iface));
         } else {
             kernel.CurrentProcess()->GetResourceLimit()->Reserve(
                 Kernel::LimitableResource::Sessions, 1);
 
             auto* session = Kernel::KSession::Create(kernel);
-            session->Initialize(nullptr, iface->GetServiceName());
-            iface->RegisterSession(&session->GetServerSession(),
-                                   std::make_shared<Kernel::SessionRequestManager>(kernel));
+            session->Initialize(nullptr, iface->GetServiceName(),
+                                std::make_shared<Kernel::SessionRequestManager>(kernel));
 
             context->AddMoveObject(&session->GetClientSession());
+            iface->ClientConnected(&session->GetServerSession());
         }
     }
 
@@ -386,7 +387,7 @@ public:
 
     template <class T>
     std::weak_ptr<T> PopIpcInterface() {
-        ASSERT(context->GetManager()->IsDomain());
+        ASSERT(context->Session()->GetSessionRequestManager()->IsDomain());
         ASSERT(context->GetDomainMessageHeader().input_object_count > 0);
         return context->GetDomainHandler<T>(Pop<u32>() - 1);
     }
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index fd354d484..e4f43a053 100755
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -16,7 +16,6 @@
 #include "core/hle/kernel/k_auto_object.h"
 #include "core/hle/kernel/k_handle_table.h"
 #include "core/hle/kernel/k_process.h"
-#include "core/hle/kernel/k_server_port.h"
 #include "core/hle/kernel/k_server_session.h"
 #include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/kernel.h"
@@ -36,21 +35,7 @@ SessionRequestHandler::SessionRequestHandler(KernelCore& kernel_, const char* se
 }
 
 SessionRequestHandler::~SessionRequestHandler() {
-    kernel.ReleaseServiceThread(service_thread.lock());
-}
-
-void SessionRequestHandler::AcceptSession(KServerPort* server_port) {
-    auto* server_session = server_port->AcceptSession();
-    ASSERT(server_session != nullptr);
-
-    RegisterSession(server_session, std::make_shared<SessionRequestManager>(kernel));
-}
-
-void SessionRequestHandler::RegisterSession(KServerSession* server_session,
-                                            std::shared_ptr<SessionRequestManager> manager) {
-    manager->SetSessionHandler(shared_from_this());
-    service_thread.lock()->RegisterServerSession(server_session, manager);
-    server_session->Close();
+    kernel.ReleaseServiceThread(service_thread);
 }
 
 SessionRequestManager::SessionRequestManager(KernelCore& kernel_) : kernel{kernel_} {}
@@ -107,7 +92,7 @@ Result SessionRequestManager::HandleDomainSyncRequest(KServerSession* server_ses
     }
 
     // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs
-    ASSERT(context.GetManager().get() == this);
+    context.SetSessionRequestManager(server_session->GetSessionRequestManager());
 
     // If there is a DomainMessageHeader, then this is CommandType "Request"
     const auto& domain_message_header = context.GetDomainMessageHeader();
@@ -145,6 +130,31 @@ Result SessionRequestManager::HandleDomainSyncRequest(KServerSession* server_ses
     return ResultSuccess;
 }
 
+Result SessionRequestManager::QueueSyncRequest(KSession* parent,
+                                               std::shared_ptr<HLERequestContext>&& context) {
+    // Ensure we have a session request handler
+    if (this->HasSessionRequestHandler(*context)) {
+        if (auto strong_ptr = this->GetServiceThread().lock()) {
+            strong_ptr->QueueSyncRequest(*parent, std::move(context));
+        } else {
+            ASSERT_MSG(false, "strong_ptr is nullptr!");
+        }
+    } else {
+        ASSERT_MSG(false, "handler is invalid!");
+    }
+
+    return ResultSuccess;
+}
+
+void SessionRequestHandler::ClientConnected(KServerSession* session) {
+    session->GetSessionRequestManager()->SetSessionHandler(shared_from_this());
+
+    // Ensure our server session is tracked globally.
+    kernel.RegisterServerObject(session);
+}
+
+void SessionRequestHandler::ClientDisconnected(KServerSession* session) {}
+
 HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_,
                                      KServerSession* server_session_, KThread* thread_)
     : server_session(server_session_), thread(thread_), kernel{kernel_}, memory{memory_} {
@@ -204,7 +214,7 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32
         // Padding to align to 16 bytes
         rp.AlignWithPadding();
 
-        if (GetManager()->IsDomain() &&
+        if (Session()->GetSessionRequestManager()->IsDomain() &&
             ((command_header->type == IPC::CommandType::Request ||
               command_header->type == IPC::CommandType::RequestWithContext) ||
              !incoming)) {
@@ -213,7 +223,7 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32
             if (incoming || domain_message_header) {
                 domain_message_header = rp.PopRaw<IPC::DomainMessageHeader>();
             } else {
-                if (GetManager()->IsDomain()) {
+                if (Session()->GetSessionRequestManager()->IsDomain()) {
                     LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!");
                 }
             }
@@ -306,11 +316,12 @@ Result HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_threa
     // Write the domain objects to the command buffer, these go after the raw untranslated data.
     // TODO(Subv): This completely ignores C buffers.
 
-    if (GetManager()->IsDomain()) {
+    if (server_session->GetSessionRequestManager()->IsDomain()) {
         current_offset = domain_offset - static_cast<u32>(outgoing_domain_objects.size());
         for (auto& object : outgoing_domain_objects) {
-            GetManager()->AppendDomainHandler(std::move(object));
-            cmd_buf[current_offset++] = static_cast<u32_le>(GetManager()->DomainHandlerCount());
+            server_session->GetSessionRequestManager()->AppendDomainHandler(std::move(object));
+            cmd_buf[current_offset++] = static_cast<u32_le>(
+                server_session->GetSessionRequestManager()->DomainHandlerCount());
         }
     }
 
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 67da8e7e1..1083638a9 100755
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -45,13 +45,11 @@ class KAutoObject;
 class KernelCore;
 class KEvent;
 class KHandleTable;
-class KServerPort;
 class KProcess;
 class KServerSession;
 class KThread;
 class KReadableEvent;
 class KSession;
-class SessionRequestManager;
 class ServiceThread;
 
 enum class ThreadWakeupReason;
@@ -78,9 +76,19 @@ public:
     virtual Result HandleSyncRequest(Kernel::KServerSession& session,
                                      Kernel::HLERequestContext& context) = 0;
 
-    void AcceptSession(KServerPort* server_port);
-    void RegisterSession(KServerSession* server_session,
-                         std::shared_ptr<SessionRequestManager> manager);
+    /**
+     * 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(KServerSession* 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(KServerSession* session);
 
     std::weak_ptr<ServiceThread> GetServiceThread() const {
         return service_thread;
@@ -162,6 +170,7 @@ public:
 
     Result HandleDomainSyncRequest(KServerSession* server_session, HLERequestContext& context);
     Result CompleteSyncRequest(KServerSession* server_session, HLERequestContext& context);
+    Result QueueSyncRequest(KSession* parent, std::shared_ptr<HLERequestContext>&& context);
 
 private:
     bool convert_to_domain{};
@@ -341,11 +350,11 @@ public:
 
     template <typename T>
     std::shared_ptr<T> GetDomainHandler(std::size_t index) const {
-        return std::static_pointer_cast<T>(GetManager()->DomainHandler(index).lock());
+        return std::static_pointer_cast<T>(manager.lock()->DomainHandler(index).lock());
     }
 
     void SetSessionRequestManager(std::weak_ptr<SessionRequestManager> manager_) {
-        manager = manager_;
+        manager = std::move(manager_);
     }
 
     std::string Description() const;
@@ -354,10 +363,6 @@ public:
         return *thread;
     }
 
-    std::shared_ptr<SessionRequestManager> GetManager() const {
-        return manager.lock();
-    }
-
 private:
     friend class IPC::ResponseBuilder;
 
@@ -391,7 +396,7 @@ private:
     u32 handles_offset{};
     u32 domain_offset{};
 
-    std::weak_ptr<SessionRequestManager> manager{};
+    std::weak_ptr<SessionRequestManager> manager;
 
     KernelCore& kernel;
     Core::Memory::Memory& memory;
diff --git a/src/core/hle/kernel/k_client_port.cpp b/src/core/hle/kernel/k_client_port.cpp
index eaa2e094c..3cb22ff4d 100755
--- a/src/core/hle/kernel/k_client_port.cpp
+++ b/src/core/hle/kernel/k_client_port.cpp
@@ -58,7 +58,8 @@ bool KClientPort::IsSignaled() const {
     return num_sessions < max_sessions;
 }
 
-Result KClientPort::CreateSession(KClientSession** out) {
+Result KClientPort::CreateSession(KClientSession** out,
+                                  std::shared_ptr<SessionRequestManager> session_manager) {
     // Reserve a new session from the resource limit.
     KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(),
                                                    LimitableResource::Sessions);
@@ -103,7 +104,7 @@ Result KClientPort::CreateSession(KClientSession** out) {
     }
 
     // Initialize the session.
-    session->Initialize(this, parent->GetName());
+    session->Initialize(this, parent->GetName(), session_manager);
 
     // Commit the session reservation.
     session_reservation.Commit();
diff --git a/src/core/hle/kernel/k_client_port.h b/src/core/hle/kernel/k_client_port.h
index 81046fb86..e17eff28f 100755
--- a/src/core/hle/kernel/k_client_port.h
+++ b/src/core/hle/kernel/k_client_port.h
@@ -52,7 +52,8 @@ public:
     void Destroy() override;
     bool IsSignaled() const override;
 
-    Result CreateSession(KClientSession** out);
+    Result CreateSession(KClientSession** out,
+                         std::shared_ptr<SessionRequestManager> session_manager = nullptr);
 
 private:
     std::atomic<s32> num_sessions{};
diff --git a/src/core/hle/kernel/k_port.cpp b/src/core/hle/kernel/k_port.cpp
index 77d00ae2c..7a5a9dc2a 100755
--- a/src/core/hle/kernel/k_port.cpp
+++ b/src/core/hle/kernel/k_port.cpp
@@ -57,6 +57,12 @@ Result KPort::EnqueueSession(KServerSession* session) {
 
     server.EnqueueSession(session);
 
+    if (auto session_ptr = server.GetSessionRequestHandler().lock()) {
+        session_ptr->ClientConnected(server.AcceptSession());
+    } else {
+        ASSERT(false);
+    }
+
     return ResultSuccess;
 }
 
diff --git a/src/core/hle/kernel/k_server_port.cpp b/src/core/hle/kernel/k_server_port.cpp
index 12e0c3ffb..e968f26ad 100755
--- a/src/core/hle/kernel/k_server_port.cpp
+++ b/src/core/hle/kernel/k_server_port.cpp
@@ -19,8 +19,6 @@ void KServerPort::Initialize(KPort* parent_port_, std::string&& name_) {
     // Set member variables.
     parent = parent_port_;
     name = std::move(name_);
-
-    kernel.RegisterServerObject(this);
 }
 
 bool KServerPort::IsLight() const {
@@ -64,6 +62,9 @@ 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);
 }
diff --git a/src/core/hle/kernel/k_server_port.h b/src/core/hle/kernel/k_server_port.h
index 5fc7ee683..fd4f4bd20 100755
--- a/src/core/hle/kernel/k_server_port.h
+++ b/src/core/hle/kernel/k_server_port.h
@@ -27,6 +27,24 @@ public:
 
     void Initialize(KPort* parent_port_, std::string&& name_);
 
+    /// Whether or not this server port has an HLE handler available.
+    bool HasSessionRequestHandler() const {
+        return !session_handler.expired();
+    }
+
+    /// Gets the HLE handler for this port.
+    SessionRequestHandlerWeakPtr GetSessionRequestHandler() const {
+        return session_handler;
+    }
+
+    /**
+     * Sets the HLE handler template for the port. ServerSessions crated by connecting to this port
+     * will inherit a reference to this handler.
+     */
+    void SetSessionHandler(SessionRequestHandlerWeakPtr&& handler) {
+        session_handler = std::move(handler);
+    }
+
     void EnqueueSession(KServerSession* pending_session);
 
     KServerSession* AcceptSession();
@@ -47,6 +65,7 @@ private:
     void CleanupSessions();
 
     SessionList session_list;
+    SessionRequestHandlerWeakPtr session_handler;
     KPort* parent{};
 };
 
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp
index aa1941f01..faf03fcc8 100755
--- a/src/core/hle/kernel/k_server_session.cpp
+++ b/src/core/hle/kernel/k_server_session.cpp
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
 // SPDX-License-Identifier: GPL-2.0-or-later
 
 #include <tuple>
@@ -33,10 +33,12 @@ KServerSession::KServerSession(KernelCore& kernel_)
 
 KServerSession::~KServerSession() = default;
 
-void KServerSession::Initialize(KSession* parent_session_, std::string&& name_) {
+void KServerSession::Initialize(KSession* parent_session_, std::string&& name_,
+                                std::shared_ptr<SessionRequestManager> manager_) {
     // Set member variables.
     parent = parent_session_;
     name = std::move(name_);
+    manager = manager_;
 }
 
 void KServerSession::Destroy() {
@@ -45,99 +47,18 @@ void KServerSession::Destroy() {
     this->CleanupRequests();
 
     parent->Close();
+
+    // 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() {
-    KScopedLightLock lk{m_lock};
-
-    // Handle any pending requests.
-    KSessionRequest* prev_request = nullptr;
-    while (true) {
-        // Declare variables for processing the request.
-        KSessionRequest* request = nullptr;
-        KEvent* event = nullptr;
-        KThread* thread = nullptr;
-        bool cur_request = false;
-        bool terminate = false;
-
-        // Get the next request.
-        {
-            KScopedSchedulerLock sl{kernel};
-
-            if (m_current_request != nullptr && m_current_request != prev_request) {
-                // Set the request, open a reference as we process it.
-                request = m_current_request;
-                request->Open();
-                cur_request = true;
-
-                // Get thread and event for the request.
-                thread = request->GetThread();
-                event = request->GetEvent();
-
-                // If the thread is terminating, handle that.
-                if (thread->IsTerminationRequested()) {
-                    request->ClearThread();
-                    request->ClearEvent();
-                    terminate = true;
-                }
-
-                prev_request = request;
-            } else if (!m_request_list.empty()) {
-                // Pop the request from the front of the list.
-                request = std::addressof(m_request_list.front());
-                m_request_list.pop_front();
-
-                // Get thread and event for the request.
-                thread = request->GetThread();
-                event = request->GetEvent();
-            }
-        }
-
-        // If there are no requests, we're done.
-        if (request == nullptr) {
-            break;
-        }
-
-        // All requests must have threads.
-        ASSERT(thread != nullptr);
-
-        // Ensure that we close the request when done.
-        SCOPE_EXIT({ request->Close(); });
-
-        // If we're terminating, close a reference to the thread and event.
-        if (terminate) {
-            thread->Close();
-            if (event != nullptr) {
-                event->Close();
-            }
-        }
-
-        // If we need to, reply.
-        if (event != nullptr && !cur_request) {
-            // There must be no mappings.
-            ASSERT(request->GetSendCount() == 0);
-            ASSERT(request->GetReceiveCount() == 0);
-            ASSERT(request->GetExchangeCount() == 0);
-
-            // // Get the process and page table.
-            // KProcess *client_process = thread->GetOwnerProcess();
-            // auto &client_pt = client_process->GetPageTable();
-
-            // // Reply to the request.
-            // ReplyAsyncError(client_process, request->GetAddress(), request->GetSize(),
-            //                 ResultSessionClosed);
-
-            // // Unlock the buffer.
-            // // NOTE: Nintendo does not check the result of this.
-            // client_pt.UnlockForIpcUserBuffer(request->GetAddress(), request->GetSize());
-
-            // Signal the event.
-            event->Signal();
-        }
+    if (manager && manager->HasSessionHandler()) {
+        manager->SessionHandler().ClientDisconnected(this);
     }
-
-    // Notify.
-    this->NotifyAvailable(ResultSessionClosed);
 }
 
 bool KServerSession::IsSignaled() const {
@@ -152,6 +73,24 @@ bool KServerSession::IsSignaled() const {
     return !m_request_list.empty() && m_current_request == nullptr;
 }
 
+Result KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory) {
+    u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(thread->GetTLSAddress()))};
+    auto context = std::make_shared<HLERequestContext>(kernel, memory, this, thread);
+
+    context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
+
+    return manager->QueueSyncRequest(parent, std::move(context));
+}
+
+Result KServerSession::CompleteSyncRequest(HLERequestContext& context) {
+    Result result = manager->CompleteSyncRequest(this, context);
+
+    // The calling thread is waiting for this request to complete, so wake it up.
+    context.GetThread().EndWait(result);
+
+    return result;
+}
+
 Result KServerSession::OnRequest(KSessionRequest* request) {
     // Create the wait queue.
     ThreadQueueImplForKServerSessionRequest wait_queue{kernel};
@@ -166,16 +105,24 @@ Result KServerSession::OnRequest(KSessionRequest* request) {
         // Check that we're not terminating.
         R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), ResultTerminationRequested);
 
-        // Get whether we're empty.
-        const bool was_empty = m_request_list.empty();
+        if (manager) {
+            // HLE request.
+            auto& memory{kernel.System().Memory()};
+            this->QueueSyncRequest(GetCurrentThreadPointer(kernel), memory);
+        } else {
+            // Non-HLE request.
 
-        // Add the request to the list.
-        request->Open();
-        m_request_list.push_back(*request);
+            // Get whether we're empty.
+            const bool was_empty = m_request_list.empty();
 
-        // If we were empty, signal.
-        if (was_empty) {
-            this->NotifyAvailable();
+            // Add the request to the list.
+            request->Open();
+            m_request_list.push_back(*request);
+
+            // If we were empty, signal.
+            if (was_empty) {
+                this->NotifyAvailable();
+            }
         }
 
         // If we have a request event, this is asynchronous, and we don't need to wait.
@@ -189,7 +136,7 @@ Result KServerSession::OnRequest(KSessionRequest* request) {
     return GetCurrentThread(kernel).GetWaitResult();
 }
 
-Result KServerSession::SendReply(bool is_hle) {
+Result KServerSession::SendReply() {
     // Lock the session.
     KScopedLightLock lk{m_lock};
 
@@ -224,18 +171,13 @@ Result KServerSession::SendReply(bool is_hle) {
     Result result = ResultSuccess;
     if (!closed) {
         // If we're not closed, send the reply.
-        if (is_hle) {
-            // HLE servers write directly to a pointer to the thread command buffer. Therefore
-            // the reply has already been written in this case.
-        } else {
-            Core::Memory::Memory& memory{kernel.System().Memory()};
-            KThread* server_thread{GetCurrentThreadPointer(kernel)};
-            UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
+        Core::Memory::Memory& memory{kernel.System().Memory()};
+        KThread* server_thread{GetCurrentThreadPointer(kernel)};
+        UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
 
-            auto* src_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress());
-            auto* dst_msg_buffer = memory.GetPointer(client_message);
-            std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
-        }
+        auto* src_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress());
+        auto* dst_msg_buffer = memory.GetPointer(client_message);
+        std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
     } else {
         result = ResultSessionClosed;
     }
@@ -281,8 +223,7 @@ Result KServerSession::SendReply(bool is_hle) {
     return result;
 }
 
-Result KServerSession::ReceiveRequest(std::shared_ptr<HLERequestContext>* out_context,
-                                      std::weak_ptr<SessionRequestManager> manager) {
+Result KServerSession::ReceiveRequest() {
     // Lock the session.
     KScopedLightLock lk{m_lock};
 
@@ -326,22 +267,12 @@ Result KServerSession::ReceiveRequest(std::shared_ptr<HLERequestContext>* out_co
 
     // Receive the message.
     Core::Memory::Memory& memory{kernel.System().Memory()};
-    if (out_context != nullptr) {
-        // HLE request.
-        u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(client_message))};
-        *out_context = std::make_shared<HLERequestContext>(kernel, memory, this, client_thread);
-        (*out_context)->SetSessionRequestManager(manager);
-        (*out_context)
-            ->PopulateFromIncomingCommandBuffer(client_thread->GetOwnerProcess()->GetHandleTable(),
-                                                cmd_buf);
-    } else {
-        KThread* server_thread{GetCurrentThreadPointer(kernel)};
-        UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
+    KThread* server_thread{GetCurrentThreadPointer(kernel)};
+    UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
 
-        auto* src_msg_buffer = memory.GetPointer(client_message);
-        auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress());
-        std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
-    }
+    auto* src_msg_buffer = memory.GetPointer(client_message);
+    auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress());
+    std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
 
     // We succeeded.
     return ResultSuccess;
diff --git a/src/core/hle/kernel/k_server_session.h b/src/core/hle/kernel/k_server_session.h
index 6e189af8b..32135473b 100755
--- a/src/core/hle/kernel/k_server_session.h
+++ b/src/core/hle/kernel/k_server_session.h
@@ -1,4 +1,4 @@
-// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
 // SPDX-License-Identifier: GPL-2.0-or-later
 
 #pragma once
@@ -16,11 +16,21 @@
 #include "core/hle/kernel/k_synchronization_object.h"
 #include "core/hle/result.h"
 
+namespace Core::Memory {
+class Memory;
+}
+
+namespace Core::Timing {
+class CoreTiming;
+struct EventType;
+} // namespace Core::Timing
+
 namespace Kernel {
 
 class HLERequestContext;
 class KernelCore;
 class KSession;
+class SessionRequestHandler;
 class SessionRequestManager;
 class KThread;
 
@@ -36,7 +46,8 @@ public:
 
     void Destroy() override;
 
-    void Initialize(KSession* parent_session_, std::string&& name_);
+    void Initialize(KSession* parent_session_, std::string&& name_,
+                    std::shared_ptr<SessionRequestManager> manager_);
 
     KSession* GetParent() {
         return parent;
@@ -49,26 +60,38 @@ public:
     bool IsSignaled() const override;
     void OnClientClosed();
 
+    /// Gets the session request manager, which forwards requests to the underlying service
+    std::shared_ptr<SessionRequestManager>& GetSessionRequestManager() {
+        return manager;
+    }
+
     /// TODO: flesh these out to match the real kernel
     Result OnRequest(KSessionRequest* request);
-    Result SendReply(bool is_hle = false);
-    Result ReceiveRequest(std::shared_ptr<HLERequestContext>* out_context = nullptr,
-                          std::weak_ptr<SessionRequestManager> manager = {});
-
-    Result SendReplyHLE() {
-        return SendReply(true);
-    }
+    Result SendReply();
+    Result ReceiveRequest();
 
 private:
     /// Frees up waiting client sessions when this server session is about to die
     void CleanupRequests();
 
+    /// Queues a sync request from the emulated application.
+    Result QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory);
+
+    /// Completes a sync request from the emulated application.
+    Result CompleteSyncRequest(HLERequestContext& context);
+
+    /// This session's HLE request handlers; if nullptr, this is not an HLE server
+    std::shared_ptr<SessionRequestManager> manager;
+
+    /// When set to True, converts the session to a domain at the end of the command
+    bool convert_to_domain{};
+
     /// KSession that owns this KServerSession
     KSession* parent{};
 
     /// List of threads which are pending a reply.
     boost::intrusive::list<KSessionRequest> m_request_list;
-    KSessionRequest* m_current_request{};
+    KSessionRequest* m_current_request;
 
     KLightLock m_lock;
 };
diff --git a/src/core/hle/kernel/k_session.cpp b/src/core/hle/kernel/k_session.cpp
index 7a6534ac3..ee05aa282 100755
--- a/src/core/hle/kernel/k_session.cpp
+++ b/src/core/hle/kernel/k_session.cpp
@@ -13,7 +13,8 @@ KSession::KSession(KernelCore& kernel_)
     : KAutoObjectWithSlabHeapAndContainer{kernel_}, server{kernel_}, client{kernel_} {}
 KSession::~KSession() = default;
 
-void KSession::Initialize(KClientPort* port_, const std::string& name_) {
+void KSession::Initialize(KClientPort* port_, const std::string& name_,
+                          std::shared_ptr<SessionRequestManager> manager_) {
     // Increment reference count.
     // Because reference count is one on creation, this will result
     // in a reference count of two. Thus, when both server and client are closed
@@ -25,7 +26,7 @@ void KSession::Initialize(KClientPort* port_, const std::string& name_) {
     KAutoObject::Create(std::addressof(client));
 
     // Initialize our sub sessions.
-    server.Initialize(this, name_ + ":Server");
+    server.Initialize(this, name_ + ":Server", manager_);
     client.Initialize(this, name_ + ":Client");
 
     // Set state and name.
diff --git a/src/core/hle/kernel/k_session.h b/src/core/hle/kernel/k_session.h
index 93e5e6f71..c6ead403b 100755
--- a/src/core/hle/kernel/k_session.h
+++ b/src/core/hle/kernel/k_session.h
@@ -21,7 +21,8 @@ public:
     explicit KSession(KernelCore& kernel_);
     ~KSession() override;
 
-    void Initialize(KClientPort* port_, const std::string& name_);
+    void Initialize(KClientPort* port_, const std::string& name_,
+                    std::shared_ptr<SessionRequestManager> manager_ = nullptr);
 
     void Finalize() override;
 
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 29e122dfd..fdc774e30 100755
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -60,6 +60,7 @@ struct KernelCore::Impl {
         global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
         global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel);
         global_handle_table->Initialize(KHandleTable::MaxTableSize);
+        default_service_thread = CreateServiceThread(kernel, "DefaultServiceThread");
 
         is_phantom_mode_for_singlecore = false;
 
@@ -85,8 +86,6 @@ struct KernelCore::Impl {
         }
 
         RegisterHostThread();
-
-        default_service_thread = CreateServiceThread(kernel, "DefaultServiceThread");
     }
 
     void InitializeCores() {
@@ -704,15 +703,6 @@ struct KernelCore::Impl {
         return port;
     }
 
-    void RegisterNamedServiceHandler(std::string name, KServerPort* server_port) {
-        auto search = service_interface_handlers.find(name);
-        if (search == service_interface_handlers.end()) {
-            return;
-        }
-
-        search->second(system.ServiceManager(), server_port);
-    }
-
     void RegisterServerObject(KAutoObject* server_object) {
         std::scoped_lock lk(server_objects_lock);
         server_objects.insert(server_object);
@@ -725,7 +715,7 @@ struct KernelCore::Impl {
 
     std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(KernelCore& kernel,
                                                              const std::string& name) {
-        auto service_thread = std::make_shared<Kernel::ServiceThread>(kernel, name);
+        auto service_thread = std::make_shared<Kernel::ServiceThread>(kernel, 1, name);
 
         service_threads_manager.QueueWork(
             [this, service_thread]() { service_threads.emplace(service_thread); });
@@ -784,7 +774,6 @@ struct KernelCore::Impl {
     /// Map of named ports managed by the kernel, which can be retrieved using
     /// the ConnectToPort SVC.
     std::unordered_map<std::string, ServiceInterfaceFactory> service_interface_factory;
-    std::unordered_map<std::string, ServiceInterfaceHandlerFn> service_interface_handlers;
     NamedPortTable named_ports;
     std::unordered_set<KAutoObject*> server_objects;
     std::unordered_set<KAutoObject*> registered_objects;
@@ -992,19 +981,10 @@ void KernelCore::RegisterNamedService(std::string name, ServiceInterfaceFactory&
     impl->service_interface_factory.emplace(std::move(name), factory);
 }
 
-void KernelCore::RegisterInterfaceForNamedService(std::string name,
-                                                  ServiceInterfaceHandlerFn&& handler) {
-    impl->service_interface_handlers.emplace(std::move(name), handler);
-}
-
 KClientPort* KernelCore::CreateNamedServicePort(std::string name) {
     return impl->CreateNamedServicePort(std::move(name));
 }
 
-void KernelCore::RegisterNamedServiceHandler(std::string name, KServerPort* server_port) {
-    impl->RegisterNamedServiceHandler(std::move(name), server_port);
-}
-
 void KernelCore::RegisterServerObject(KAutoObject* server_object) {
     impl->RegisterServerObject(server_object);
 }
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 670f93ee3..266be2bc4 100755
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -45,7 +45,6 @@ class KPort;
 class KProcess;
 class KResourceLimit;
 class KScheduler;
-class KServerPort;
 class KServerSession;
 class KSession;
 class KSessionRequest;
@@ -64,8 +63,6 @@ class TimeManager;
 using ServiceInterfaceFactory =
     std::function<KClientPort&(Service::SM::ServiceManager&, Core::System&)>;
 
-using ServiceInterfaceHandlerFn = std::function<void(Service::SM::ServiceManager&, KServerPort*)>;
-
 namespace Init {
 struct KSlabResourceCounts;
 }
@@ -195,15 +192,9 @@ public:
     /// Registers a named HLE service, passing a factory used to open a port to that service.
     void RegisterNamedService(std::string name, ServiceInterfaceFactory&& factory);
 
-    /// Registers a setup function for the named HLE service.
-    void RegisterInterfaceForNamedService(std::string name, ServiceInterfaceHandlerFn&& handler);
-
     /// Opens a port to a service previously registered with RegisterNamedService.
     KClientPort* CreateNamedServicePort(std::string name);
 
-    /// Accepts a session on a port created by CreateNamedServicePort.
-    void RegisterNamedServiceHandler(std::string name, KServerPort* server_port);
-
     /// 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);
diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp
index c8fe42537..d23d76706 100755
--- a/src/core/hle/kernel/service_thread.cpp
+++ b/src/core/hle/kernel/service_thread.cpp
@@ -1,18 +1,15 @@
-// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
 // SPDX-License-Identifier: GPL-2.0-or-later
 
+#include <condition_variable>
 #include <functional>
-#include <map>
 #include <mutex>
 #include <thread>
 #include <vector>
+#include <queue>
 
 #include "common/scope_exit.h"
 #include "common/thread.h"
-#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/hle_ipc.h"
-#include "core/hle/kernel/k_event.h"
-#include "core/hle/kernel/k_scoped_resource_reservation.h"
 #include "core/hle/kernel/k_session.h"
 #include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/kernel.h"
@@ -22,198 +19,101 @@ namespace Kernel {
 
 class ServiceThread::Impl final {
 public:
-    explicit Impl(KernelCore& kernel, const std::string& service_name);
+    explicit Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name);
     ~Impl();
 
-    void WaitAndProcessImpl();
-    void SessionClosed(KServerSession* server_session,
-                       std::shared_ptr<SessionRequestManager> manager);
-    void LoopProcess();
-
-    void RegisterServerSession(KServerSession* session,
-                               std::shared_ptr<SessionRequestManager> manager);
+    void QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context);
 
 private:
-    KernelCore& kernel;
-
-    std::jthread m_thread;
-    std::mutex m_session_mutex;
-    std::map<KServerSession*, std::shared_ptr<SessionRequestManager>> m_sessions;
-    KEvent* m_wakeup_event;
-    KProcess* m_process;
-    std::atomic<bool> m_shutdown_requested;
-    const std::string m_service_name;
+    std::vector<std::jthread> threads;
+    std::queue<std::function<void()>> requests;
+    std::mutex queue_mutex;
+    std::condition_variable_any condition;
+    const std::string service_name;
 };
 
-void ServiceThread::Impl::WaitAndProcessImpl() {
-    // Create local list of waitable sessions.
-    std::vector<KSynchronizationObject*> objs;
-    std::vector<std::shared_ptr<SessionRequestManager>> managers;
+ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name)
+    : service_name{name} {
+    for (std::size_t i = 0; i < num_threads; ++i) {
+        threads.emplace_back([this, &kernel](std::stop_token stop_token) {
+            Common::SetCurrentThreadName(std::string{service_name}.c_str());
 
-    {
-        // Lock to get the set.
-        std::scoped_lock lk{m_session_mutex};
+            // Wait for first request before trying to acquire a render context
+            {
+                std::unique_lock lock{queue_mutex};
+                condition.wait(lock, stop_token, [this] { return !requests.empty(); });
+            }
 
-        // Reserve the needed quantity.
-        objs.reserve(m_sessions.size() + 1);
-        managers.reserve(m_sessions.size());
+            if (stop_token.stop_requested()) {
+                return;
+            }
 
-        // Copy to our local list.
-        for (const auto& [session, manager] : m_sessions) {
-            objs.push_back(session);
-            managers.push_back(manager);
-        }
+            // Allocate a dummy guest thread for this host thread.
+            kernel.RegisterHostThread();
 
-        // Insert the wakeup event at the end.
-        objs.push_back(&m_wakeup_event->GetReadableEvent());
-    }
+            while (true) {
+                std::function<void()> task;
 
-    // Wait on the list of sessions.
-    s32 index{-1};
-    Result rc = KSynchronizationObject::Wait(kernel, &index, objs.data(),
-                                             static_cast<s32>(objs.size()), -1);
-    ASSERT(!rc.IsFailure());
+                {
+                    std::unique_lock lock{queue_mutex};
+                    condition.wait(lock, stop_token, [this] { return !requests.empty(); });
 
-    // If this was the wakeup event, clear it and finish.
-    if (index >= static_cast<s64>(objs.size() - 1)) {
-        m_wakeup_event->Clear();
-        return;
-    }
+                    if (stop_token.stop_requested()) {
+                        return;
+                    }
 
-    // This event is from a server session.
-    auto* server_session = static_cast<KServerSession*>(objs[index]);
-    auto& manager = managers[index];
+                    if (requests.empty()) {
+                        continue;
+                    }
 
-    // Fetch the HLE request context.
-    std::shared_ptr<HLERequestContext> context;
-    rc = server_session->ReceiveRequest(&context, manager);
+                    task = std::move(requests.front());
+                    requests.pop();
+                }
 
-    // If the session was closed, handle that.
-    if (rc == ResultSessionClosed) {
-        SessionClosed(server_session, manager);
-
-        // Finish.
-        return;
-    }
-
-    // TODO: handle other cases
-    ASSERT(rc == ResultSuccess);
-
-    // Perform the request.
-    Result service_rc = manager->CompleteSyncRequest(server_session, *context);
-
-    // Reply to the client.
-    rc = server_session->SendReplyHLE();
-
-    if (rc == ResultSessionClosed || service_rc == IPC::ERR_REMOTE_PROCESS_DEAD) {
-        SessionClosed(server_session, manager);
-        return;
-    }
-
-    // TODO: handle other cases
-    ASSERT(rc == ResultSuccess);
-    ASSERT(service_rc == ResultSuccess);
-}
-
-void ServiceThread::Impl::SessionClosed(KServerSession* server_session,
-                                        std::shared_ptr<SessionRequestManager> manager) {
-    {
-        // Lock to get the set.
-        std::scoped_lock lk{m_session_mutex};
-
-        // Erase the session.
-        ASSERT(m_sessions.erase(server_session) == 1);
-    }
-
-    // Close our reference to the server session.
-    server_session->Close();
-}
-
-void ServiceThread::Impl::LoopProcess() {
-    Common::SetCurrentThreadName(m_service_name.c_str());
-
-    kernel.RegisterHostThread();
-
-    while (!m_shutdown_requested.load()) {
-        WaitAndProcessImpl();
+                task();
+            }
+        });
     }
 }
 
-void ServiceThread::Impl::RegisterServerSession(KServerSession* server_session,
-                                                std::shared_ptr<SessionRequestManager> manager) {
-    // Open the server session.
-    server_session->Open();
-
+void ServiceThread::Impl::QueueSyncRequest(KSession& session,
+                                           std::shared_ptr<HLERequestContext>&& context) {
     {
-        // Lock to get the set.
-        std::scoped_lock lk{m_session_mutex};
+        std::unique_lock lock{queue_mutex};
 
-        // Insert the session and manager.
-        m_sessions[server_session] = manager;
+        auto* server_session{&session.GetServerSession()};
+
+        // Open a reference to the session to ensure it is not closes while the service request
+        // completes asynchronously.
+        server_session->Open();
+
+        requests.emplace([server_session, context{std::move(context)}]() {
+            // Close the reference.
+            SCOPE_EXIT({ server_session->Close(); });
+
+            // Complete the service request.
+            server_session->CompleteSyncRequest(*context);
+        });
     }
-
-    // Signal the wakeup event.
-    m_wakeup_event->Signal();
+    condition.notify_one();
 }
 
 ServiceThread::Impl::~Impl() {
-    // Shut down the processing thread.
-    m_shutdown_requested.store(true);
-    m_wakeup_event->Signal();
-    m_thread.join();
-
-    // Lock mutex.
-    m_session_mutex.lock();
-
-    // Close all remaining sessions.
-    for (const auto& [server_session, manager] : m_sessions) {
-        server_session->Close();
+    condition.notify_all();
+    for (auto& thread : threads) {
+        thread.request_stop();
+        thread.join();
     }
-
-    // Destroy remaining managers.
-    m_sessions.clear();
-
-    // Close event.
-    m_wakeup_event->GetReadableEvent().Close();
-    m_wakeup_event->Close();
-
-    // Close process.
-    m_process->Close();
 }
 
-ServiceThread::Impl::Impl(KernelCore& kernel_, const std::string& service_name)
-    : kernel{kernel_}, m_service_name{service_name} {
-    // Initialize process.
-    m_process = KProcess::Create(kernel);
-    KProcess::Initialize(m_process, kernel.System(), service_name,
-                         KProcess::ProcessType::KernelInternal, kernel.GetSystemResourceLimit());
-
-    // Reserve a new event from the process resource limit
-    KScopedResourceReservation event_reservation(m_process, LimitableResource::Events);
-    ASSERT(event_reservation.Succeeded());
-
-    // Initialize event.
-    m_wakeup_event = KEvent::Create(kernel);
-    m_wakeup_event->Initialize(m_process);
-
-    // Commit the event reservation.
-    event_reservation.Commit();
-
-    // Register the event.
-    KEvent::Register(kernel, m_wakeup_event);
-
-    // Start thread.
-    m_thread = std::jthread([this] { LoopProcess(); });
-}
-
-ServiceThread::ServiceThread(KernelCore& kernel, const std::string& name)
-    : impl{std::make_unique<Impl>(kernel, name)} {}
+ServiceThread::ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name)
+    : impl{std::make_unique<Impl>(kernel, num_threads, name)} {}
 
 ServiceThread::~ServiceThread() = default;
 
-void ServiceThread::RegisterServerSession(KServerSession* session,
-                                          std::shared_ptr<SessionRequestManager> manager) {
-    impl->RegisterServerSession(session, manager);
+void ServiceThread::QueueSyncRequest(KSession& session,
+                                     std::shared_ptr<HLERequestContext>&& context) {
+    impl->QueueSyncRequest(session, std::move(context));
 }
 
 } // namespace Kernel
diff --git a/src/core/hle/kernel/service_thread.h b/src/core/hle/kernel/service_thread.h
index fb4325531..c5896f2bd 100755
--- a/src/core/hle/kernel/service_thread.h
+++ b/src/core/hle/kernel/service_thread.h
@@ -11,15 +11,13 @@ namespace Kernel {
 class HLERequestContext;
 class KernelCore;
 class KSession;
-class SessionRequestManager;
 
 class ServiceThread final {
 public:
-    explicit ServiceThread(KernelCore& kernel, const std::string& name);
+    explicit ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name);
     ~ServiceThread();
 
-    void RegisterServerSession(KServerSession* session,
-                               std::shared_ptr<SessionRequestManager> manager);
+    void QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context);
 
 private:
     class Impl;
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 8d2c7d6b7..4aca5b27d 100755
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -24,7 +24,6 @@
 #include "core/hle/kernel/k_memory_block.h"
 #include "core/hle/kernel/k_memory_layout.h"
 #include "core/hle/kernel/k_page_table.h"
-#include "core/hle/kernel/k_port.h"
 #include "core/hle/kernel/k_process.h"
 #include "core/hle/kernel/k_readable_event.h"
 #include "core/hle/kernel/k_resource_limit.h"
@@ -383,11 +382,10 @@ static Result ConnectToNamedPort(Core::System& system, Handle* out, VAddr port_n
 
     // Create a session.
     KClientSession* session{};
-    R_TRY(port->CreateSession(std::addressof(session)));
+    R_TRY(port->CreateSession(std::addressof(session),
+                              std::make_shared<SessionRequestManager>(kernel)));
     port->Close();
 
-    kernel.RegisterNamedServiceHandler(port_name, &port->GetParent()->GetServerPort());
-
     // Register the session in the table, close the extra reference.
     handle_table.Register(*out, session);
     session->Close();
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 0913a8065..5db6588e4 100755
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -99,10 +99,6 @@ ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* se
 ServiceFrameworkBase::~ServiceFrameworkBase() {
     // Wait for other threads to release access before destroying
     const auto guard = LockService();
-
-    if (named_port != nullptr) {
-        named_port->Close();
-    }
 }
 
 void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) {
@@ -119,12 +115,13 @@ Kernel::KClientPort& ServiceFrameworkBase::CreatePort() {
 
     ASSERT(!service_registered);
 
-    named_port = Kernel::KPort::Create(kernel);
-    named_port->Initialize(max_sessions, false, service_name);
+    auto* port = Kernel::KPort::Create(kernel);
+    port->Initialize(max_sessions, false, service_name);
+    port->GetServerPort().SetSessionHandler(shared_from_this());
 
     service_registered = true;
 
-    return named_port->GetClientPort();
+    return port->GetClientPort();
 }
 
 void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) {
@@ -202,6 +199,7 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session,
     switch (ctx.GetCommandType()) {
     case IPC::CommandType::Close:
     case IPC::CommandType::TIPC_Close: {
+        session.Close();
         IPC::ResponseBuilder rb{ctx, 2};
         rb.Push(ResultSuccess);
         result = IPC::ERR_REMOTE_PROCESS_DEAD;
@@ -246,7 +244,6 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
     system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false);
 
     system.Kernel().RegisterNamedService("sm:", SM::ServiceManager::InterfaceFactory);
-    system.Kernel().RegisterInterfaceForNamedService("sm:", SM::ServiceManager::SessionHandler);
 
     Account::InstallInterfaces(system);
     AM::InstallInterfaces(*sm, *nv_flinger, system);
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 22e2119d7..ec9deeee4 100755
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -20,7 +20,6 @@ class System;
 namespace Kernel {
 class HLERequestContext;
 class KClientPort;
-class KPort;
 class KServerSession;
 class ServiceThread;
 } // namespace Kernel
@@ -99,9 +98,6 @@ protected:
     /// Identifier string used to connect to the service.
     std::string service_name;
 
-    /// Port used by ManageNamedPort.
-    Kernel::KPort* named_port{};
-
 private:
     template <typename T>
     friend class ServiceFramework;
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index b51b760ee..48e70f93c 100755
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -43,10 +43,6 @@ Kernel::KClientPort& ServiceManager::InterfaceFactory(ServiceManager& self, Core
     return self.sm_interface->CreatePort();
 }
 
-void ServiceManager::SessionHandler(ServiceManager& self, Kernel::KServerPort* server_port) {
-    self.sm_interface->AcceptSession(server_port);
-}
-
 Result ServiceManager::RegisterService(std::string name, u32 max_sessions,
                                        Kernel::SessionRequestHandlerPtr handler) {
 
@@ -88,6 +84,7 @@ ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name
 
     port->Initialize(ServerSessionCountMax, false, name);
     auto handler = it->second;
+    port->GetServerPort().SetSessionHandler(std::move(handler));
 
     return port;
 }
@@ -148,21 +145,23 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext&
 
     // Find the named port.
     auto port_result = service_manager.GetServicePort(name);
-    auto service = service_manager.GetService<Kernel::SessionRequestHandler>(name);
-    if (port_result.Failed() || !service) {
+    if (port_result.Failed()) {
         LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, port_result.Code().raw);
         return port_result.Code();
     }
     auto& port = port_result.Unwrap();
     SCOPE_EXIT({ port->GetClientPort().Close(); });
 
+    kernel.RegisterServerObject(&port->GetServerPort());
+
     // Create a new session.
     Kernel::KClientSession* session{};
-    if (const auto result = port->GetClientPort().CreateSession(&session); result.IsError()) {
+    if (const auto result = port->GetClientPort().CreateSession(
+            std::addressof(session), std::make_shared<Kernel::SessionRequestManager>(kernel));
+        result.IsError()) {
         LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.raw);
         return result;
     }
-    service->AcceptSession(&port->GetServerPort());
 
     LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId());
 
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index cfe370652..878decc6f 100755
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -51,7 +51,6 @@ private:
 class ServiceManager {
 public:
     static Kernel::KClientPort& InterfaceFactory(ServiceManager& self, Core::System& system);
-    static void SessionHandler(ServiceManager& self, Kernel::KServerPort* server_port);
 
     explicit ServiceManager(Kernel::KernelCore& kernel_);
     ~ServiceManager();
diff --git a/src/core/hle/service/sm/sm_controller.cpp b/src/core/hle/service/sm/sm_controller.cpp
index 0ddbbbb67..273f79568 100755
--- a/src/core/hle/service/sm/sm_controller.cpp
+++ b/src/core/hle/service/sm/sm_controller.cpp
@@ -15,9 +15,10 @@
 namespace Service::SM {
 
 void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) {
-    ASSERT_MSG(!ctx.GetManager()->IsDomain(), "Session is already a domain");
+    ASSERT_MSG(!ctx.Session()->GetSessionRequestManager()->IsDomain(),
+               "Session is already a domain");
     LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetId());
-    ctx.GetManager()->ConvertToDomainOnRequestEnd();
+    ctx.Session()->GetSessionRequestManager()->ConvertToDomainOnRequestEnd();
 
     IPC::ResponseBuilder rb{ctx, 3};
     rb.Push(ResultSuccess);
@@ -27,35 +28,23 @@ void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) {
 void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) {
     LOG_DEBUG(Service, "called");
 
-    auto& process = *ctx.GetThread().GetOwnerProcess();
-    auto session_manager = ctx.GetManager();
+    auto& parent_session = *ctx.Session()->GetParent();
+    auto& parent_port = parent_session.GetParent()->GetParent()->GetClientPort();
+    auto& session_manager = parent_session.GetServerSession().GetSessionRequestManager();
 
-    // FIXME: this is duplicated from the SVC, it should just call it instead
-    // once this is a proper process
-
-    // Reserve a new session from the process resource limit.
-    Kernel::KScopedResourceReservation session_reservation(&process,
-                                                           Kernel::LimitableResource::Sessions);
-    ASSERT(session_reservation.Succeeded());
-
-    // Create the sessionn.
-    Kernel::KSession* session = Kernel::KSession::Create(system.Kernel());
-    ASSERT(session != nullptr);
-
-    // Initialize the session.
-    session->Initialize(nullptr, "");
-
-    // Commit the session reservation.
-    session_reservation.Commit();
-
-    // Register with manager.
-    session_manager->SessionHandler().RegisterSession(&session->GetServerSession(),
-                                                      session_manager);
+    // Create a session.
+    Kernel::KClientSession* session{};
+    const Result result = parent_port.CreateSession(std::addressof(session), session_manager);
+    if (result.IsError()) {
+        LOG_CRITICAL(Service, "CreateSession failed with error 0x{:08X}", result.raw);
+        IPC::ResponseBuilder rb{ctx, 2};
+        rb.Push(result);
+    }
 
     // We succeeded.
     IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
     rb.Push(ResultSuccess);
-    rb.PushMoveObjects(session->GetClientSession());
+    rb.PushMoveObjects(session);
 }
 
 void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) {