diff options
author | bunnei <bunneidev@gmail.com> | 2021-04-14 02:48:37 +0200 |
---|---|---|
committer | bunnei <bunneidev@gmail.com> | 2021-05-06 01:40:51 +0200 |
commit | 7444963bbb300cff269e410948de7fa577f5ff16 (patch) | |
tree | 6e0000cb345dc02c8f2ca38958b7c90383f45b03 /src/core/hle/kernel | |
parent | hle: kernel: svc: Migrate GetThreadContext, GetThreadCoreMask. (diff) | |
download | yuzu-7444963bbb300cff269e410948de7fa577f5ff16.tar yuzu-7444963bbb300cff269e410948de7fa577f5ff16.tar.gz yuzu-7444963bbb300cff269e410948de7fa577f5ff16.tar.bz2 yuzu-7444963bbb300cff269e410948de7fa577f5ff16.tar.lz yuzu-7444963bbb300cff269e410948de7fa577f5ff16.tar.xz yuzu-7444963bbb300cff269e410948de7fa577f5ff16.tar.zst yuzu-7444963bbb300cff269e410948de7fa577f5ff16.zip |
Diffstat (limited to 'src/core/hle/kernel')
21 files changed, 384 insertions, 316 deletions
diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index d856b83e3..ce88da1c3 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -3,11 +3,10 @@ // Refer to the license.txt file included. #include "core/hle/kernel/client_port.h" -#include "core/hle/kernel/client_session.h" #include "core/hle/kernel/hle_ipc.h" +#include "core/hle/kernel/k_session.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/server_port.h" -#include "core/hle/kernel/session.h" #include "core/hle/kernel/svc_results.h" namespace Kernel { @@ -19,21 +18,22 @@ std::shared_ptr<ServerPort> ClientPort::GetServerPort() const { return server_port; } -ResultVal<std::shared_ptr<ClientSession>> ClientPort::Connect() { +ResultVal<KClientSession*> ClientPort::Connect() { if (active_sessions >= max_sessions) { return ResultOutOfSessions; } active_sessions++; - auto [client, server] = Kernel::Session::Create(kernel, name); + auto* session = Kernel::KSession::Create(kernel); + session->Initialize(name + ":ClientPort"); if (server_port->HasHLEHandler()) { - server_port->GetHLEHandler()->ClientConnected(client, std::move(server)); + server_port->GetHLEHandler()->ClientConnected(session); } else { - server_port->AppendPendingSession(std::move(server)); + server_port->AppendPendingSession(std::addressof(session->GetServerSession())); } - return MakeResult(std::move(client)); + return MakeResult(std::addressof(session->GetClientSession())); } void ClientPort::ConnectionClosed() { diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h index 77559ebf9..0b20fef40 100644 --- a/src/core/hle/kernel/client_port.h +++ b/src/core/hle/kernel/client_port.h @@ -13,7 +13,7 @@ namespace Kernel { -class ClientSession; +class KClientSession; class KernelCore; class ServerPort; @@ -43,7 +43,7 @@ public: * waiting on it to awake. * @returns ClientSession The client endpoint of the created Session pair, or error code. */ - ResultVal<std::shared_ptr<ClientSession>> Connect(); + ResultVal<KClientSession*> Connect(); /** * Signifies that a previously active connection has been closed, diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp deleted file mode 100644 index fa9cad498..000000000 --- a/src/core/hle/kernel/client_session.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2019 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/kernel/client_session.h" -#include "core/hle/kernel/hle_ipc.h" -#include "core/hle/kernel/k_thread.h" -#include "core/hle/kernel/server_session.h" -#include "core/hle/kernel/session.h" -#include "core/hle/kernel/svc_results.h" -#include "core/hle/result.h" - -namespace Kernel { - -ClientSession::ClientSession(KernelCore& kernel) : KSynchronizationObject{kernel} {} - -ClientSession::~ClientSession() { - // This destructor will be called automatically when the last ClientSession handle is closed by - // the emulated application. - if (parent->Server()) { - parent->Server()->ClientDisconnected(); - } -} - -bool ClientSession::IsSignaled() const { - UNIMPLEMENTED(); - return true; -} - -ResultVal<std::shared_ptr<ClientSession>> ClientSession::Create(KernelCore& kernel, - std::shared_ptr<Session> parent, - std::string name) { - std::shared_ptr<ClientSession> client_session{std::make_shared<ClientSession>(kernel)}; - - client_session->name = std::move(name); - client_session->parent = std::move(parent); - - return MakeResult(std::move(client_session)); -} - -ResultCode ClientSession::SendSyncRequest(KThread* thread, Core::Memory::Memory& memory, - Core::Timing::CoreTiming& core_timing) { - // Keep ServerSession alive until we're done working with it. - if (!parent->Server()) { - return ResultSessionClosed; - } - - // Signal the server session that new data is available - return parent->Server()->HandleSyncRequest(std::move(thread), memory, core_timing); -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index adfcd3c5b..ddb1e6fb2 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp @@ -56,7 +56,10 @@ ResultVal<Handle> HandleTable::Create(Object* obj) { case HandleType::Event: case HandleType::Process: case HandleType::ReadableEvent: - case HandleType::WritableEvent: { + case HandleType::WritableEvent: + case HandleType::ClientSession: + case HandleType::ServerSession: + case HandleType::Session: { Handle handle{}; Add(&handle, reinterpret_cast<KAutoObject*>(obj), {}); return MakeResult<Handle>(handle); diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 1e831aaca..d647d9dd3 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -19,12 +19,12 @@ #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" +#include "core/hle/kernel/k_server_session.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/k_writable_event.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/process.h" -#include "core/hle/kernel/server_session.h" #include "core/hle/kernel/svc_results.h" #include "core/hle/kernel/time_manager.h" #include "core/memory.h" @@ -35,24 +35,19 @@ SessionRequestHandler::SessionRequestHandler() = default; SessionRequestHandler::~SessionRequestHandler() = default; -void SessionRequestHandler::ClientConnected(std::shared_ptr<ClientSession> client_session, - std::shared_ptr<ServerSession> server_session) { - server_session->SetHleHandler(shared_from_this()); - client_sessions.push_back(std::move(client_session)); - server_sessions.push_back(std::move(server_session)); +void SessionRequestHandler::ClientConnected(KSession* session) { + session->GetServerSession().SetHleHandler(shared_from_this()); + sessions.push_back(session); } -void SessionRequestHandler::ClientDisconnected( - const std::shared_ptr<ServerSession>& server_session) { - server_session->SetHleHandler(nullptr); - boost::range::remove_erase(server_sessions, server_session); +void SessionRequestHandler::ClientDisconnected(KSession* session) { + session->GetServerSession().SetHleHandler(nullptr); + boost::range::remove_erase(sessions, session); } HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_, - std::shared_ptr<ServerSession> server_session_, - KThread* thread_) - : server_session(std::move(server_session_)), - thread(thread_), kernel{kernel_}, memory{memory_} { + KServerSession* server_session_, KThread* thread_) + : server_session(server_session_), thread(thread_), kernel{kernel_}, memory{memory_} { cmd_buf[0] = 0; } diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 74a95bc76..dc5c3b47d 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -39,10 +39,10 @@ class HandleTable; class HLERequestContext; class KernelCore; class Process; -class ClientSession; -class ServerSession; +class KServerSession; class KThread; class KReadableEvent; +class KSession; class KWritableEvent; enum class ThreadWakeupReason; @@ -72,22 +72,20 @@ public: * associated ServerSession alive for the duration of the connection. * @param server_session Owning pointer to the ServerSession associated with the connection. */ - void ClientConnected( - std::shared_ptr<ClientSession> client_session, std::shared_ptr<ServerSession> server_session); + void ClientConnected(KSession* 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(const std::shared_ptr<ServerSession>& server_session); + void ClientDisconnected(KSession* session); protected: /// List of sessions that are connected to this handler. /// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list /// for the duration of the connection. - std::vector<std::shared_ptr<ClientSession>> client_sessions; - std::vector<std::shared_ptr<ServerSession>> server_sessions; + std::vector<KSession*> sessions; }; /** @@ -112,7 +110,7 @@ protected: class HLERequestContext { public: explicit HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory, - std::shared_ptr<ServerSession> session, KThread* thread); + KServerSession* session, KThread* thread); ~HLERequestContext(); /// Returns a pointer to the IPC command buffer for this request. @@ -124,7 +122,7 @@ public: * Returns the session through which this request was made. This can be used as a map key to * access per-client data on services. */ - const std::shared_ptr<Kernel::ServerSession>& Session() const { + Kernel::KServerSession* Session() { return server_session; } @@ -288,7 +286,7 @@ private: void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming); std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; - std::shared_ptr<Kernel::ServerSession> server_session; + Kernel::KServerSession* server_session{}; KThread* thread; // TODO(yuriks): Check common usage of this and optimize size accordingly diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index b292f7db2..84d509d52 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp @@ -12,6 +12,7 @@ #include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_memory_manager.h" +#include "core/hle/kernel/k_session.h" #include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_system_control.h" #include "core/hle/kernel/k_thread.h" @@ -27,7 +28,8 @@ namespace Kernel::Init { HANDLER(Process, (SLAB_COUNT(Process)), ##__VA_ARGS__) \ HANDLER(KThread, (SLAB_COUNT(KThread)), ##__VA_ARGS__) \ HANDLER(KEvent, (SLAB_COUNT(KEvent)), ##__VA_ARGS__) \ - HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) + HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__) \ + HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) namespace { diff --git a/src/core/hle/kernel/k_client_session.cpp b/src/core/hle/kernel/k_client_session.cpp new file mode 100644 index 000000000..0618dc246 --- /dev/null +++ b/src/core/hle/kernel/k_client_session.cpp @@ -0,0 +1,31 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/kernel/hle_ipc.h" +#include "core/hle/kernel/k_client_session.h" +#include "core/hle/kernel/k_server_session.h" +#include "core/hle/kernel/k_session.h" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/svc_results.h" +#include "core/hle/result.h" + +namespace Kernel { + +KClientSession::KClientSession(KernelCore& kernel) : KAutoObjectWithSlabHeapAndContainer{kernel} {} +KClientSession::~KClientSession() = default; + +void KClientSession::Destroy() { + parent->OnClientClosed(); + parent->Close(); +} + +void KClientSession::OnServerClosed() {} + +ResultCode KClientSession::SendSyncRequest(KThread* thread, Core::Memory::Memory& memory, + Core::Timing::CoreTiming& core_timing) { + // Signal the server session that new data is available + return parent->GetServerSession().HandleSyncRequest(thread, memory, core_timing); +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/k_client_session.h index 7a1d15d0c..c4b193773 100644 --- a/src/core/hle/kernel/client_session.h +++ b/src/core/hle/kernel/k_client_session.h @@ -1,4 +1,4 @@ -// Copyright 2019 yuzu emulator team +// Copyright 2021 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -7,7 +7,9 @@ #include <memory> #include <string> +#include "core/hle/kernel/k_auto_object.h" #include "core/hle/kernel/k_synchronization_object.h" +#include "core/hle/kernel/slab_helpers.h" #include "core/hle/result.h" union ResultCode; @@ -23,43 +25,53 @@ class CoreTiming; namespace Kernel { class KernelCore; -class Session; +class KSession; class KThread; -class ClientSession final : public KSynchronizationObject { -public: - explicit ClientSession(KernelCore& kernel); - ~ClientSession() override; +class KClientSession final + : public KAutoObjectWithSlabHeapAndContainer<KClientSession, KAutoObjectWithList> { + KERNEL_AUTOOBJECT_TRAITS(KClientSession, KAutoObject); - friend class Session; +public: + explicit KClientSession(KernelCore& kernel); + virtual ~KClientSession(); - std::string GetTypeName() const override { - return "ClientSession"; + void Initialize(KSession* parent_, std::string&& name_) { + // Set member variables. + parent = parent_; + name = std::move(name_); } - std::string GetName() const override { - return name; + virtual void Destroy() override; + static void PostDestroy([[maybe_unused]] uintptr_t arg) {} + + constexpr KSession* GetParent() const { + return parent; } + ResultCode SendSyncRequest(KThread* thread, Core::Memory::Memory& memory, + Core::Timing::CoreTiming& core_timing); + + void OnServerClosed(); + + // DEPRECATED + static constexpr HandleType HANDLE_TYPE = HandleType::ClientSession; HandleType GetHandleType() const override { return HANDLE_TYPE; } - ResultCode SendSyncRequest(KThread* thread, Core::Memory::Memory& memory, - Core::Timing::CoreTiming& core_timing); - - bool IsSignaled() const override; + std::string GetTypeName() const override { + return "ClientSession"; + } - void Finalize() override {} + std::string GetName() const override { + return name; + } private: - static ResultVal<std::shared_ptr<ClientSession>> Create(KernelCore& kernel, - std::shared_ptr<Session> parent, - std::string name = "Unknown"); - /// The parent session, which links to the server endpoint. - std::shared_ptr<Session> parent; + KSession* parent{}; /// Name of the client session (optional) std::string name; diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index bb247959c..8cd2c283c 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp @@ -11,43 +11,38 @@ #include "core/core_timing.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/client_port.h" -#include "core/hle/kernel/client_session.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/k_scheduler.h" +#include "core/hle/kernel/k_server_session.h" +#include "core/hle/kernel/k_session.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" -#include "core/hle/kernel/server_session.h" -#include "core/hle/kernel/session.h" #include "core/memory.h" namespace Kernel { -ServerSession::ServerSession(KernelCore& kernel) : KSynchronizationObject{kernel} {} +KServerSession::KServerSession(KernelCore& kernel) : KSynchronizationObject{kernel} {} -ServerSession::~ServerSession() { +KServerSession::~KServerSession() { kernel.ReleaseServiceThread(service_thread); } -ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel, - std::shared_ptr<Session> parent, - std::string name) { - std::shared_ptr<ServerSession> session{std::make_shared<ServerSession>(kernel)}; - - session->name = std::move(name); - session->parent = std::move(parent); - session->service_thread = kernel.CreateServiceThread(session->name); - - return MakeResult(std::move(session)); +void KServerSession::Initialize(KSession* parent_, std::string&& name_) { + // Set member variables. + parent = parent_; + name = std::move(name_); + service_thread = kernel.CreateServiceThread(name); } -bool ServerSession::IsSignaled() const { - // Closed sessions should never wait, an error will be returned from svcReplyAndReceive. - return !parent->Client(); +void KServerSession::Destroy() { + parent->OnServerClosed(); + + parent->Close(); } -void ServerSession::ClientDisconnected() { +void KServerSession::OnClientClosed() { // We keep a shared pointer to the hle handler to keep it alive throughout // the call to ClientDisconnected, as ClientDisconnected invalidates the // hle_handler member itself during the course of the function executing. @@ -55,19 +50,31 @@ void ServerSession::ClientDisconnected() { if (handler) { // Note that after this returns, this server session's hle_handler is // invalidated (set to null). - handler->ClientDisconnected(SharedFrom(this)); + handler->ClientDisconnected(parent); + } +} + +bool KServerSession::IsSignaled() const { + ASSERT(kernel.GlobalSchedulerContext().IsLocked()); + + // If the client is closed, we're always signaled. + if (parent->IsClientClosed()) { + return true; } + + // Otherwise, we're signaled if we have a request and aren't handling one. + return false; } -void ServerSession::AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler) { +void KServerSession::AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler) { domain_request_handlers.push_back(std::move(handler)); } -std::size_t ServerSession::NumDomainRequestHandlers() const { +std::size_t KServerSession::NumDomainRequestHandlers() const { return domain_request_handlers.size(); } -ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) { +ResultCode KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) { if (!context.HasDomainMessageHeader()) { return RESULT_SUCCESS; } @@ -106,21 +113,21 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con return RESULT_SUCCESS; } -ResultCode ServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory) { +ResultCode 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, SharedFrom(this), thread); + auto context = std::make_shared<HLERequestContext>(kernel, memory, this, thread); context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); if (auto strong_ptr = service_thread.lock()) { - strong_ptr->QueueSyncRequest(*this, std::move(context)); + strong_ptr->QueueSyncRequest(*parent, std::move(context)); return RESULT_SUCCESS; } return RESULT_SUCCESS; } -ResultCode ServerSession::CompleteSyncRequest(HLERequestContext& context) { +ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) { ResultCode result = RESULT_SUCCESS; // If the session has been converted to a domain, handle the domain request if (IsDomain() && context.HasDomainMessageHeader()) { @@ -149,8 +156,8 @@ ResultCode ServerSession::CompleteSyncRequest(HLERequestContext& context) { return result; } -ResultCode ServerSession::HandleSyncRequest(KThread* thread, Core::Memory::Memory& memory, - Core::Timing::CoreTiming& core_timing) { +ResultCode KServerSession::HandleSyncRequest(KThread* thread, Core::Memory::Memory& memory, + Core::Timing::CoreTiming& core_timing) { return QueueSyncRequest(thread, memory); } diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/k_server_session.h index 77ed18c60..ef81c4e30 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/k_server_session.h @@ -27,55 +27,34 @@ namespace Kernel { class HLERequestContext; class KernelCore; -class Session; +class KSession; class SessionRequestHandler; class KThread; -/** - * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS - * primitive for communication between different processes, and are used to implement service calls - * to the various system services. - * - * To make a service call, the client must write the command header and parameters to the buffer - * located at offset 0x80 of the TLS (Thread-Local Storage) area, then execute a SendSyncRequest - * SVC call with its ClientSession handle. The kernel will read the command header, using it to - * marshall the parameters to the process at the server endpoint of the session. - * After the server replies to the request, the response is marshalled back to the caller's - * TLS buffer and control is transferred back to it. - */ -class ServerSession final : public KSynchronizationObject { +class KServerSession final : public KSynchronizationObject { + KERNEL_AUTOOBJECT_TRAITS(KServerSession, KSynchronizationObject); + friend class ServiceThread; public: - explicit ServerSession(KernelCore& kernel); - ~ServerSession() override; + explicit KServerSession(KernelCore& kernel); + virtual ~KServerSession() override; - friend class Session; + virtual void Destroy() override; - static ResultVal<std::shared_ptr<ServerSession>> Create(KernelCore& kernel, - std::shared_ptr<Session> parent, - std::string name = "Unknown"); + void Initialize(KSession* parent_, std::string&& name_); - std::string GetTypeName() const override { - return "ServerSession"; - } - - std::string GetName() const override { - return name; + constexpr KSession* GetParent() { + return parent; } - static constexpr HandleType HANDLE_TYPE = HandleType::ServerSession; - HandleType GetHandleType() const override { - return HANDLE_TYPE; + constexpr const KSession* GetParent() const { + return parent; } - Session* GetParent() { - return parent.get(); - } + virtual bool IsSignaled() const override; - const Session* GetParent() const { - return parent.get(); - } + void OnClientClosed(); /** * Sets the HLE handler for the session. This handler will be called to service IPC requests @@ -98,9 +77,6 @@ public: ResultCode HandleSyncRequest(KThread* thread, Core::Memory::Memory& memory, Core::Timing::CoreTiming& core_timing); - /// Called when a client disconnection occurs. - void ClientDisconnected(); - /// Adds a new domain request handler to the collection of request handlers within /// this ServerSession instance. void AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler); @@ -124,9 +100,20 @@ public: convert_to_domain = true; } - bool IsSignaled() const override; + // DEPRECATED - void Finalize() override {} + std::string GetTypeName() const override { + return "ServerSession"; + } + + std::string GetName() const override { + return name; + } + + static constexpr HandleType HANDLE_TYPE = HandleType::ServerSession; + HandleType GetHandleType() const override { + return HANDLE_TYPE; + } private: /// Queues a sync request from the emulated application. @@ -139,9 +126,6 @@ private: /// object handle. ResultCode HandleDomainSyncRequest(Kernel::HLERequestContext& context); - /// The parent session, which links to the client endpoint. - std::shared_ptr<Session> parent; - /// This session's HLE request handler (applicable when not a domain) std::shared_ptr<SessionRequestHandler> hle_handler; @@ -156,6 +140,9 @@ private: /// Thread to dispatch service requests std::weak_ptr<ServiceThread> service_thread; + + /// KSession that owns this KServerSession + KSession* parent{}; }; } // namespace Kernel diff --git a/src/core/hle/kernel/k_session.cpp b/src/core/hle/kernel/k_session.cpp new file mode 100644 index 000000000..ca1cf18cd --- /dev/null +++ b/src/core/hle/kernel/k_session.cpp @@ -0,0 +1,67 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" +#include "core/hle/kernel/k_client_session.h" +#include "core/hle/kernel/k_scoped_resource_reservation.h" +#include "core/hle/kernel/k_server_session.h" +#include "core/hle/kernel/k_session.h" + +namespace Kernel { + +KSession::KSession(KernelCore& kernel) + : KAutoObjectWithSlabHeapAndContainer{kernel}, server{kernel}, client{kernel} {} +KSession::~KSession() = default; + +void KSession::Initialize(std::string&& name_) { + // 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 + // this object will be destroyed. + Open(); + + // Create our sub sessions. + KAutoObject::Create(std::addressof(server)); + KAutoObject::Create(std::addressof(client)); + + // Initialize our sub sessions. + server.Initialize(this, name_ + ":Server"); + client.Initialize(this, name_ + ":Client"); + + // Set state and name. + SetState(State::Normal); + name = std::move(name_); + + // Set our owner process. + process = kernel.CurrentProcess(); + process->Open(); + + // Mark initialized. + initialized = true; +} + +void KSession::Finalize() {} + +void KSession::OnServerClosed() { + if (GetState() == State::Normal) { + SetState(State::ServerClosed); + client.OnServerClosed(); + } +} + +void KSession::OnClientClosed() { + if (GetState() == State::Normal) { + SetState(State::ClientClosed); + server.OnClientClosed(); + } +} + +void KSession::PostDestroy(uintptr_t arg) { + // Release the session count resource the owner process holds. + Process* owner = reinterpret_cast<Process*>(arg); + owner->GetResourceLimit()->Release(LimitableResource::Sessions, 1); + owner->Close(); +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_session.h b/src/core/hle/kernel/k_session.h new file mode 100644 index 000000000..1d24e80cd --- /dev/null +++ b/src/core/hle/kernel/k_session.h @@ -0,0 +1,108 @@ +// Copyright 2021 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <atomic> +#include <string> + +#include "core/hle/kernel/k_client_session.h" +#include "core/hle/kernel/k_server_session.h" +#include "core/hle/kernel/slab_helpers.h" + +namespace Kernel { + +class KSession final : public KAutoObjectWithSlabHeapAndContainer<KSession, KAutoObjectWithList> { + KERNEL_AUTOOBJECT_TRAITS(KSession, KAutoObject); + +private: + enum class State : u8 { + Invalid = 0, + Normal = 1, + ClientClosed = 2, + ServerClosed = 3, + }; + +public: + explicit KSession(KernelCore& kernel); + virtual ~KSession() override; + + void Initialize(std::string&& name_); + + virtual void Finalize() override; + + virtual bool IsInitialized() const override { + return initialized; + } + + virtual uintptr_t GetPostDestroyArgument() const override { + return reinterpret_cast<uintptr_t>(process); + } + + static void PostDestroy(uintptr_t arg); + + void OnServerClosed(); + + void OnClientClosed(); + + bool IsServerClosed() const { + return this->GetState() != State::Normal; + } + + bool IsClientClosed() const { + return this->GetState() != State::Normal; + } + + KClientSession& GetClientSession() { + return client; + } + + KServerSession& GetServerSession() { + return server; + } + + const KClientSession& GetClientSession() const { + return client; + } + + const KServerSession& GetServerSession() const { + return server; + } + + const ClientPort* GetParent() const { + return port; + } + + // DEPRECATED + + std::string GetName() const override { + return name; + } + + static constexpr HandleType HANDLE_TYPE = HandleType::Session; + HandleType GetHandleType() const override { + return HANDLE_TYPE; + } + +private: + void SetState(State state) { + atomic_state = static_cast<u8>(state); + } + + State GetState() const { + return static_cast<State>(atomic_state.load()); + } + +private: + KServerSession server; + KClientSession client; + std::atomic<std::underlying_type<State>::type> atomic_state{ + static_cast<std::underlying_type<State>::type>(State::Invalid)}; + ClientPort* port{}; + std::string name; + Process* process{}; + bool initialized{}; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 850436eb3..ecced1034 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -33,11 +33,13 @@ class ClientPort; class GlobalSchedulerContext; class HandleTable; class KAutoObjectWithListContainer; +class KClientSession; class KEvent; class KLinkedListNode; class KMemoryManager; class KResourceLimit; class KScheduler; +class KSession; class KSharedMemory; class KThread; class KWritableEvent; @@ -272,6 +274,10 @@ public: return slab_heap_container->linked_list_node; } else if constexpr (std::is_same_v<T, KWritableEvent>) { return slab_heap_container->writeable_event; + } else if constexpr (std::is_same_v<T, KClientSession>) { + return slab_heap_container->client_session; + } else if constexpr (std::is_same_v<T, KSession>) { + return slab_heap_container->session; } } @@ -312,6 +318,8 @@ private: KSlabHeap<KSharedMemory> shared_memory; KSlabHeap<KLinkedListNode> linked_list_node; KSlabHeap<KWritableEvent> writeable_event; + KSlabHeap<KClientSession> client_session; + KSlabHeap<KSession> session; }; std::unique_ptr<SlabHeapContainer> slab_heap_container; diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp index 5d17346ad..8626b56fd 100644 --- a/src/core/hle/kernel/server_port.cpp +++ b/src/core/hle/kernel/server_port.cpp @@ -5,10 +5,10 @@ #include <tuple> #include "common/assert.h" #include "core/hle/kernel/client_port.h" +#include "core/hle/kernel/k_server_session.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/server_port.h" -#include "core/hle/kernel/server_session.h" #include "core/hle/kernel/svc_results.h" namespace Kernel { @@ -16,17 +16,17 @@ namespace Kernel { ServerPort::ServerPort(KernelCore& kernel) : KSynchronizationObject{kernel} {} ServerPort::~ServerPort() = default; -ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() { +ResultVal<KServerSession*> ServerPort::Accept() { if (pending_sessions.empty()) { return ResultNotFound; } - auto session = std::move(pending_sessions.back()); + auto* session = pending_sessions.back(); pending_sessions.pop_back(); - return MakeResult(std::move(session)); + return MakeResult(session); } -void ServerPort::AppendPendingSession(std::shared_ptr<ServerSession> pending_session) { +void ServerPort::AppendPendingSession(KServerSession* pending_session) { pending_sessions.push_back(std::move(pending_session)); if (pending_sessions.size() == 1) { NotifyAvailable(); diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h index 29b4f2509..eebceaa2a 100644 --- a/src/core/hle/kernel/server_port.h +++ b/src/core/hle/kernel/server_port.h @@ -17,7 +17,7 @@ namespace Kernel { class ClientPort; class KernelCore; -class ServerSession; +class KServerSession; class SessionRequestHandler; class ServerPort final : public KSynchronizationObject { @@ -55,7 +55,7 @@ public: * Accepts a pending incoming connection on this port. If there are no pending sessions, will * return ERR_NO_PENDING_SESSIONS. */ - ResultVal<std::shared_ptr<ServerSession>> Accept(); + ResultVal<KServerSession*> Accept(); /// Whether or not this server port has an HLE handler available. bool HasHLEHandler() const { @@ -77,7 +77,7 @@ public: /// Appends a ServerSession to the collection of ServerSessions /// waiting to be accepted by this port. - void AppendPendingSession(std::shared_ptr<ServerSession> pending_session); + void AppendPendingSession(KServerSession* pending_session); bool IsSignaled() const override; @@ -85,7 +85,7 @@ public: private: /// ServerSessions waiting to be accepted by the port - std::vector<std::shared_ptr<ServerSession>> pending_sessions; + std::vector<KServerSession*> pending_sessions; /// This session's HLE request handler template (optional) /// ServerSessions created from this port inherit a reference to this handler. diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp index ee46f3e21..04be8a502 100644 --- a/src/core/hle/kernel/service_thread.cpp +++ b/src/core/hle/kernel/service_thread.cpp @@ -13,8 +13,8 @@ #include "common/scope_exit.h" #include "common/thread.h" #include "core/core.h" +#include "core/hle/kernel/k_session.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/server_session.h" #include "core/hle/kernel/service_thread.h" #include "core/hle/lock.h" #include "video_core/renderer_base.h" @@ -26,7 +26,7 @@ public: explicit Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name); ~Impl(); - void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context); + void QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context); private: std::vector<std::thread> threads; @@ -69,18 +69,27 @@ ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std }); } -void ServiceThread::Impl::QueueSyncRequest(ServerSession& session, +void ServiceThread::Impl::QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context) { { std::unique_lock lock{queue_mutex}; - // ServerSession owns the service thread, so we cannot caption a strong pointer here in the - // event that the ServerSession is terminated. - std::weak_ptr<ServerSession> weak_ptr{SharedFrom(&session)}; - requests.emplace([weak_ptr, context{std::move(context)}]() { - if (auto strong_ptr = weak_ptr.lock()) { - strong_ptr->CompleteSyncRequest(*context); + // Open a reference to the session to ensure it is not closes while the service request + // completes asynchronously. + session.Open(); + + requests.emplace([session_ptr{&session}, context{std::move(context)}]() { + // Close the reference. + SCOPE_EXIT({ session_ptr->Close(); }); + + // If the session has been closed, we are done. + if (session_ptr->IsServerClosed()) { + return; } + + // Complete the service request. + KScopedAutoObject server_session{&session_ptr->GetServerSession()}; + server_session->CompleteSyncRequest(*context); }); } condition.notify_one(); @@ -102,7 +111,7 @@ ServiceThread::ServiceThread(KernelCore& kernel, std::size_t num_threads, const ServiceThread::~ServiceThread() = default; -void ServiceThread::QueueSyncRequest(ServerSession& session, +void ServiceThread::QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context) { impl->QueueSyncRequest(session, std::move(context)); } diff --git a/src/core/hle/kernel/service_thread.h b/src/core/hle/kernel/service_thread.h index 025ab8fb5..6a7fd7c56 100644 --- a/src/core/hle/kernel/service_thread.h +++ b/src/core/hle/kernel/service_thread.h @@ -11,14 +11,14 @@ namespace Kernel { class HLERequestContext; class KernelCore; -class ServerSession; +class KSession; class ServiceThread final { public: explicit ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name); ~ServiceThread(); - void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context); + void QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context); private: class Impl; diff --git a/src/core/hle/kernel/session.cpp b/src/core/hle/kernel/session.cpp deleted file mode 100644 index 8830d4e91..000000000 --- a/src/core/hle/kernel/session.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2019 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/assert.h" -#include "core/hle/kernel/client_session.h" -#include "core/hle/kernel/k_scoped_resource_reservation.h" -#include "core/hle/kernel/server_session.h" -#include "core/hle/kernel/session.h" - -namespace Kernel { - -Session::Session(KernelCore& kernel) : KSynchronizationObject{kernel} {} -Session::~Session() { - // Release reserved resource when the Session pair was created. - kernel.GetSystemResourceLimit()->Release(LimitableResource::Sessions, 1); -} - -Session::SessionPair Session::Create(KernelCore& kernel, std::string name) { - // Reserve a new session from the resource limit. - KScopedResourceReservation session_reservation(kernel.GetSystemResourceLimit(), - LimitableResource::Sessions); - ASSERT(session_reservation.Succeeded()); - auto session{std::make_shared<Session>(kernel)}; - auto client_session{Kernel::ClientSession::Create(kernel, session, name + "_Client").Unwrap()}; - auto server_session{Kernel::ServerSession::Create(kernel, session, name + "_Server").Unwrap()}; - - session->name = std::move(name); - session->client = client_session; - session->server = server_session; - - session_reservation.Commit(); - return std::make_pair(std::move(client_session), std::move(server_session)); -} - -bool Session::IsSignaled() const { - UNIMPLEMENTED(); - return true; -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h deleted file mode 100644 index fa3c5651a..000000000 --- a/src/core/hle/kernel/session.h +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2019 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <memory> -#include <string> -#include <utility> - -#include "core/hle/kernel/k_synchronization_object.h" - -namespace Kernel { - -class ClientSession; -class ServerSession; - -/** - * Parent structure to link the client and server endpoints of a session with their associated - * client port. - */ -class Session final : public KSynchronizationObject { -public: - explicit Session(KernelCore& kernel); - ~Session() override; - - using SessionPair = std::pair<std::shared_ptr<ClientSession>, std::shared_ptr<ServerSession>>; - - static SessionPair Create(KernelCore& kernel, std::string name = "Unknown"); - - std::string GetName() const override { - return name; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::Session; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - - bool IsSignaled() const override; - - void Finalize() override {} - - std::shared_ptr<ClientSession> Client() { - if (auto result{client.lock()}) { - return result; - } - return {}; - } - - std::shared_ptr<ServerSession> Server() { - if (auto result{server.lock()}) { - return result; - } - return {}; - } - -private: - std::string name; - std::weak_ptr<ClientSession> client; - std::weak_ptr<ServerSession> server; -}; - -} // namespace Kernel diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index b83ee3e69..28c45e8a3 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -22,9 +22,9 @@ #include "core/core_timing_util.h" #include "core/cpu_manager.h" #include "core/hle/kernel/client_port.h" -#include "core/hle/kernel/client_session.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/k_address_arbiter.h" +#include "core/hle/kernel/k_client_session.h" #include "core/hle/kernel/k_condition_variable.h" #include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_memory_block.h" @@ -323,12 +323,12 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, auto client_port = it->second; - std::shared_ptr<ClientSession> client_session; + KClientSession* client_session{}; CASCADE_RESULT(client_session, client_port->Connect()); // Return the client session auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); - CASCADE_RESULT(*out_handle, handle_table.Create(client_session.get())); + CASCADE_RESULT(*out_handle, handle_table.Create(client_session)); return RESULT_SUCCESS; } @@ -340,15 +340,13 @@ static ResultCode ConnectToNamedPort32(Core::System& system, Handle* out_handle, /// Makes a blocking IPC call to an OS service. static ResultCode SendSyncRequest(Core::System& system, Handle handle) { + LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); + auto& kernel = system.Kernel(); - const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); - auto session = handle_table.Get<ClientSession>(handle); - if (!session) { - LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle); - return ResultInvalidHandle; - } - LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); + KScopedAutoObject session = + kernel.CurrentProcess()->GetHandleTable().GetObject<KClientSession>(handle); + R_UNLESS(session.IsNotNull(), ResultInvalidHandle); auto thread = kernel.CurrentScheduler()->GetCurrentThread(); { |