mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-10-30 15:39:02 -05:00 
			
		
		
		
	kernel: Implement a more accurate IPC dispatch.
This commit is contained in:
		| @@ -9,6 +9,7 @@ | ||||
| #include "core/hle/kernel/object.h" | ||||
| #include "core/hle/kernel/server_port.h" | ||||
| #include "core/hle/kernel/server_session.h" | ||||
| #include "core/hle/kernel/session.h" | ||||
|  | ||||
| namespace Kernel { | ||||
|  | ||||
| @@ -20,28 +21,23 @@ std::shared_ptr<ServerPort> ClientPort::GetServerPort() const { | ||||
| } | ||||
|  | ||||
| ResultVal<std::shared_ptr<ClientSession>> ClientPort::Connect() { | ||||
|     // Note: Threads do not wait for the server endpoint to call | ||||
|     // AcceptSession before returning from this call. | ||||
|  | ||||
|     if (active_sessions >= max_sessions) { | ||||
|         return ERR_MAX_CONNECTIONS_REACHED; | ||||
|     } | ||||
|     active_sessions++; | ||||
|  | ||||
|     // Create a new session pair, let the created sessions inherit the parent port's HLE handler. | ||||
|     auto [server, client] = | ||||
|         ServerSession::CreateSessionPair(kernel, server_port->GetName(), SharedFrom(this)); | ||||
|     auto [client, server] = Kernel::Session::Create(kernel, name); | ||||
|  | ||||
|     if (server_port->HasHLEHandler()) { | ||||
|         server_port->GetHLEHandler()->ClientConnected(server); | ||||
|         server_port->GetHLEHandler()->ClientConnected(std::move(server)); | ||||
|     } else { | ||||
|         server_port->AppendPendingSession(server); | ||||
|         server_port->AppendPendingSession(std::move(server)); | ||||
|     } | ||||
|  | ||||
|     // Wake the threads waiting on the ServerPort | ||||
|     server_port->WakeupAllWaitingThreads(); | ||||
|  | ||||
|     return MakeResult(client); | ||||
|     return MakeResult(std::move(client)); | ||||
| } | ||||
|  | ||||
| void ClientPort::ConnectionClosed() { | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| // Copyright 2016 Citra Emulator Project | ||||
| // Copyright 2019 yuzu emulator team | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| @@ -12,22 +12,44 @@ | ||||
|  | ||||
| namespace Kernel { | ||||
|  | ||||
| ClientSession::ClientSession(KernelCore& kernel) : Object{kernel} {} | ||||
| ClientSession::ClientSession(KernelCore& kernel) : WaitObject{kernel} {} | ||||
|  | ||||
| ClientSession::~ClientSession() { | ||||
|     // This destructor will be called automatically when the last ClientSession handle is closed by | ||||
|     // the emulated application. | ||||
|     if (auto server = parent->server.lock()) { | ||||
|         server->ClientDisconnected(); | ||||
|     if (parent->Server()) { | ||||
|         parent->Server()->ClientDisconnected(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| ResultCode ClientSession::SendSyncRequest(Thread* thread, Memory::Memory& memory) { | ||||
|     // Signal the server session that new data is available | ||||
|     if (auto server = parent->server.lock()) { | ||||
|         return server->HandleSyncRequest(SharedFrom(thread), memory); | ||||
| bool ClientSession::ShouldWait(const Thread* thread) const { | ||||
|     UNIMPLEMENTED(); | ||||
|     return {}; | ||||
| } | ||||
|  | ||||
| void ClientSession::Acquire(Thread* thread) { | ||||
|     UNIMPLEMENTED(); | ||||
| } | ||||
|  | ||||
| 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(std::shared_ptr<Thread> thread, Memory::Memory& memory) { | ||||
|     // Keep ServerSession alive until we're done working with it. | ||||
|     if (!parent->Server()) { | ||||
|         return ERR_SESSION_CLOSED_BY_REMOTE; | ||||
|     } | ||||
|  | ||||
|     return ERR_SESSION_CLOSED_BY_REMOTE; | ||||
|     // Signal the server session that new data is available | ||||
|     return parent->Server()->HandleSyncRequest(std::move(thread), memory); | ||||
| } | ||||
|  | ||||
| } // namespace Kernel | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| // Copyright 2016 Citra Emulator Project | ||||
| // Copyright 2019 yuzu emulator team | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| @@ -6,7 +6,9 @@ | ||||
|  | ||||
| #include <memory> | ||||
| #include <string> | ||||
| #include "core/hle/kernel/object.h" | ||||
|  | ||||
| #include "core/hle/kernel/wait_object.h" | ||||
| #include "core/hle/result.h" | ||||
|  | ||||
| union ResultCode; | ||||
|  | ||||
| @@ -18,15 +20,14 @@ namespace Kernel { | ||||
|  | ||||
| class KernelCore; | ||||
| class Session; | ||||
| class ServerSession; | ||||
| class Thread; | ||||
|  | ||||
| class ClientSession final : public Object { | ||||
| class ClientSession final : public WaitObject { | ||||
| public: | ||||
|     explicit ClientSession(KernelCore& kernel); | ||||
|     ~ClientSession() override; | ||||
|  | ||||
|     friend class ServerSession; | ||||
|     friend class Session; | ||||
|  | ||||
|     std::string GetTypeName() const override { | ||||
|         return "ClientSession"; | ||||
| @@ -41,9 +42,17 @@ public: | ||||
|         return HANDLE_TYPE; | ||||
|     } | ||||
|  | ||||
|     ResultCode SendSyncRequest(Thread* thread, Memory::Memory& memory); | ||||
|     ResultCode SendSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory); | ||||
|  | ||||
|     bool ShouldWait(const Thread* thread) const override; | ||||
|  | ||||
|     void Acquire(Thread* thread) override; | ||||
|  | ||||
| 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; | ||||
|  | ||||
|   | ||||
| @@ -74,6 +74,8 @@ std::shared_ptr<WritableEvent> HLERequestContext::SleepClientThread( | ||||
|         thread->WakeAfterDelay(timeout); | ||||
|     } | ||||
|  | ||||
|     is_thread_waiting = true; | ||||
|  | ||||
|     return writable_event; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -264,6 +264,18 @@ public: | ||||
|  | ||||
|     std::string Description() const; | ||||
|  | ||||
|     Thread& GetThread() { | ||||
|         return *thread; | ||||
|     } | ||||
|  | ||||
|     const Thread& GetThread() const { | ||||
|         return *thread; | ||||
|     } | ||||
|  | ||||
|     bool IsThreadWaiting() const { | ||||
|         return is_thread_waiting; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming); | ||||
|  | ||||
| @@ -290,6 +302,7 @@ private: | ||||
|     u32_le command{}; | ||||
|  | ||||
|     std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers; | ||||
|     bool is_thread_waiting{}; | ||||
| }; | ||||
|  | ||||
| } // namespace Kernel | ||||
|   | ||||
| @@ -27,6 +27,7 @@ bool Object::IsWaitable() const { | ||||
|     case HandleType::ResourceLimit: | ||||
|     case HandleType::ClientPort: | ||||
|     case HandleType::ClientSession: | ||||
|     case HandleType::Session: | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -29,6 +29,7 @@ enum class HandleType : u32 { | ||||
|     ServerPort, | ||||
|     ClientSession, | ||||
|     ServerSession, | ||||
|     Session, | ||||
| }; | ||||
|  | ||||
| class Object : NonCopyable, public std::enable_shared_from_this<Object> { | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| // Copyright 2016 Citra Emulator Project | ||||
| // Copyright 2019 yuzu emulator team | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| @@ -9,6 +9,7 @@ | ||||
| #include "common/common_types.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "core/core.h" | ||||
| #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" | ||||
| @@ -24,34 +25,29 @@ | ||||
| namespace Kernel { | ||||
|  | ||||
| ServerSession::ServerSession(KernelCore& kernel) : WaitObject{kernel} {} | ||||
| ServerSession::~ServerSession() { | ||||
|     // This destructor will be called automatically when the last ServerSession handle is closed by | ||||
|     // the emulated application. | ||||
|  | ||||
|     // Decrease the port's connection count. | ||||
|     if (parent->port) { | ||||
|         parent->port->ConnectionClosed(); | ||||
|     } | ||||
| } | ||||
| ServerSession::~ServerSession() = default; | ||||
|  | ||||
| ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel, | ||||
|                                                                 std::shared_ptr<Session> parent, | ||||
|                                                                 std::string name) { | ||||
|     std::shared_ptr<ServerSession> server_session = std::make_shared<ServerSession>(kernel); | ||||
|     std::shared_ptr<ServerSession> session{std::make_shared<ServerSession>(kernel)}; | ||||
|  | ||||
|     server_session->name = std::move(name); | ||||
|     server_session->parent = nullptr; | ||||
|     session->request_event = Core::Timing::CreateEvent( | ||||
|         name, [session](u64 userdata, s64 cycles_late) { session->CompleteSyncRequest(); }); | ||||
|     session->name = std::move(name); | ||||
|     session->parent = std::move(parent); | ||||
|  | ||||
|     return MakeResult(std::move(server_session)); | ||||
|     return MakeResult(std::move(session)); | ||||
| } | ||||
|  | ||||
| bool ServerSession::ShouldWait(const Thread* thread) const { | ||||
|     // Wait if we have no pending requests, or if we're currently handling a request. | ||||
|     if (auto client = parent->client.lock()) { | ||||
|         return pending_requesting_threads.empty() || currently_handling != nullptr; | ||||
|     // Closed sessions should never wait, an error will be returned from svcReplyAndReceive. | ||||
|     if (!parent->Client()) { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     // Closed sessions should never wait, an error will be returned from svcReplyAndReceive. | ||||
|     return {}; | ||||
|     // Wait if we have no pending requests, or if we're currently handling a request. | ||||
|     return pending_requesting_threads.empty() || currently_handling != nullptr; | ||||
| } | ||||
|  | ||||
| void ServerSession::Acquire(Thread* thread) { | ||||
| @@ -128,14 +124,21 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con | ||||
|     return RESULT_SUCCESS; | ||||
| } | ||||
|  | ||||
| ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread, | ||||
|                                             Memory::Memory& memory) { | ||||
|     // The ServerSession received a sync request, this means that there's new data available | ||||
|     // from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or | ||||
|     // similar. | ||||
|     Kernel::HLERequestContext context(SharedFrom(this), thread); | ||||
|     u32* cmd_buf = (u32*)memory.GetPointer(thread->GetTLSAddress()); | ||||
|     context.PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); | ||||
| ResultCode ServerSession::QueueSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory) { | ||||
|     u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(thread->GetTLSAddress()))}; | ||||
|     std::shared_ptr<Kernel::HLERequestContext> context{ | ||||
|         std::make_shared<Kernel::HLERequestContext>(SharedFrom(this), std::move(thread))}; | ||||
|  | ||||
|     context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); | ||||
|     request_queue.Push(std::move(context)); | ||||
|  | ||||
|     return RESULT_SUCCESS; | ||||
| } | ||||
|  | ||||
| ResultCode ServerSession::CompleteSyncRequest() { | ||||
|     ASSERT(!request_queue.Empty()); | ||||
|  | ||||
|     auto& context = *request_queue.Front(); | ||||
|  | ||||
|     ResultCode result = RESULT_SUCCESS; | ||||
|     // If the session has been converted to a domain, handle the domain request | ||||
| @@ -147,61 +150,27 @@ ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread, | ||||
|         result = hle_handler->HandleSyncRequest(context); | ||||
|     } | ||||
|  | ||||
|     if (thread->GetStatus() == ThreadStatus::Running) { | ||||
|         // Put the thread to sleep until the server replies, it will be awoken in | ||||
|         // svcReplyAndReceive for LLE servers. | ||||
|         thread->SetStatus(ThreadStatus::WaitIPC); | ||||
|  | ||||
|         if (hle_handler != nullptr) { | ||||
|             // For HLE services, we put the request threads to sleep for a short duration to | ||||
|             // simulate IPC overhead, but only if the HLE handler didn't put the thread to sleep for | ||||
|             // other reasons like an async callback. The IPC overhead is needed to prevent | ||||
|             // starvation when a thread only does sync requests to HLE services while a | ||||
|             // lower-priority thread is waiting to run. | ||||
|  | ||||
|             // This delay was approximated in a homebrew application by measuring the average time | ||||
|             // it takes for svcSendSyncRequest to return when performing the SetLcdForceBlack IPC | ||||
|             // request to the GSP:GPU service in a n3DS with firmware 11.6. The measured values have | ||||
|             // a high variance and vary between models. | ||||
|             static constexpr u64 IPCDelayNanoseconds = 39000; | ||||
|             thread->WakeAfterDelay(IPCDelayNanoseconds); | ||||
|         } else { | ||||
|             // Add the thread to the list of threads that have issued a sync request with this | ||||
|             // server. | ||||
|             pending_requesting_threads.push_back(std::move(thread)); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // If this ServerSession does not have an HLE implementation, just wake up the threads waiting | ||||
|     // on it. | ||||
|     WakeupAllWaitingThreads(); | ||||
|  | ||||
|     // Handle scenario when ConvertToDomain command was issued, as we must do the conversion at the | ||||
|     // end of the command such that only commands following this one are handled as domains | ||||
|     if (convert_to_domain) { | ||||
|         ASSERT_MSG(IsSession(), "ServerSession is already a domain instance."); | ||||
|         domain_request_handlers = {hle_handler}; | ||||
|         convert_to_domain = false; | ||||
|     } | ||||
|  | ||||
|     // Some service requests require the thread to block | ||||
|     if (!context.IsThreadWaiting()) { | ||||
|         context.GetThread().ResumeFromWait(); | ||||
|         context.GetThread().SetWaitSynchronizationResult(result); | ||||
|     } | ||||
|  | ||||
|     request_queue.Pop(); | ||||
|  | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| ServerSession::SessionPair ServerSession::CreateSessionPair(KernelCore& kernel, | ||||
|                                                             const std::string& name, | ||||
|                                                             std::shared_ptr<ClientPort> port) { | ||||
|     auto server_session = ServerSession::Create(kernel, name + "_Server").Unwrap(); | ||||
|     std::shared_ptr<ClientSession> client_session = std::make_shared<ClientSession>(kernel); | ||||
|     client_session->name = name + "_Client"; | ||||
|  | ||||
|     std::shared_ptr<Session> parent = std::make_shared<Session>(); | ||||
|     parent->client = client_session; | ||||
|     parent->server = server_session; | ||||
|     parent->port = std::move(port); | ||||
|  | ||||
|     client_session->parent = parent; | ||||
|     server_session->parent = parent; | ||||
|  | ||||
|     return std::make_pair(std::move(server_session), std::move(client_session)); | ||||
| ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread, | ||||
|                                             Memory::Memory& memory) { | ||||
|     Core::System::GetInstance().CoreTiming().ScheduleEvent(20000, request_event, {}); | ||||
|     return QueueSyncRequest(std::move(thread), memory); | ||||
| } | ||||
|  | ||||
| } // namespace Kernel | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| // Copyright 2014 Citra Emulator Project | ||||
| // Copyright 2019 yuzu emulator team | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| @@ -9,7 +9,7 @@ | ||||
| #include <utility> | ||||
| #include <vector> | ||||
|  | ||||
| #include "core/hle/kernel/object.h" | ||||
| #include "common/threadsafe_queue.h" | ||||
| #include "core/hle/kernel/wait_object.h" | ||||
| #include "core/hle/result.h" | ||||
|  | ||||
| @@ -17,13 +17,14 @@ namespace Memory { | ||||
| class Memory; | ||||
| } | ||||
|  | ||||
| namespace Core::Timing { | ||||
| struct EventType; | ||||
| } | ||||
|  | ||||
| namespace Kernel { | ||||
|  | ||||
| class ClientPort; | ||||
| class ClientSession; | ||||
| class HLERequestContext; | ||||
| class KernelCore; | ||||
| class ServerSession; | ||||
| class Session; | ||||
| class SessionRequestHandler; | ||||
| class Thread; | ||||
| @@ -45,6 +46,12 @@ public: | ||||
|     explicit ServerSession(KernelCore& kernel); | ||||
|     ~ServerSession() override; | ||||
|  | ||||
|     friend class Session; | ||||
|  | ||||
|     static ResultVal<std::shared_ptr<ServerSession>> Create(KernelCore& kernel, | ||||
|                                                             std::shared_ptr<Session> parent, | ||||
|                                                             std::string name = "Unknown"); | ||||
|  | ||||
|     std::string GetTypeName() const override { | ||||
|         return "ServerSession"; | ||||
|     } | ||||
| @@ -66,18 +73,6 @@ public: | ||||
|         return parent.get(); | ||||
|     } | ||||
|  | ||||
|     using SessionPair = std::pair<std::shared_ptr<ServerSession>, std::shared_ptr<ClientSession>>; | ||||
|  | ||||
|     /** | ||||
|      * Creates a pair of ServerSession and an associated ClientSession. | ||||
|      * @param kernel      The kernal instance to create the session pair under. | ||||
|      * @param name        Optional name of the ports. | ||||
|      * @param client_port Optional The ClientPort that spawned this session. | ||||
|      * @return The created session tuple | ||||
|      */ | ||||
|     static SessionPair CreateSessionPair(KernelCore& kernel, const std::string& name = "Unknown", | ||||
|                                          std::shared_ptr<ClientPort> client_port = nullptr); | ||||
|  | ||||
|     /** | ||||
|      * Sets the HLE handler for the session. This handler will be called to service IPC requests | ||||
|      * instead of the regular IPC machinery. (The regular IPC machinery is currently not | ||||
| @@ -128,15 +123,11 @@ public: | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     /** | ||||
|      * Creates a server session. The server session can have an optional HLE handler, | ||||
|      * which will be invoked to handle the IPC requests that this session receives. | ||||
|      * @param kernel The kernel instance to create this server session under. | ||||
|      * @param name Optional name of the server session. | ||||
|      * @return The created server session | ||||
|      */ | ||||
|     static ResultVal<std::shared_ptr<ServerSession>> Create(KernelCore& kernel, | ||||
|                                                             std::string name = "Unknown"); | ||||
|     /// Queues a sync request from the emulated application. | ||||
|     ResultCode QueueSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory); | ||||
|  | ||||
|     /// Completes a sync request from the emulated application. | ||||
|     ResultCode CompleteSyncRequest(); | ||||
|  | ||||
|     /// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an | ||||
|     /// object handle. | ||||
| @@ -166,6 +157,12 @@ private: | ||||
|  | ||||
|     /// The name of this session (optional) | ||||
|     std::string name; | ||||
|  | ||||
|     /// Core timing event used to schedule the service request at some point in the future | ||||
|     std::shared_ptr<Core::Timing::EventType> request_event; | ||||
|  | ||||
|     /// Queue of scheduled service requests | ||||
|     Common::MPSCQueue<std::shared_ptr<Kernel::HLERequestContext>> request_queue; | ||||
| }; | ||||
|  | ||||
| } // namespace Kernel | ||||
|   | ||||
| @@ -1,12 +1,36 @@ | ||||
| // Copyright 2015 Citra Emulator Project | ||||
| // 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/server_session.h" | ||||
| #include "core/hle/kernel/session.h" | ||||
| #include "core/hle/kernel/thread.h" | ||||
|  | ||||
| namespace Kernel { | ||||
|  | ||||
| Session::Session() {} | ||||
| Session::~Session() {} | ||||
| Session::Session(KernelCore& kernel) : WaitObject{kernel} {} | ||||
| Session::~Session() = default; | ||||
|  | ||||
| Session::SessionPair Session::Create(KernelCore& kernel, std::string name) { | ||||
|     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; | ||||
|  | ||||
|     return std::make_pair(std::move(client_session), std::move(server_session)); | ||||
| } | ||||
|  | ||||
| bool Session::ShouldWait(const Thread* thread) const { | ||||
|     UNIMPLEMENTED(); | ||||
|     return {}; | ||||
| } | ||||
|  | ||||
| void Session::Acquire(Thread* thread) { | ||||
|     UNIMPLEMENTED(); | ||||
| } | ||||
|  | ||||
| } // namespace Kernel | ||||
|   | ||||
| @@ -1,27 +1,64 @@ | ||||
| // Copyright 2018 yuzu emulator team | ||||
| // Copyright 2019 yuzu emulator team | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "core/hle/kernel/object.h" | ||||
| #include <memory> | ||||
| #include <string> | ||||
|  | ||||
| #include "core/hle/kernel/wait_object.h" | ||||
| #include "core/hle/result.h" | ||||
|  | ||||
| namespace Kernel { | ||||
|  | ||||
| class ClientSession; | ||||
| class ClientPort; | ||||
| class ServerSession; | ||||
|  | ||||
| /** | ||||
|  * Parent structure to link the client and server endpoints of a session with their associated | ||||
|  * client port. The client port need not exist, as is the case for portless sessions like the | ||||
|  * FS File and Directory sessions. When one of the endpoints of a session is destroyed, its | ||||
|  * corresponding field in this structure will be set to nullptr. | ||||
|  * client port. | ||||
|  */ | ||||
| class Session final { | ||||
| class Session final : public WaitObject { | ||||
| public: | ||||
|     std::weak_ptr<ClientSession> client; ///< The client endpoint of the session. | ||||
|     std::weak_ptr<ServerSession> server; ///< The server endpoint of the session. | ||||
|     std::shared_ptr<ClientPort> port; ///< The port that this session is associated with (optional). | ||||
|     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 ShouldWait(const Thread* thread) const override; | ||||
|  | ||||
|     void Acquire(Thread* thread) 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 | ||||
|   | ||||
| @@ -381,11 +381,12 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { | ||||
|  | ||||
|     LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); | ||||
|  | ||||
|     system.PrepareReschedule(); | ||||
|     auto thread = system.CurrentScheduler().GetCurrentThread(); | ||||
|     thread->InvalidateWakeupCallback(); | ||||
|     thread->SetStatus(ThreadStatus::WaitIPC); | ||||
|     system.PrepareReschedule(thread->GetProcessorID()); | ||||
|  | ||||
|     // TODO(Subv): svcSendSyncRequest should put the caller thread to sleep while the server | ||||
|     // responds and cause a reschedule. | ||||
|     return session->SendSyncRequest(system.CurrentScheduler().GetCurrentThread(), system.Memory()); | ||||
|     return session->SendSyncRequest(SharedFrom(thread), system.Memory()); | ||||
| } | ||||
|  | ||||
| /// Get the ID for the specified thread. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 bunnei
					bunnei