diff options
| author | 2016-06-14 18:03:30 -0500 | |
|---|---|---|
| committer | 2016-11-30 23:02:05 -0500 | |
| commit | 073653e858abf377fd1ebbdb071809c8830ce99d (patch) | |
| tree | a29e1c1e50d53162ed89cd90e8c069525150392f /src/core/hle/kernel | |
| parent | Merge pull request #2228 from freiro/winver_fix (diff) | |
| download | yuzu-073653e858abf377fd1ebbdb071809c8830ce99d.tar.gz yuzu-073653e858abf377fd1ebbdb071809c8830ce99d.tar.xz yuzu-073653e858abf377fd1ebbdb071809c8830ce99d.zip | |
Kernel/IPC: Use Ports and Sessions as the fundamental building block of Inter Process Communication.
All handles obtained via srv::GetServiceHandle or svcConnectToPort are references to ClientSessions.
Service modules will wait on the counterpart of those ClientSessions (Called ServerSessions) using svcReplyAndReceive or svcWaitSynchronization[1|N], and will be awoken when a SyncRequest is performed.
HLE Interfaces are now ClientPorts which override the HandleSyncRequest virtual member function to perform command handling immediately.
Diffstat (limited to 'src/core/hle/kernel')
| -rw-r--r-- | src/core/hle/kernel/client_port.cpp | 7 | ||||
| -rw-r--r-- | src/core/hle/kernel/client_port.h | 23 | ||||
| -rw-r--r-- | src/core/hle/kernel/client_session.cpp | 42 | ||||
| -rw-r--r-- | src/core/hle/kernel/client_session.h | 50 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 36 | ||||
| -rw-r--r-- | src/core/hle/kernel/server_session.cpp | 58 | ||||
| -rw-r--r-- | src/core/hle/kernel/server_session.h (renamed from src/core/hle/kernel/session.h) | 73 |
7 files changed, 233 insertions, 56 deletions
diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index aedc6f989..5ee7679eb 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp | |||
| @@ -6,10 +6,17 @@ | |||
| 6 | #include "core/hle/kernel/client_port.h" | 6 | #include "core/hle/kernel/client_port.h" |
| 7 | #include "core/hle/kernel/kernel.h" | 7 | #include "core/hle/kernel/kernel.h" |
| 8 | #include "core/hle/kernel/server_port.h" | 8 | #include "core/hle/kernel/server_port.h" |
| 9 | #include "core/hle/kernel/server_session.h" | ||
| 9 | 10 | ||
| 10 | namespace Kernel { | 11 | namespace Kernel { |
| 11 | 12 | ||
| 12 | ClientPort::ClientPort() {} | 13 | ClientPort::ClientPort() {} |
| 13 | ClientPort::~ClientPort() {} | 14 | ClientPort::~ClientPort() {} |
| 14 | 15 | ||
| 16 | void ClientPort::AddWaitingSession(SharedPtr<ServerSession> server_session) { | ||
| 17 | server_port->pending_sessions.push_back(server_session); | ||
| 18 | // Wake the threads waiting on the ServerPort | ||
| 19 | server_port->WakeupAllWaitingThreads(); | ||
| 20 | } | ||
| 21 | |||
| 15 | } // namespace | 22 | } // namespace |
diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h index d28147718..eb0882870 100644 --- a/src/core/hle/kernel/client_port.h +++ b/src/core/hle/kernel/client_port.h | |||
| @@ -11,16 +11,27 @@ | |||
| 11 | namespace Kernel { | 11 | namespace Kernel { |
| 12 | 12 | ||
| 13 | class ServerPort; | 13 | class ServerPort; |
| 14 | class ServerSession; | ||
| 14 | 15 | ||
| 15 | class ClientPort : public Object { | 16 | class ClientPort : public Object { |
| 16 | public: | 17 | public: |
| 17 | friend class ServerPort; | 18 | friend class ServerPort; |
| 18 | std::string GetTypeName() const override { | 19 | |
| 19 | return "ClientPort"; | 20 | /** |
| 20 | } | 21 | * Adds the specified server session to the queue of pending sessions of the associated ServerPort |
| 21 | std::string GetName() const override { | 22 | * @param server_session Server session to add to the queue |
| 22 | return name; | 23 | */ |
| 23 | } | 24 | virtual void AddWaitingSession(SharedPtr<ServerSession> server_session); |
| 25 | |||
| 26 | /** | ||
| 27 | * Handle a sync request from the emulated application. | ||
| 28 | * Only HLE services should override this function. | ||
| 29 | * @returns ResultCode from the operation. | ||
| 30 | */ | ||
| 31 | virtual ResultCode HandleSyncRequest() { return RESULT_SUCCESS; } | ||
| 32 | |||
| 33 | std::string GetTypeName() const override { return "ClientPort"; } | ||
| 34 | std::string GetName() const override { return name; } | ||
| 24 | 35 | ||
| 25 | static const HandleType HANDLE_TYPE = HandleType::ClientPort; | 36 | static const HandleType HANDLE_TYPE = HandleType::ClientPort; |
| 26 | HandleType GetHandleType() const override { | 37 | HandleType GetHandleType() const override { |
diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp new file mode 100644 index 000000000..f1ad9b65b --- /dev/null +++ b/src/core/hle/kernel/client_session.cpp | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/assert.h" | ||
| 6 | |||
| 7 | #include "core/hle/kernel/client_port.h" | ||
| 8 | #include "core/hle/kernel/client_session.h" | ||
| 9 | #include "core/hle/kernel/server_session.h" | ||
| 10 | #include "core/hle/kernel/kernel.h" | ||
| 11 | |||
| 12 | namespace Kernel { | ||
| 13 | |||
| 14 | ClientSession::ClientSession() {} | ||
| 15 | ClientSession::~ClientSession() {} | ||
| 16 | |||
| 17 | ResultVal<SharedPtr<ClientSession>> ClientSession::Create(SharedPtr<ServerSession> server_session, SharedPtr<ClientPort> client_port, std::string name) { | ||
| 18 | SharedPtr<ClientSession> client_session(new ClientSession); | ||
| 19 | |||
| 20 | client_session->name = std::move(name); | ||
| 21 | client_session->server_session = server_session; | ||
| 22 | client_session->client_port = client_port; | ||
| 23 | |||
| 24 | return MakeResult<SharedPtr<ClientSession>>(std::move(client_session)); | ||
| 25 | } | ||
| 26 | |||
| 27 | ResultCode ClientSession::HandleSyncRequest() { | ||
| 28 | // Signal the server session that new data is available | ||
| 29 | ResultCode result = server_session->HandleSyncRequest(); | ||
| 30 | |||
| 31 | if (result.IsError()) | ||
| 32 | return result; | ||
| 33 | |||
| 34 | // Tell the client port to handle the request in case it's an HLE service. | ||
| 35 | // The client port can be nullptr for port-less sessions (Like for example File and Directory sessions). | ||
| 36 | if (client_port != nullptr) | ||
| 37 | result = client_port->HandleSyncRequest(); | ||
| 38 | |||
| 39 | return result; | ||
| 40 | } | ||
| 41 | |||
| 42 | } // namespace | ||
diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h new file mode 100644 index 000000000..4fe9b4517 --- /dev/null +++ b/src/core/hle/kernel/client_session.h | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <string> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | |||
| 11 | #include "core/hle/kernel/kernel.h" | ||
| 12 | |||
| 13 | namespace Kernel { | ||
| 14 | |||
| 15 | class ClientPort; | ||
| 16 | class ServerSession; | ||
| 17 | |||
| 18 | class ClientSession final : public Object { | ||
| 19 | public: | ||
| 20 | /** | ||
| 21 | * Creates a client session. | ||
| 22 | * @param server_session The server session associated with this client session | ||
| 23 | * @param client_port The client port which this session is connected to | ||
| 24 | * @param name Optional name of client session | ||
| 25 | * @return The created client session | ||
| 26 | */ | ||
| 27 | static ResultVal<SharedPtr<ClientSession>> Create(SharedPtr<ServerSession> server_session, SharedPtr<ClientPort> client_port, std::string name = "Unknown"); | ||
| 28 | |||
| 29 | std::string GetTypeName() const override { return "ClientSession"; } | ||
| 30 | std::string GetName() const override { return name; } | ||
| 31 | |||
| 32 | static const HandleType HANDLE_TYPE = HandleType::ClientSession; | ||
| 33 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | ||
| 34 | |||
| 35 | /** | ||
| 36 | * Handle a SyncRequest from the emulated application. | ||
| 37 | * @return ResultCode of the operation. | ||
| 38 | */ | ||
| 39 | ResultCode HandleSyncRequest(); | ||
| 40 | |||
| 41 | std::string name; ///< Name of client port (optional) | ||
| 42 | SharedPtr<ServerSession> server_session; ///< The server session associated with this client session. | ||
| 43 | SharedPtr<ClientPort> client_port; ///< The client port which this session is connected to. | ||
| 44 | |||
| 45 | private: | ||
| 46 | ClientSession(); | ||
| 47 | ~ClientSession() override; | ||
| 48 | }; | ||
| 49 | |||
| 50 | } // namespace | ||
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 231cf7b75..c11c14b7d 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -31,22 +31,24 @@ enum KernelHandle : Handle { | |||
| 31 | }; | 31 | }; |
| 32 | 32 | ||
| 33 | enum class HandleType : u32 { | 33 | enum class HandleType : u32 { |
| 34 | Unknown = 0, | 34 | Unknown = 0, |
| 35 | 35 | ||
| 36 | Session = 2, | 36 | |
| 37 | Event = 3, | 37 | Event = 3, |
| 38 | Mutex = 4, | 38 | Mutex = 4, |
| 39 | SharedMemory = 5, | 39 | SharedMemory = 5, |
| 40 | Redirection = 6, | 40 | Redirection = 6, |
| 41 | Thread = 7, | 41 | Thread = 7, |
| 42 | Process = 8, | 42 | Process = 8, |
| 43 | AddressArbiter = 9, | 43 | AddressArbiter = 9, |
| 44 | Semaphore = 10, | 44 | Semaphore = 10, |
| 45 | Timer = 11, | 45 | Timer = 11, |
| 46 | ResourceLimit = 12, | 46 | ResourceLimit = 12, |
| 47 | CodeSet = 13, | 47 | CodeSet = 13, |
| 48 | ClientPort = 14, | 48 | ClientPort = 14, |
| 49 | ServerPort = 15, | 49 | ServerPort = 15, |
| 50 | ClientSession = 16, | ||
| 51 | ServerSession = 17, | ||
| 50 | }; | 52 | }; |
| 51 | 53 | ||
| 52 | enum { | 54 | enum { |
| @@ -82,7 +84,7 @@ public: | |||
| 82 | */ | 84 | */ |
| 83 | bool IsWaitable() const { | 85 | bool IsWaitable() const { |
| 84 | switch (GetHandleType()) { | 86 | switch (GetHandleType()) { |
| 85 | case HandleType::Session: | 87 | case HandleType::ServerSession: |
| 86 | case HandleType::ServerPort: | 88 | case HandleType::ServerPort: |
| 87 | case HandleType::Event: | 89 | case HandleType::Event: |
| 88 | case HandleType::Mutex: | 90 | case HandleType::Mutex: |
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp new file mode 100644 index 000000000..9f5350ce5 --- /dev/null +++ b/src/core/hle/kernel/server_session.cpp | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <tuple> | ||
| 6 | |||
| 7 | #include "core/hle/kernel/client_port.h" | ||
| 8 | #include "core/hle/kernel/client_session.h" | ||
| 9 | #include "core/hle/kernel/server_session.h" | ||
| 10 | #include "core/hle/kernel/thread.h" | ||
| 11 | |||
| 12 | namespace Kernel { | ||
| 13 | |||
| 14 | ServerSession::ServerSession() {} | ||
| 15 | ServerSession::~ServerSession() {} | ||
| 16 | |||
| 17 | ResultVal<SharedPtr<ServerSession>> ServerSession::Create(std::string name) { | ||
| 18 | SharedPtr<ServerSession> server_session(new ServerSession); | ||
| 19 | |||
| 20 | server_session->name = std::move(name); | ||
| 21 | server_session->signaled = false; | ||
| 22 | |||
| 23 | return MakeResult<SharedPtr<ServerSession>>(std::move(server_session)); | ||
| 24 | } | ||
| 25 | |||
| 26 | bool ServerSession::ShouldWait() { | ||
| 27 | return !signaled; | ||
| 28 | } | ||
| 29 | |||
| 30 | void ServerSession::Acquire() { | ||
| 31 | ASSERT_MSG(!ShouldWait(), "object unavailable!"); | ||
| 32 | signaled = false; | ||
| 33 | } | ||
| 34 | |||
| 35 | ResultCode ServerSession::HandleSyncRequest() { | ||
| 36 | // The ServerSession received a sync request, this means that there's new data available | ||
| 37 | // from one of its ClientSessions, so wake up any threads that may be waiting on a svcReplyAndReceive or similar. | ||
| 38 | signaled = true; | ||
| 39 | WakeupAllWaitingThreads(); | ||
| 40 | return RESULT_SUCCESS; | ||
| 41 | } | ||
| 42 | |||
| 43 | SharedPtr<ClientSession> ServerSession::CreateClientSession() { | ||
| 44 | // In Citra, some types of ServerSessions (File and Directory sessions) are not created as a pair of Server-Client sessions, | ||
| 45 | // but are instead created as a single ServerSession, which then hands over a ClientSession on demand (When opening the File or Directory). | ||
| 46 | // The real kernel (Or more specifically, the real FS service) does create the pair of Sessions at the same time (via svcCreateSession), and simply | ||
| 47 | // stores the ClientSession until it is needed. | ||
| 48 | return ClientSession::Create(SharedPtr<ServerSession>(this), nullptr, name + "Client").MoveFrom(); | ||
| 49 | } | ||
| 50 | |||
| 51 | std::tuple<SharedPtr<ServerSession>, SharedPtr<ClientSession>> ServerSession::CreateSessionPair(SharedPtr<ClientPort> client_port, std::string name) { | ||
| 52 | auto server_session = ServerSession::Create(name + "Server").MoveFrom(); | ||
| 53 | auto client_session = ClientSession::Create(server_session, client_port, name + "Client").MoveFrom(); | ||
| 54 | |||
| 55 | return std::make_tuple(server_session, client_session); | ||
| 56 | } | ||
| 57 | |||
| 58 | } | ||
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/server_session.h index ec025f732..eab9fe211 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/kernel/server_session.h | |||
| @@ -162,57 +162,64 @@ inline u32* GetCommandBuffer(const int offset = 0) { | |||
| 162 | offset); | 162 | offset); |
| 163 | } | 163 | } |
| 164 | 164 | ||
| 165 | class ClientSession; | ||
| 166 | class ClientPort; | ||
| 167 | |||
| 165 | /** | 168 | /** |
| 166 | * Kernel object representing the client endpoint of an IPC session. Sessions are the basic CTR-OS | 169 | * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS |
| 167 | * primitive for communication between different processes, and are used to implement service calls | 170 | * primitive for communication between different processes, and are used to implement service calls |
| 168 | * to the various system services. | 171 | * to the various system services. |
| 169 | * | 172 | * |
| 170 | * To make a service call, the client must write the command header and parameters to the buffer | 173 | * To make a service call, the client must write the command header and parameters to the buffer |
| 171 | * located at offset 0x80 of the TLS (Thread-Local Storage) area, then execute a SendSyncRequest | 174 | * located at offset 0x80 of the TLS (Thread-Local Storage) area, then execute a SendSyncRequest |
| 172 | * SVC call with its Session handle. The kernel will read the command header, using it to marshall | 175 | * SVC call with its ClientSession handle. The kernel will read the command header, using it to marshall |
| 173 | * the parameters to the process at the server endpoint of the session. After the server replies to | 176 | * the parameters to the process at the server endpoint of the session. After the server replies to |
| 174 | * the request, the response is marshalled back to the caller's TLS buffer and control is | 177 | * the request, the response is marshalled back to the caller's TLS buffer and control is |
| 175 | * transferred back to it. | 178 | * transferred back to it. |
| 176 | * | ||
| 177 | * In Citra, only the client endpoint is currently implemented and only HLE calls, where the IPC | ||
| 178 | * request is answered by C++ code in the emulator, are supported. When SendSyncRequest is called | ||
| 179 | * with the session handle, this class's SyncRequest method is called, which should read the TLS | ||
| 180 | * buffer and emulate the call accordingly. Since the code can directly read the emulated memory, | ||
| 181 | * no parameter marshalling is done. | ||
| 182 | * | ||
| 183 | * In the long term, this should be turned into the full-fledged IPC mechanism implemented by | ||
| 184 | * CTR-OS so that IPC calls can be optionally handled by the real implementations of processes, as | ||
| 185 | * opposed to HLE simulations. | ||
| 186 | */ | 179 | */ |
| 187 | class Session : public WaitObject { | 180 | class ServerSession : public WaitObject { |
| 188 | public: | 181 | public: |
| 189 | Session(); | 182 | ServerSession(); |
| 190 | ~Session() override; | 183 | ~ServerSession() override; |
| 184 | |||
| 185 | /** | ||
| 186 | * Creates a server session. | ||
| 187 | * @param name Optional name of the server session | ||
| 188 | * @return The created server session | ||
| 189 | */ | ||
| 190 | static ResultVal<SharedPtr<ServerSession>> Create(std::string name = "Unknown"); | ||
| 191 | 191 | ||
| 192 | std::string GetTypeName() const override { | 192 | std::string GetTypeName() const override { return "ServerSession"; } |
| 193 | return "Session"; | ||
| 194 | } | ||
| 195 | 193 | ||
| 196 | static const HandleType HANDLE_TYPE = HandleType::Session; | 194 | static const HandleType HANDLE_TYPE = HandleType::ServerSession; |
| 197 | HandleType GetHandleType() const override { | 195 | HandleType GetHandleType() const override { return HANDLE_TYPE; } |
| 198 | return HANDLE_TYPE; | 196 | |
| 199 | } | 197 | /** |
| 198 | * Creates a pair of ServerSession and an associated ClientSession. | ||
| 199 | * @param client_port ClientPort to which the sessions are connected | ||
| 200 | * @param name Optional name of the ports | ||
| 201 | * @return The created session tuple | ||
| 202 | */ | ||
| 203 | static std::tuple<SharedPtr<ServerSession>, SharedPtr<ClientSession>> CreateSessionPair(SharedPtr<ClientPort> client_port, std::string name = "Unknown"); | ||
| 204 | |||
| 205 | /** | ||
| 206 | * Creates a portless ClientSession and associates it with this ServerSession. | ||
| 207 | * @returns ClientSession The newly created ClientSession. | ||
| 208 | */ | ||
| 209 | SharedPtr<ClientSession> CreateClientSession(); | ||
| 200 | 210 | ||
| 201 | /** | 211 | /** |
| 202 | * Handles a synchronous call to this session using HLE emulation. Emulated <-> emulated calls | 212 | * Handle a sync request from the emulated application. |
| 203 | * aren't supported yet. | 213 | * Only HLE services should override this function. |
| 214 | * @returns ResultCode from the operation. | ||
| 204 | */ | 215 | */ |
| 205 | virtual ResultVal<bool> SyncRequest() = 0; | 216 | virtual ResultCode HandleSyncRequest(); |
| 206 | 217 | ||
| 207 | // TODO(bunnei): These functions exist to satisfy a hardware test with a Session object | 218 | bool ShouldWait() override; |
| 208 | // passed into WaitSynchronization. Figure out the meaning of them. | ||
| 209 | 219 | ||
| 210 | bool ShouldWait() override { | 220 | void Acquire() override; |
| 211 | return true; | ||
| 212 | } | ||
| 213 | 221 | ||
| 214 | void Acquire() override { | 222 | std::string name; ///< The name of this session (optional) |
| 215 | ASSERT_MSG(!ShouldWait(), "object unavailable!"); | 223 | bool signaled; ///< Whether there's new data available to this ServerSession |
| 216 | } | ||
| 217 | }; | 224 | }; |
| 218 | } | 225 | } |