From dc5d75a93278a8619ea143992ee456f7c18c26ec Mon Sep 17 00:00:00 2001 From: pineappleEA Date: Wed, 2 Nov 2022 16:51:22 +0100 Subject: [PATCH] early-access version 3075 --- README.md | 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 | 6 + 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 | 41 +++- src/core/hle/kernel/k_session.cpp | 5 +- src/core/hle/kernel/k_session.h | 3 +- src/core/hle/kernel/kernel.cpp | 52 +++-- src/core/hle/kernel/kernel.h | 15 +- src/core/hle/kernel/service_thread.cpp | 236 +++++++--------------- src/core/hle/kernel/service_thread.h | 6 +- src/core/hle/kernel/svc.cpp | 7 +- src/core/hle/service/service.cpp | 21 +- src/core/hle/service/service.h | 4 - src/core/hle/service/sm/sm.cpp | 44 ++-- src/core/hle/service/sm/sm.h | 2 - src/core/hle/service/sm/sm_controller.cpp | 16 +- 23 files changed, 339 insertions(+), 442 deletions(-) diff --git a/README.md b/README.md index b000c8ba1..abceb673d 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 3074. +This is the source code for early-access 3075. ## Legal Notice 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(flags) & static_cast(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(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 void PushIpcInterface(std::shared_ptr 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)); + session->Initialize(nullptr, iface->GetServiceName(), + std::make_shared(kernel)); context->AddMoveObject(&session->GetClientSession()); + iface->ClientConnected(&session->GetServerSession()); } } @@ -386,7 +387,7 @@ public: template std::weak_ptr PopIpcInterface() { - ASSERT(context->GetManager()->IsDomain()); + ASSERT(context->Session()->GetSessionRequestManager()->IsDomain()); ASSERT(context->GetDomainMessageHeader().input_object_count > 0); return context->GetDomainHandler(Pop() - 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(kernel)); -} - -void SessionRequestHandler::RegisterSession(KServerSession* server_session, - std::shared_ptr 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&& 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(); } 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(outgoing_domain_objects.size()); for (auto& object : outgoing_domain_objects) { - GetManager()->AppendDomainHandler(std::move(object)); - cmd_buf[current_offset++] = static_cast(GetManager()->DomainHandlerCount()); + server_session->GetSessionRequestManager()->AppendDomainHandler(std::move(object)); + cmd_buf[current_offset++] = static_cast( + 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 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 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&& context); private: bool convert_to_domain{}; @@ -341,11 +350,11 @@ public: template std::shared_ptr GetDomainHandler(std::size_t index) const { - return std::static_pointer_cast(GetManager()->DomainHandler(index).lock()); + return std::static_pointer_cast(manager.lock()->DomainHandler(index).lock()); } void SetSessionRequestManager(std::weak_ptr manager_) { - manager = manager_; + manager = std::move(manager_); } std::string Description() const; @@ -354,10 +363,6 @@ public: return *thread; } - std::shared_ptr GetManager() const { - return manager.lock(); - } - private: friend class IPC::ResponseBuilder; @@ -391,7 +396,7 @@ private: u32 handles_offset{}; u32 domain_offset{}; - std::weak_ptr manager{}; + std::weak_ptr 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 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 session_manager = nullptr); private: std::atomic 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 16968ba97..e968f26ad 100755 --- a/src/core/hle/kernel/k_server_port.cpp +++ b/src/core/hle/kernel/k_server_port.cpp @@ -61,6 +61,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 { 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 @@ -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 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(memory.GetPointer(thread->GetTLSAddress()))}; + auto context = std::make_shared(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* out_context, - std::weak_ptr manager) { +Result KServerSession::ReceiveRequest() { // Lock the session. KScopedLightLock lk{m_lock}; @@ -326,22 +267,12 @@ Result KServerSession::ReceiveRequest(std::shared_ptr* out_co // Receive the message. Core::Memory::Memory& memory{kernel.System().Memory()}; - if (out_context != nullptr) { - // HLE request. - u32* cmd_buf{reinterpret_cast(memory.GetPointer(client_message))}; - *out_context = std::make_shared(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..188aef4af 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 manager_); KSession* GetParent() { return parent; @@ -49,20 +60,32 @@ public: bool IsSignaled() const override; void OnClientClosed(); + /// Gets the session request manager, which forwards requests to the underlying service + std::shared_ptr& 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* out_context = nullptr, - std::weak_ptr 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 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{}; 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 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 manager_ = nullptr); void Finalize() override; diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 09c36ee09..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); global_handle_table = std::make_unique(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() { @@ -185,6 +184,17 @@ struct KernelCore::Impl { } void CloseServices() { + // Close all open server sessions and ports. + std::unordered_set server_objects_; + { + std::scoped_lock lk(server_objects_lock); + server_objects_ = server_objects; + server_objects.clear(); + } + for (auto* server_object : server_objects_) { + server_object->Close(); + } + // Ensures all service threads gracefully shutdown. ClearServiceThreads(); } @@ -336,8 +346,6 @@ struct KernelCore::Impl { return this_id; } - static inline thread_local bool is_phantom_mode_for_singlecore{false}; - bool IsPhantomModeForSingleCore() const { return is_phantom_mode_for_singlecore; } @@ -690,21 +698,24 @@ struct KernelCore::Impl { return {}; } - return &search->second(system.ServiceManager(), system); + KClientPort* port = &search->second(system.ServiceManager(), system); + RegisterServerObject(&port->GetParent()->GetServerPort()); + return port; } - void RegisterNamedServiceHandler(std::string name, KServerPort* server_port) { - auto search = service_interface_handlers.find(name); - if (search == service_interface_handlers.end()) { - return; - } + void RegisterServerObject(KAutoObject* server_object) { + std::scoped_lock lk(server_objects_lock); + server_objects.insert(server_object); + } - search->second(system.ServiceManager(), server_port); + void UnregisterServerObject(KAutoObject* server_object) { + std::scoped_lock lk(server_objects_lock); + server_objects.erase(server_object); } std::weak_ptr CreateServiceThread(KernelCore& kernel, const std::string& name) { - auto service_thread = std::make_shared(kernel, name); + auto service_thread = std::make_shared(kernel, 1, name); service_threads_manager.QueueWork( [this, service_thread]() { service_threads.emplace(service_thread); }); @@ -734,6 +745,7 @@ struct KernelCore::Impl { service_thread_barrier.Sync(); } + std::mutex server_objects_lock; std::mutex registered_objects_lock; std::mutex registered_in_use_objects_lock; @@ -762,8 +774,8 @@ struct KernelCore::Impl { /// Map of named ports managed by the kernel, which can be retrieved using /// the ConnectToPort SVC. std::unordered_map service_interface_factory; - std::unordered_map service_interface_handlers; NamedPortTable named_ports; + std::unordered_set server_objects; std::unordered_set registered_objects; std::unordered_set registered_in_use_objects; @@ -802,6 +814,7 @@ struct KernelCore::Impl { bool is_multicore{}; std::atomic_bool is_shutting_down{}; + bool is_phantom_mode_for_singlecore{}; u32 single_core_thread_id{}; std::array svc_ticks{}; @@ -968,17 +981,16 @@ 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); +} + +void KernelCore::UnregisterServerObject(KAutoObject* server_object) { + impl->UnregisterServerObject(server_object); } void KernelCore::RegisterKernelObject(KAutoObject* object) { diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 4ae6b3923..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; -using ServiceInterfaceHandlerFn = std::function; - namespace Init { struct KSlabResourceCounts; } @@ -195,14 +192,16 @@ 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); + + /// 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. 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 #include -#include #include #include #include +#include #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 manager); - void LoopProcess(); - - void RegisterServerSession(KServerSession* session, - std::shared_ptr manager); + void QueueSyncRequest(KSession& session, std::shared_ptr&& context); private: - KernelCore& kernel; - - std::jthread m_thread; - std::mutex m_session_mutex; - std::map> m_sessions; - KEvent* m_wakeup_event; - KProcess* m_process; - std::atomic m_shutdown_requested; - const std::string m_service_name; + std::vector threads; + std::queue> 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 objs; - std::vector> 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 task; - // Wait on the list of sessions. - s32 index{-1}; - Result rc = KSynchronizationObject::Wait(kernel, &index, objs.data(), - static_cast(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(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(objs[index]); - auto& manager = managers[index]; + if (requests.empty()) { + continue; + } - // Fetch the HLE request context. - std::shared_ptr 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 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 manager) { - // Open the server session. - server_session->Open(); - +void ServiceThread::Impl::QueueSyncRequest(KSession& session, + std::shared_ptr&& 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(kernel, name)} {} +ServiceThread::ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name) + : impl{std::make_unique(kernel, num_threads, name)} {} ServiceThread::~ServiceThread() = default; -void ServiceThread::RegisterServerSession(KServerSession* session, - std::shared_ptr manager) { - impl->RegisterServerSession(session, manager); +void ServiceThread::QueueSyncRequest(KSession& session, + std::shared_ptr&& 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 manager); + void QueueSyncRequest(KSession& session, std::shared_ptr&& context); private: class Impl; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 4c819f4b6..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,9 +382,9 @@ static Result ConnectToNamedPort(Core::System& system, Handle* out, VAddr port_n // Create a session. KClientSession* session{}; - R_TRY(port->CreateSession(std::addressof(session))); - - kernel.RegisterNamedServiceHandler(port_name, &port->GetParent()->GetServerPort()); + R_TRY(port->CreateSession(std::addressof(session), + std::make_shared(kernel))); + port->Close(); // Register the session in the table, close the extra reference. handle_table.Register(*out, session); diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 5ab41c0c4..5db6588e4 100755 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -99,12 +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->GetClientPort().Close(); - named_port->GetServerPort().Close(); - named_port = nullptr; - } } void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) { @@ -119,16 +113,15 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) Kernel::KClientPort& ServiceFrameworkBase::CreatePort() { const auto guard = LockService(); - if (named_port == nullptr) { - ASSERT(!service_registered); + 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; - } + service_registered = true; - return named_port->GetClientPort(); + return port->GetClientPort(); } void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) { @@ -206,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; @@ -250,7 +244,6 @@ Services::Services(std::shared_ptr& 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 friend class ServiceFramework; diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 84720094f..cb6c0e96f 100755 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -23,13 +23,7 @@ constexpr Result ERR_INVALID_NAME(ErrorModule::SM, 6); constexpr Result ERR_SERVICE_NOT_REGISTERED(ErrorModule::SM, 7); ServiceManager::ServiceManager(Kernel::KernelCore& kernel_) : kernel{kernel_} {} - -ServiceManager::~ServiceManager() { - for (auto& [name, port] : service_ports) { - port->GetClientPort().Close(); - port->GetServerPort().Close(); - } -} +ServiceManager::~ServiceManager() = default; void ServiceManager::InvokeControlRequest(Kernel::HLERequestContext& context) { controller_interface->InvokeRequest(context); @@ -49,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) { @@ -63,11 +53,7 @@ Result ServiceManager::RegisterService(std::string name, u32 max_sessions, return ERR_ALREADY_REGISTERED; } - auto* port = Kernel::KPort::Create(kernel); - port->Initialize(ServerSessionCountMax, false, name); - - service_ports.emplace(name, port); - registered_services.emplace(name, handler); + registered_services.emplace(std::move(name), handler); return ResultSuccess; } @@ -82,20 +68,24 @@ Result ServiceManager::UnregisterService(const std::string& name) { } registered_services.erase(iter); - service_ports.erase(name); - return ResultSuccess; } ResultVal ServiceManager::GetServicePort(const std::string& name) { CASCADE_CODE(ValidateServiceName(name)); - auto it = service_ports.find(name); - if (it == service_ports.end()) { + auto it = registered_services.find(name); + if (it == registered_services.end()) { LOG_ERROR(Service_SM, "Server is not registered! service={}", name); return ERR_SERVICE_NOT_REGISTERED; } - return it->second; + auto* port = Kernel::KPort::Create(kernel); + + port->Initialize(ServerSessionCountMax, false, name); + auto handler = it->second; + port->GetServerPort().SetSessionHandler(std::move(handler)); + + return port; } /** @@ -154,20 +144,24 @@ ResultVal SM::GetServiceImpl(Kernel::HLERequestContext& // Find the named port. auto port_result = service_manager.GetServicePort(name); - auto service = service_manager.GetService(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(); + port->GetServerPort().Close(); + }); // 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)); + 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 02a5dde9e..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(); @@ -79,7 +78,6 @@ private: /// Map of registered services, retrieved using GetServicePort. std::unordered_map registered_services; - std::unordered_map service_ports; /// Kernel context Kernel::KernelCore& kernel; diff --git a/src/core/hle/service/sm/sm_controller.cpp b/src/core/hle/service/sm/sm_controller.cpp index 69e0fe808..46a8439d8 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); @@ -28,7 +29,9 @@ 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& session_manager = parent_session.GetServerSession().GetSessionRequestManager(); + auto& session_handler = session_manager->SessionHandler(); // FIXME: this is duplicated from the SVC, it should just call it instead // once this is a proper process @@ -43,14 +46,13 @@ void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) { ASSERT(session != nullptr); // Initialize the session. - session->Initialize(nullptr, ""); + session->Initialize(nullptr, parent_session.GetName(), session_manager); // Commit the session reservation. session_reservation.Commit(); - // Register with manager. - session_manager->SessionHandler().RegisterSession(&session->GetServerSession(), - session_manager); + // Register the session. + session_handler.ClientConnected(&session->GetServerSession()); // We succeeded. IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};