diff options
| author | 2016-12-14 20:35:33 -0800 | |
|---|---|---|
| committer | 2016-12-14 20:35:33 -0800 | |
| commit | 905fc92ce1f7d99d8819a17b180a559b3a9f15de (patch) | |
| tree | cc992764c2ea065d8d30dce2055cc1efe167bc59 /src/core/hle | |
| parent | Merge pull request #2166 from endrift/clang-detect (diff) | |
| parent | Fixed the codestyle to match our clang-format rules. (diff) | |
| download | yuzu-905fc92ce1f7d99d8819a17b180a559b3a9f15de.tar.gz yuzu-905fc92ce1f7d99d8819a17b180a559b3a9f15de.tar.xz yuzu-905fc92ce1f7d99d8819a17b180a559b3a9f15de.zip | |
Merge pull request #2249 from Subv/sessions_v3
Kernel/IPC: Use Ports and Sessions as the fundamental building block of Inter Process Communication.
Diffstat (limited to 'src/core/hle')
23 files changed, 586 insertions, 168 deletions
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/ipc.h index ec025f732..4e094faa7 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/ipc.h | |||
| @@ -1,17 +1,31 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | 1 | // Copyright 2016 Citra Emulator Project |
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <string> | ||
| 8 | #include "common/assert.h" | ||
| 9 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 10 | #include "core/hle/kernel/kernel.h" | ||
| 11 | #include "core/hle/kernel/thread.h" | 8 | #include "core/hle/kernel/thread.h" |
| 12 | #include "core/hle/result.h" | ||
| 13 | #include "core/memory.h" | 9 | #include "core/memory.h" |
| 14 | 10 | ||
| 11 | namespace Kernel { | ||
| 12 | |||
| 13 | static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header | ||
| 14 | |||
| 15 | /** | ||
| 16 | * Returns a pointer to the command buffer in the current thread's TLS | ||
| 17 | * TODO(Subv): This is not entirely correct, the command buffer should be copied from | ||
| 18 | * the thread's TLS to an intermediate buffer in kernel memory, and then copied again to | ||
| 19 | * the service handler process' memory. | ||
| 20 | * @param offset Optional offset into command buffer | ||
| 21 | * @return Pointer to command buffer | ||
| 22 | */ | ||
| 23 | inline u32* GetCommandBuffer(const int offset = 0) { | ||
| 24 | return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset + | ||
| 25 | offset); | ||
| 26 | } | ||
| 27 | } | ||
| 28 | |||
| 15 | namespace IPC { | 29 | namespace IPC { |
| 16 | 30 | ||
| 17 | enum DescriptorType : u32 { | 31 | enum DescriptorType : u32 { |
| @@ -144,75 +158,3 @@ inline DescriptorType GetDescriptorType(u32 descriptor) { | |||
| 144 | } | 158 | } |
| 145 | 159 | ||
| 146 | } // namespace IPC | 160 | } // namespace IPC |
| 147 | |||
| 148 | namespace Kernel { | ||
| 149 | |||
| 150 | static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header | ||
| 151 | |||
| 152 | /** | ||
| 153 | * Returns a pointer to the command buffer in the current thread's TLS | ||
| 154 | * TODO(Subv): This is not entirely correct, the command buffer should be copied from | ||
| 155 | * the thread's TLS to an intermediate buffer in kernel memory, and then copied again to | ||
| 156 | * the service handler process' memory. | ||
| 157 | * @param offset Optional offset into command buffer | ||
| 158 | * @return Pointer to command buffer | ||
| 159 | */ | ||
| 160 | inline u32* GetCommandBuffer(const int offset = 0) { | ||
| 161 | return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset + | ||
| 162 | offset); | ||
| 163 | } | ||
| 164 | |||
| 165 | /** | ||
| 166 | * Kernel object representing the client 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 | ||
| 168 | * to the various system services. | ||
| 169 | * | ||
| 170 | * 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 | ||
| 172 | * SVC call with its Session 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 | ||
| 174 | * the request, the response is marshalled back to the caller's TLS buffer and control is | ||
| 175 | * 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 | */ | ||
| 187 | class Session : public WaitObject { | ||
| 188 | public: | ||
| 189 | Session(); | ||
| 190 | ~Session() override; | ||
| 191 | |||
| 192 | std::string GetTypeName() const override { | ||
| 193 | return "Session"; | ||
| 194 | } | ||
| 195 | |||
| 196 | static const HandleType HANDLE_TYPE = HandleType::Session; | ||
| 197 | HandleType GetHandleType() const override { | ||
| 198 | return HANDLE_TYPE; | ||
| 199 | } | ||
| 200 | |||
| 201 | /** | ||
| 202 | * Handles a synchronous call to this session using HLE emulation. Emulated <-> emulated calls | ||
| 203 | * aren't supported yet. | ||
| 204 | */ | ||
| 205 | virtual ResultVal<bool> SyncRequest() = 0; | ||
| 206 | |||
| 207 | // TODO(bunnei): These functions exist to satisfy a hardware test with a Session object | ||
| 208 | // passed into WaitSynchronization. Figure out the meaning of them. | ||
| 209 | |||
| 210 | bool ShouldWait() override { | ||
| 211 | return true; | ||
| 212 | } | ||
| 213 | |||
| 214 | void Acquire() override { | ||
| 215 | ASSERT_MSG(!ShouldWait(), "object unavailable!"); | ||
| 216 | } | ||
| 217 | }; | ||
| 218 | } | ||
diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index aedc6f989..22645f4ec 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp | |||
| @@ -4,12 +4,44 @@ | |||
| 4 | 4 | ||
| 5 | #include "common/assert.h" | 5 | #include "common/assert.h" |
| 6 | #include "core/hle/kernel/client_port.h" | 6 | #include "core/hle/kernel/client_port.h" |
| 7 | #include "core/hle/kernel/client_session.h" | ||
| 7 | #include "core/hle/kernel/kernel.h" | 8 | #include "core/hle/kernel/kernel.h" |
| 8 | #include "core/hle/kernel/server_port.h" | 9 | #include "core/hle/kernel/server_port.h" |
| 10 | #include "core/hle/kernel/server_session.h" | ||
| 9 | 11 | ||
| 10 | namespace Kernel { | 12 | namespace Kernel { |
| 11 | 13 | ||
| 12 | ClientPort::ClientPort() {} | 14 | ClientPort::ClientPort() {} |
| 13 | ClientPort::~ClientPort() {} | 15 | ClientPort::~ClientPort() {} |
| 14 | 16 | ||
| 17 | ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() { | ||
| 18 | // Note: Threads do not wait for the server endpoint to call | ||
| 19 | // AcceptSession before returning from this call. | ||
| 20 | |||
| 21 | if (active_sessions >= max_sessions) { | ||
| 22 | // TODO(Subv): Return an error code in this situation after session disconnection is | ||
| 23 | // implemented. | ||
| 24 | /*return ResultCode(ErrorDescription::MaxConnectionsReached, | ||
| 25 | ErrorModule::OS, ErrorSummary::WouldBlock, | ||
| 26 | ErrorLevel::Temporary);*/ | ||
| 27 | } | ||
| 28 | active_sessions++; | ||
| 29 | |||
| 30 | // Create a new session pair, let the created sessions inherit the parent port's HLE handler. | ||
| 31 | auto sessions = | ||
| 32 | ServerSession::CreateSessionPair(server_port->GetName(), server_port->hle_handler); | ||
| 33 | auto client_session = std::get<SharedPtr<ClientSession>>(sessions); | ||
| 34 | auto server_session = std::get<SharedPtr<ServerSession>>(sessions); | ||
| 35 | |||
| 36 | if (server_port->hle_handler) | ||
| 37 | server_port->hle_handler->ClientConnected(server_session); | ||
| 38 | |||
| 39 | server_port->pending_sessions.push_back(std::move(server_session)); | ||
| 40 | |||
| 41 | // Wake the threads waiting on the ServerPort | ||
| 42 | server_port->WakeupAllWaitingThreads(); | ||
| 43 | |||
| 44 | return MakeResult<SharedPtr<ClientSession>>(std::move(client_session)); | ||
| 45 | } | ||
| 46 | |||
| 15 | } // namespace | 47 | } // namespace |
diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h index d28147718..511490c7c 100644 --- a/src/core/hle/kernel/client_port.h +++ b/src/core/hle/kernel/client_port.h | |||
| @@ -11,8 +11,9 @@ | |||
| 11 | namespace Kernel { | 11 | namespace Kernel { |
| 12 | 12 | ||
| 13 | class ServerPort; | 13 | class ServerPort; |
| 14 | class ClientSession; | ||
| 14 | 15 | ||
| 15 | class ClientPort : public Object { | 16 | class ClientPort final : public Object { |
| 16 | public: | 17 | public: |
| 17 | friend class ServerPort; | 18 | friend class ServerPort; |
| 18 | std::string GetTypeName() const override { | 19 | std::string GetTypeName() const override { |
| @@ -27,12 +28,20 @@ public: | |||
| 27 | return HANDLE_TYPE; | 28 | return HANDLE_TYPE; |
| 28 | } | 29 | } |
| 29 | 30 | ||
| 31 | /** | ||
| 32 | * Creates a new Session pair, adds the created ServerSession to the associated ServerPort's | ||
| 33 | * list of pending sessions, and signals the ServerPort, causing any threads | ||
| 34 | * waiting on it to awake. | ||
| 35 | * @returns ClientSession The client endpoint of the created Session pair, or error code. | ||
| 36 | */ | ||
| 37 | ResultVal<SharedPtr<ClientSession>> Connect(); | ||
| 38 | |||
| 30 | SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port. | 39 | SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port. |
| 31 | u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have | 40 | u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have |
| 32 | u32 active_sessions; ///< Number of currently open sessions to this port | 41 | u32 active_sessions; ///< Number of currently open sessions to this port |
| 33 | std::string name; ///< Name of client port (optional) | 42 | std::string name; ///< Name of client port (optional) |
| 34 | 43 | ||
| 35 | protected: | 44 | private: |
| 36 | ClientPort(); | 45 | ClientPort(); |
| 37 | ~ClientPort() override; | 46 | ~ClientPort() override; |
| 38 | }; | 47 | }; |
diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp new file mode 100644 index 000000000..0331386ec --- /dev/null +++ b/src/core/hle/kernel/client_session.cpp | |||
| @@ -0,0 +1,40 @@ | |||
| 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_session.h" | ||
| 8 | #include "core/hle/kernel/server_session.h" | ||
| 9 | |||
| 10 | namespace Kernel { | ||
| 11 | |||
| 12 | ClientSession::ClientSession() = default; | ||
| 13 | ClientSession::~ClientSession() { | ||
| 14 | // This destructor will be called automatically when the last ClientSession handle is closed by | ||
| 15 | // the emulated application. | ||
| 16 | |||
| 17 | if (server_session->hle_handler) | ||
| 18 | server_session->hle_handler->ClientDisconnected(server_session); | ||
| 19 | |||
| 20 | // TODO(Subv): If the session is still open, set the connection status to 2 (Closed by client), | ||
| 21 | // wake up all the ServerSession's waiting threads and set the WaitSynchronization result to | ||
| 22 | // 0xC920181A. | ||
| 23 | } | ||
| 24 | |||
| 25 | ResultVal<SharedPtr<ClientSession>> ClientSession::Create(ServerSession* server_session, | ||
| 26 | std::string name) { | ||
| 27 | SharedPtr<ClientSession> client_session(new ClientSession); | ||
| 28 | |||
| 29 | client_session->name = std::move(name); | ||
| 30 | client_session->server_session = server_session; | ||
| 31 | client_session->session_status = SessionStatus::Open; | ||
| 32 | return MakeResult<SharedPtr<ClientSession>>(std::move(client_session)); | ||
| 33 | } | ||
| 34 | |||
| 35 | ResultCode ClientSession::SendSyncRequest() { | ||
| 36 | // Signal the server session that new data is available | ||
| 37 | return server_session->HandleSyncRequest(); | ||
| 38 | } | ||
| 39 | |||
| 40 | } // 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..ed468dec6 --- /dev/null +++ b/src/core/hle/kernel/client_session.h | |||
| @@ -0,0 +1,65 @@ | |||
| 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 <memory> | ||
| 8 | #include <string> | ||
| 9 | |||
| 10 | #include "common/common_types.h" | ||
| 11 | |||
| 12 | #include "core/hle/kernel/kernel.h" | ||
| 13 | |||
| 14 | namespace Kernel { | ||
| 15 | |||
| 16 | class ServerSession; | ||
| 17 | |||
| 18 | enum class SessionStatus { | ||
| 19 | Open = 1, | ||
| 20 | ClosedByClient = 2, | ||
| 21 | ClosedBYServer = 3, | ||
| 22 | }; | ||
| 23 | |||
| 24 | class ClientSession final : public Object { | ||
| 25 | public: | ||
| 26 | friend class ServerSession; | ||
| 27 | |||
| 28 | std::string GetTypeName() const override { | ||
| 29 | return "ClientSession"; | ||
| 30 | } | ||
| 31 | |||
| 32 | std::string GetName() const override { | ||
| 33 | return name; | ||
| 34 | } | ||
| 35 | |||
| 36 | static const HandleType HANDLE_TYPE = HandleType::ClientSession; | ||
| 37 | HandleType GetHandleType() const override { | ||
| 38 | return HANDLE_TYPE; | ||
| 39 | } | ||
| 40 | |||
| 41 | /** | ||
| 42 | * Sends an SyncRequest from the current emulated thread. | ||
| 43 | * @return ResultCode of the operation. | ||
| 44 | */ | ||
| 45 | ResultCode SendSyncRequest(); | ||
| 46 | |||
| 47 | std::string name; ///< Name of client port (optional) | ||
| 48 | ServerSession* server_session; ///< The server session associated with this client session. | ||
| 49 | SessionStatus session_status; ///< The session's current status. | ||
| 50 | |||
| 51 | private: | ||
| 52 | ClientSession(); | ||
| 53 | ~ClientSession() override; | ||
| 54 | |||
| 55 | /** | ||
| 56 | * Creates a client session. | ||
| 57 | * @param server_session The server session associated with this client session | ||
| 58 | * @param name Optional name of client session | ||
| 59 | * @return The created client session | ||
| 60 | */ | ||
| 61 | static ResultVal<SharedPtr<ClientSession>> Create(ServerSession* server_session, | ||
| 62 | std::string name = "Unknown"); | ||
| 63 | }; | ||
| 64 | |||
| 65 | } // namespace | ||
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 231cf7b75..0b811c5a7 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -31,22 +31,21 @@ enum KernelHandle : Handle { | |||
| 31 | }; | 31 | }; |
| 32 | 32 | ||
| 33 | enum class HandleType : u32 { | 33 | enum class HandleType : u32 { |
| 34 | Unknown = 0, | 34 | Unknown, |
| 35 | 35 | Event, | |
| 36 | Session = 2, | 36 | Mutex, |
| 37 | Event = 3, | 37 | SharedMemory, |
| 38 | Mutex = 4, | 38 | Thread, |
| 39 | SharedMemory = 5, | 39 | Process, |
| 40 | Redirection = 6, | 40 | AddressArbiter, |
| 41 | Thread = 7, | 41 | Semaphore, |
| 42 | Process = 8, | 42 | Timer, |
| 43 | AddressArbiter = 9, | 43 | ResourceLimit, |
| 44 | Semaphore = 10, | 44 | CodeSet, |
| 45 | Timer = 11, | 45 | ClientPort, |
| 46 | ResourceLimit = 12, | 46 | ServerPort, |
| 47 | CodeSet = 13, | 47 | ClientSession, |
| 48 | ClientPort = 14, | 48 | ServerSession, |
| 49 | ServerPort = 15, | ||
| 50 | }; | 49 | }; |
| 51 | 50 | ||
| 52 | enum { | 51 | enum { |
| @@ -82,23 +81,23 @@ public: | |||
| 82 | */ | 81 | */ |
| 83 | bool IsWaitable() const { | 82 | bool IsWaitable() const { |
| 84 | switch (GetHandleType()) { | 83 | switch (GetHandleType()) { |
| 85 | case HandleType::Session: | ||
| 86 | case HandleType::ServerPort: | ||
| 87 | case HandleType::Event: | 84 | case HandleType::Event: |
| 88 | case HandleType::Mutex: | 85 | case HandleType::Mutex: |
| 89 | case HandleType::Thread: | 86 | case HandleType::Thread: |
| 90 | case HandleType::Semaphore: | 87 | case HandleType::Semaphore: |
| 91 | case HandleType::Timer: | 88 | case HandleType::Timer: |
| 89 | case HandleType::ServerPort: | ||
| 90 | case HandleType::ServerSession: | ||
| 92 | return true; | 91 | return true; |
| 93 | 92 | ||
| 94 | case HandleType::Unknown: | 93 | case HandleType::Unknown: |
| 95 | case HandleType::SharedMemory: | 94 | case HandleType::SharedMemory: |
| 96 | case HandleType::Redirection: | ||
| 97 | case HandleType::Process: | 95 | case HandleType::Process: |
| 98 | case HandleType::AddressArbiter: | 96 | case HandleType::AddressArbiter: |
| 99 | case HandleType::ResourceLimit: | 97 | case HandleType::ResourceLimit: |
| 100 | case HandleType::CodeSet: | 98 | case HandleType::CodeSet: |
| 101 | case HandleType::ClientPort: | 99 | case HandleType::ClientPort: |
| 100 | case HandleType::ClientSession: | ||
| 102 | return false; | 101 | return false; |
| 103 | } | 102 | } |
| 104 | } | 103 | } |
diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp index 8e3ec8a14..6c19aa7c0 100644 --- a/src/core/hle/kernel/server_port.cpp +++ b/src/core/hle/kernel/server_port.cpp | |||
| @@ -24,12 +24,14 @@ void ServerPort::Acquire() { | |||
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortPair( | 26 | std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortPair( |
| 27 | u32 max_sessions, std::string name) { | 27 | u32 max_sessions, std::string name, |
| 28 | std::shared_ptr<Service::SessionRequestHandler> hle_handler) { | ||
| 28 | 29 | ||
| 29 | SharedPtr<ServerPort> server_port(new ServerPort); | 30 | SharedPtr<ServerPort> server_port(new ServerPort); |
| 30 | SharedPtr<ClientPort> client_port(new ClientPort); | 31 | SharedPtr<ClientPort> client_port(new ClientPort); |
| 31 | 32 | ||
| 32 | server_port->name = name + "_Server"; | 33 | server_port->name = name + "_Server"; |
| 34 | server_port->hle_handler = std::move(hle_handler); | ||
| 33 | client_port->name = name + "_Client"; | 35 | client_port->name = name + "_Client"; |
| 34 | client_port->server_port = server_port; | 36 | client_port->server_port = server_port; |
| 35 | client_port->max_sessions = max_sessions; | 37 | client_port->max_sessions = max_sessions; |
diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h index fa9448ca0..b0f8df62c 100644 --- a/src/core/hle/kernel/server_port.h +++ b/src/core/hle/kernel/server_port.h | |||
| @@ -4,11 +4,16 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <memory> | ||
| 7 | #include <string> | 8 | #include <string> |
| 8 | #include <tuple> | 9 | #include <tuple> |
| 9 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 10 | #include "core/hle/kernel/kernel.h" | 11 | #include "core/hle/kernel/kernel.h" |
| 11 | 12 | ||
| 13 | namespace Service { | ||
| 14 | class SessionRequestHandler; | ||
| 15 | } | ||
| 16 | |||
| 12 | namespace Kernel { | 17 | namespace Kernel { |
| 13 | 18 | ||
| 14 | class ClientPort; | 19 | class ClientPort; |
| @@ -19,10 +24,13 @@ public: | |||
| 19 | * Creates a pair of ServerPort and an associated ClientPort. | 24 | * Creates a pair of ServerPort and an associated ClientPort. |
| 20 | * @param max_sessions Maximum number of sessions to the port | 25 | * @param max_sessions Maximum number of sessions to the port |
| 21 | * @param name Optional name of the ports | 26 | * @param name Optional name of the ports |
| 27 | * @param hle_handler Optional HLE handler template for the port, | ||
| 28 | * ServerSessions crated from this port will inherit a reference to this handler. | ||
| 22 | * @return The created port tuple | 29 | * @return The created port tuple |
| 23 | */ | 30 | */ |
| 24 | static std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> CreatePortPair( | 31 | static std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> CreatePortPair( |
| 25 | u32 max_sessions, std::string name = "UnknownPort"); | 32 | u32 max_sessions, std::string name = "UnknownPort", |
| 33 | std::shared_ptr<Service::SessionRequestHandler> hle_handler = nullptr); | ||
| 26 | 34 | ||
| 27 | std::string GetTypeName() const override { | 35 | std::string GetTypeName() const override { |
| 28 | return "ServerPort"; | 36 | return "ServerPort"; |
| @@ -41,6 +49,10 @@ public: | |||
| 41 | std::vector<SharedPtr<WaitObject>> | 49 | std::vector<SharedPtr<WaitObject>> |
| 42 | pending_sessions; ///< ServerSessions waiting to be accepted by the port | 50 | pending_sessions; ///< ServerSessions waiting to be accepted by the port |
| 43 | 51 | ||
| 52 | /// This session's HLE request handler template (optional) | ||
| 53 | /// ServerSessions created from this port inherit a reference to this handler. | ||
| 54 | std::shared_ptr<Service::SessionRequestHandler> hle_handler; | ||
| 55 | |||
| 44 | bool ShouldWait() override; | 56 | bool ShouldWait() override; |
| 45 | void Acquire() override; | 57 | void Acquire() override; |
| 46 | 58 | ||
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp new file mode 100644 index 000000000..146458c1c --- /dev/null +++ b/src/core/hle/kernel/server_session.cpp | |||
| @@ -0,0 +1,79 @@ | |||
| 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_session.h" | ||
| 8 | #include "core/hle/kernel/server_session.h" | ||
| 9 | #include "core/hle/kernel/thread.h" | ||
| 10 | |||
| 11 | namespace Kernel { | ||
| 12 | |||
| 13 | ServerSession::ServerSession() = default; | ||
| 14 | ServerSession::~ServerSession() { | ||
| 15 | // This destructor will be called automatically when the last ServerSession handle is closed by | ||
| 16 | // the emulated application. | ||
| 17 | // TODO(Subv): Reduce the ClientPort's connection count, | ||
| 18 | // if the session is still open, set the connection status to 3 (Closed by server), | ||
| 19 | } | ||
| 20 | |||
| 21 | ResultVal<SharedPtr<ServerSession>> ServerSession::Create( | ||
| 22 | std::string name, std::shared_ptr<Service::SessionRequestHandler> hle_handler) { | ||
| 23 | SharedPtr<ServerSession> server_session(new ServerSession); | ||
| 24 | |||
| 25 | server_session->name = std::move(name); | ||
| 26 | server_session->signaled = false; | ||
| 27 | server_session->hle_handler = std::move(hle_handler); | ||
| 28 | |||
| 29 | return MakeResult<SharedPtr<ServerSession>>(std::move(server_session)); | ||
| 30 | } | ||
| 31 | |||
| 32 | bool ServerSession::ShouldWait() { | ||
| 33 | return !signaled; | ||
| 34 | } | ||
| 35 | |||
| 36 | void ServerSession::Acquire() { | ||
| 37 | ASSERT_MSG(!ShouldWait(), "object unavailable!"); | ||
| 38 | signaled = false; | ||
| 39 | } | ||
| 40 | |||
| 41 | ResultCode ServerSession::HandleSyncRequest() { | ||
| 42 | // The ServerSession received a sync request, this means that there's new data available | ||
| 43 | // from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or | ||
| 44 | // similar. | ||
| 45 | |||
| 46 | // If this ServerSession has an associated HLE handler, forward the request to it. | ||
| 47 | if (hle_handler != nullptr) { | ||
| 48 | // Attempt to translate the incoming request's command buffer. | ||
| 49 | ResultCode result = TranslateHLERequest(this); | ||
| 50 | if (result.IsError()) | ||
| 51 | return result; | ||
| 52 | hle_handler->HandleSyncRequest(SharedPtr<ServerSession>(this)); | ||
| 53 | // TODO(Subv): Translate the response command buffer. | ||
| 54 | } | ||
| 55 | |||
| 56 | // If this ServerSession does not have an HLE implementation, just wake up the threads waiting | ||
| 57 | // on it. | ||
| 58 | signaled = true; | ||
| 59 | WakeupAllWaitingThreads(); | ||
| 60 | return RESULT_SUCCESS; | ||
| 61 | } | ||
| 62 | |||
| 63 | ServerSession::SessionPair ServerSession::CreateSessionPair( | ||
| 64 | const std::string& name, std::shared_ptr<Service::SessionRequestHandler> hle_handler) { | ||
| 65 | auto server_session = | ||
| 66 | ServerSession::Create(name + "_Server", std::move(hle_handler)).MoveFrom(); | ||
| 67 | // We keep a non-owning pointer to the ServerSession in the ClientSession because we don't want | ||
| 68 | // to prevent the ServerSession's destructor from being called when the emulated | ||
| 69 | // application closes the last ServerSession handle. | ||
| 70 | auto client_session = ClientSession::Create(server_session.get(), name + "_Client").MoveFrom(); | ||
| 71 | |||
| 72 | return std::make_tuple(std::move(server_session), std::move(client_session)); | ||
| 73 | } | ||
| 74 | |||
| 75 | ResultCode TranslateHLERequest(ServerSession* server_session) { | ||
| 76 | // TODO(Subv): Implement this function once multiple concurrent processes are supported. | ||
| 77 | return RESULT_SUCCESS; | ||
| 78 | } | ||
| 79 | } | ||
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h new file mode 100644 index 000000000..458284a5d --- /dev/null +++ b/src/core/hle/kernel/server_session.h | |||
| @@ -0,0 +1,94 @@ | |||
| 1 | // Copyright 2014 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 | #include "common/assert.h" | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "core/hle/kernel/kernel.h" | ||
| 11 | #include "core/hle/kernel/thread.h" | ||
| 12 | #include "core/hle/result.h" | ||
| 13 | #include "core/hle/service/service.h" | ||
| 14 | #include "core/memory.h" | ||
| 15 | |||
| 16 | namespace Kernel { | ||
| 17 | |||
| 18 | class ClientSession; | ||
| 19 | |||
| 20 | /** | ||
| 21 | * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS | ||
| 22 | * primitive for communication between different processes, and are used to implement service calls | ||
| 23 | * to the various system services. | ||
| 24 | * | ||
| 25 | * To make a service call, the client must write the command header and parameters to the buffer | ||
| 26 | * located at offset 0x80 of the TLS (Thread-Local Storage) area, then execute a SendSyncRequest | ||
| 27 | * SVC call with its ClientSession handle. The kernel will read the command header, using it to | ||
| 28 | * marshall the parameters to the process at the server endpoint of the session. | ||
| 29 | * After the server replies to the request, the response is marshalled back to the caller's | ||
| 30 | * TLS buffer and control is transferred back to it. | ||
| 31 | */ | ||
| 32 | class ServerSession final : public WaitObject { | ||
| 33 | public: | ||
| 34 | std::string GetTypeName() const override { | ||
| 35 | return "ServerSession"; | ||
| 36 | } | ||
| 37 | |||
| 38 | static const HandleType HANDLE_TYPE = HandleType::ServerSession; | ||
| 39 | HandleType GetHandleType() const override { | ||
| 40 | return HANDLE_TYPE; | ||
| 41 | } | ||
| 42 | |||
| 43 | using SessionPair = std::tuple<SharedPtr<ServerSession>, SharedPtr<ClientSession>>; | ||
| 44 | |||
| 45 | /** | ||
| 46 | * Creates a pair of ServerSession and an associated ClientSession. | ||
| 47 | * @param name Optional name of the ports | ||
| 48 | * @return The created session tuple | ||
| 49 | */ | ||
| 50 | static SessionPair CreateSessionPair( | ||
| 51 | const std::string& name = "Unknown", | ||
| 52 | std::shared_ptr<Service::SessionRequestHandler> hle_handler = nullptr); | ||
| 53 | |||
| 54 | /** | ||
| 55 | * Handle a sync request from the emulated application. | ||
| 56 | * @returns ResultCode from the operation. | ||
| 57 | */ | ||
| 58 | ResultCode HandleSyncRequest(); | ||
| 59 | |||
| 60 | bool ShouldWait() override; | ||
| 61 | |||
| 62 | void Acquire() override; | ||
| 63 | |||
| 64 | std::string name; ///< The name of this session (optional) | ||
| 65 | bool signaled; ///< Whether there's new data available to this ServerSession | ||
| 66 | std::shared_ptr<Service::SessionRequestHandler> | ||
| 67 | hle_handler; ///< This session's HLE request handler (optional) | ||
| 68 | |||
| 69 | private: | ||
| 70 | ServerSession(); | ||
| 71 | ~ServerSession() override; | ||
| 72 | |||
| 73 | /** | ||
| 74 | * Creates a server session. The server session can have an optional HLE handler, | ||
| 75 | * which will be invoked to handle the IPC requests that this session receives. | ||
| 76 | * @param name Optional name of the server session. | ||
| 77 | * @param hle_handler Optional HLE handler for this server session. | ||
| 78 | * @return The created server session | ||
| 79 | */ | ||
| 80 | static ResultVal<SharedPtr<ServerSession>> Create( | ||
| 81 | std::string name = "Unknown", | ||
| 82 | std::shared_ptr<Service::SessionRequestHandler> hle_handler = nullptr); | ||
| 83 | }; | ||
| 84 | |||
| 85 | /** | ||
| 86 | * Performs command buffer translation for an HLE IPC request. | ||
| 87 | * The command buffer from the ServerSession thread's TLS is copied into a | ||
| 88 | * buffer and all descriptors in the buffer are processed. | ||
| 89 | * TODO(Subv): Implement this function, currently we do not support multiple processes running at | ||
| 90 | * once, but once that is implemented we'll need to properly translate all descriptors | ||
| 91 | * in the command buffer. | ||
| 92 | */ | ||
| 93 | ResultCode TranslateHLERequest(ServerSession* server_session); | ||
| 94 | } | ||
diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 8d29117a8..53864a3a7 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h | |||
| @@ -18,6 +18,7 @@ enum class ErrorDescription : u32 { | |||
| 18 | Success = 0, | 18 | Success = 0, |
| 19 | WrongPermission = 46, | 19 | WrongPermission = 46, |
| 20 | OS_InvalidBufferDescriptor = 48, | 20 | OS_InvalidBufferDescriptor = 48, |
| 21 | MaxConnectionsReached = 52, | ||
| 21 | WrongAddress = 53, | 22 | WrongAddress = 53, |
| 22 | FS_ArchiveNotMounted = 101, | 23 | FS_ArchiveNotMounted = 101, |
| 23 | FS_FileNotFound = 112, | 24 | FS_FileNotFound = 112, |
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h index e6a8be870..80325361f 100644 --- a/src/core/hle/service/apt/apt.h +++ b/src/core/hle/service/apt/apt.h | |||
| @@ -14,6 +14,9 @@ class Interface; | |||
| 14 | 14 | ||
| 15 | namespace APT { | 15 | namespace APT { |
| 16 | 16 | ||
| 17 | /// Each APT service can only have up to 2 sessions connected at the same time. | ||
| 18 | static const u32 MaxAPTSessions = 2; | ||
| 19 | |||
| 17 | /// Holds information about the parameters used in Send/Glance/ReceiveParameter | 20 | /// Holds information about the parameters used in Send/Glance/ReceiveParameter |
| 18 | struct MessageParameter { | 21 | struct MessageParameter { |
| 19 | u32 sender_id = 0; | 22 | u32 sender_id = 0; |
diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp index 6e35e1d29..62dc2d61d 100644 --- a/src/core/hle/service/apt/apt_a.cpp +++ b/src/core/hle/service/apt/apt_a.cpp | |||
| @@ -102,7 +102,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 102 | {0x01050100, nullptr, "IsTitleAllowed"}, | 102 | {0x01050100, nullptr, "IsTitleAllowed"}, |
| 103 | }; | 103 | }; |
| 104 | 104 | ||
| 105 | APT_A_Interface::APT_A_Interface() { | 105 | APT_A_Interface::APT_A_Interface() : Interface(MaxAPTSessions) { |
| 106 | Register(FunctionTable); | 106 | Register(FunctionTable); |
| 107 | } | 107 | } |
| 108 | 108 | ||
diff --git a/src/core/hle/service/apt/apt_s.cpp b/src/core/hle/service/apt/apt_s.cpp index 84019e6e5..effd23dce 100644 --- a/src/core/hle/service/apt/apt_s.cpp +++ b/src/core/hle/service/apt/apt_s.cpp | |||
| @@ -102,7 +102,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 102 | {0x01050100, nullptr, "IsTitleAllowed"}, | 102 | {0x01050100, nullptr, "IsTitleAllowed"}, |
| 103 | }; | 103 | }; |
| 104 | 104 | ||
| 105 | APT_S_Interface::APT_S_Interface() { | 105 | APT_S_Interface::APT_S_Interface() : Interface(MaxAPTSessions) { |
| 106 | Register(FunctionTable); | 106 | Register(FunctionTable); |
| 107 | } | 107 | } |
| 108 | 108 | ||
diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp index a731c39f6..e06084a1e 100644 --- a/src/core/hle/service/apt/apt_u.cpp +++ b/src/core/hle/service/apt/apt_u.cpp | |||
| @@ -99,7 +99,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 99 | {0x01020000, CheckNew3DS, "CheckNew3DS"}, | 99 | {0x01020000, CheckNew3DS, "CheckNew3DS"}, |
| 100 | }; | 100 | }; |
| 101 | 101 | ||
| 102 | APT_U_Interface::APT_U_Interface() { | 102 | APT_U_Interface::APT_U_Interface() : Interface(MaxAPTSessions) { |
| 103 | Register(FunctionTable); | 103 | Register(FunctionTable); |
| 104 | } | 104 | } |
| 105 | 105 | ||
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index bef75f5df..f21934108 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include "core/file_sys/directory_backend.h" | 24 | #include "core/file_sys/directory_backend.h" |
| 25 | #include "core/file_sys/file_backend.h" | 25 | #include "core/file_sys/file_backend.h" |
| 26 | #include "core/hle/hle.h" | 26 | #include "core/hle/hle.h" |
| 27 | #include "core/hle/kernel/client_session.h" | ||
| 27 | #include "core/hle/result.h" | 28 | #include "core/hle/result.h" |
| 28 | #include "core/hle/service/fs/archive.h" | 29 | #include "core/hle/service/fs/archive.h" |
| 29 | #include "core/hle/service/fs/fs_user.h" | 30 | #include "core/hle/service/fs/fs_user.h" |
| @@ -93,7 +94,7 @@ File::File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& | |||
| 93 | 94 | ||
| 94 | File::~File() {} | 95 | File::~File() {} |
| 95 | 96 | ||
| 96 | ResultVal<bool> File::SyncRequest() { | 97 | void File::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) { |
| 97 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 98 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 98 | FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); | 99 | FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); |
| 99 | switch (cmd) { | 100 | switch (cmd) { |
| @@ -116,7 +117,7 @@ ResultVal<bool> File::SyncRequest() { | |||
| 116 | ResultVal<size_t> read = backend->Read(offset, data.size(), data.data()); | 117 | ResultVal<size_t> read = backend->Read(offset, data.size(), data.data()); |
| 117 | if (read.Failed()) { | 118 | if (read.Failed()) { |
| 118 | cmd_buff[1] = read.Code().raw; | 119 | cmd_buff[1] = read.Code().raw; |
| 119 | return read.Code(); | 120 | return; |
| 120 | } | 121 | } |
| 121 | Memory::WriteBlock(address, data.data(), *read); | 122 | Memory::WriteBlock(address, data.data(), *read); |
| 122 | cmd_buff[2] = static_cast<u32>(*read); | 123 | cmd_buff[2] = static_cast<u32>(*read); |
| @@ -137,7 +138,7 @@ ResultVal<bool> File::SyncRequest() { | |||
| 137 | ResultVal<size_t> written = backend->Write(offset, data.size(), flush != 0, data.data()); | 138 | ResultVal<size_t> written = backend->Write(offset, data.size(), flush != 0, data.data()); |
| 138 | if (written.Failed()) { | 139 | if (written.Failed()) { |
| 139 | cmd_buff[1] = written.Code().raw; | 140 | cmd_buff[1] = written.Code().raw; |
| 140 | return written.Code(); | 141 | return; |
| 141 | } | 142 | } |
| 142 | cmd_buff[2] = static_cast<u32>(*written); | 143 | cmd_buff[2] = static_cast<u32>(*written); |
| 143 | break; | 144 | break; |
| @@ -173,7 +174,11 @@ ResultVal<bool> File::SyncRequest() { | |||
| 173 | 174 | ||
| 174 | case FileCommand::OpenLinkFile: { | 175 | case FileCommand::OpenLinkFile: { |
| 175 | LOG_WARNING(Service_FS, "(STUBBED) File command OpenLinkFile %s", GetName().c_str()); | 176 | LOG_WARNING(Service_FS, "(STUBBED) File command OpenLinkFile %s", GetName().c_str()); |
| 176 | cmd_buff[3] = Kernel::g_handle_table.Create(this).ValueOr(INVALID_HANDLE); | 177 | auto sessions = Kernel::ServerSession::CreateSessionPair(GetName(), shared_from_this()); |
| 178 | ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); | ||
| 179 | cmd_buff[3] = Kernel::g_handle_table | ||
| 180 | .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)) | ||
| 181 | .ValueOr(INVALID_HANDLE); | ||
| 177 | break; | 182 | break; |
| 178 | } | 183 | } |
| 179 | 184 | ||
| @@ -194,10 +199,9 @@ ResultVal<bool> File::SyncRequest() { | |||
| 194 | LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); | 199 | LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); |
| 195 | ResultCode error = UnimplementedFunction(ErrorModule::FS); | 200 | ResultCode error = UnimplementedFunction(ErrorModule::FS); |
| 196 | cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. | 201 | cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. |
| 197 | return error; | 202 | return; |
| 198 | } | 203 | } |
| 199 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 204 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error |
| 200 | return MakeResult<bool>(false); | ||
| 201 | } | 205 | } |
| 202 | 206 | ||
| 203 | Directory::Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, | 207 | Directory::Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, |
| @@ -206,11 +210,10 @@ Directory::Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, | |||
| 206 | 210 | ||
| 207 | Directory::~Directory() {} | 211 | Directory::~Directory() {} |
| 208 | 212 | ||
| 209 | ResultVal<bool> Directory::SyncRequest() { | 213 | void Directory::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) { |
| 210 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 214 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 211 | DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]); | 215 | DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]); |
| 212 | switch (cmd) { | 216 | switch (cmd) { |
| 213 | |||
| 214 | // Read from directory... | 217 | // Read from directory... |
| 215 | case DirectoryCommand::Read: { | 218 | case DirectoryCommand::Read: { |
| 216 | u32 count = cmd_buff[1]; | 219 | u32 count = cmd_buff[1]; |
| @@ -237,10 +240,9 @@ ResultVal<bool> Directory::SyncRequest() { | |||
| 237 | LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); | 240 | LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); |
| 238 | ResultCode error = UnimplementedFunction(ErrorModule::FS); | 241 | ResultCode error = UnimplementedFunction(ErrorModule::FS); |
| 239 | cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. | 242 | cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. |
| 240 | return MakeResult<bool>(false); | 243 | return; |
| 241 | } | 244 | } |
| 242 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error | 245 | cmd_buff[1] = RESULT_SUCCESS.raw; // No error |
| 243 | return MakeResult<bool>(false); | ||
| 244 | } | 246 | } |
| 245 | 247 | ||
| 246 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 248 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| @@ -307,9 +309,9 @@ ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factor | |||
| 307 | return RESULT_SUCCESS; | 309 | return RESULT_SUCCESS; |
| 308 | } | 310 | } |
| 309 | 311 | ||
| 310 | ResultVal<Kernel::SharedPtr<File>> OpenFileFromArchive(ArchiveHandle archive_handle, | 312 | ResultVal<std::shared_ptr<File>> OpenFileFromArchive(ArchiveHandle archive_handle, |
| 311 | const FileSys::Path& path, | 313 | const FileSys::Path& path, |
| 312 | const FileSys::Mode mode) { | 314 | const FileSys::Mode mode) { |
| 313 | ArchiveBackend* archive = GetArchive(archive_handle); | 315 | ArchiveBackend* archive = GetArchive(archive_handle); |
| 314 | if (archive == nullptr) | 316 | if (archive == nullptr) |
| 315 | return ERR_INVALID_ARCHIVE_HANDLE; | 317 | return ERR_INVALID_ARCHIVE_HANDLE; |
| @@ -318,8 +320,8 @@ ResultVal<Kernel::SharedPtr<File>> OpenFileFromArchive(ArchiveHandle archive_han | |||
| 318 | if (backend.Failed()) | 320 | if (backend.Failed()) |
| 319 | return backend.Code(); | 321 | return backend.Code(); |
| 320 | 322 | ||
| 321 | auto file = Kernel::SharedPtr<File>(new File(backend.MoveFrom(), path)); | 323 | auto file = std::shared_ptr<File>(new File(backend.MoveFrom(), path)); |
| 322 | return MakeResult<Kernel::SharedPtr<File>>(std::move(file)); | 324 | return MakeResult<std::shared_ptr<File>>(std::move(file)); |
| 323 | } | 325 | } |
| 324 | 326 | ||
| 325 | ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { | 327 | ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { |
| @@ -398,8 +400,8 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, | |||
| 398 | } | 400 | } |
| 399 | } | 401 | } |
| 400 | 402 | ||
| 401 | ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle, | 403 | ResultVal<std::shared_ptr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle, |
| 402 | const FileSys::Path& path) { | 404 | const FileSys::Path& path) { |
| 403 | ArchiveBackend* archive = GetArchive(archive_handle); | 405 | ArchiveBackend* archive = GetArchive(archive_handle); |
| 404 | if (archive == nullptr) | 406 | if (archive == nullptr) |
| 405 | return ERR_INVALID_ARCHIVE_HANDLE; | 407 | return ERR_INVALID_ARCHIVE_HANDLE; |
| @@ -408,8 +410,8 @@ ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle a | |||
| 408 | if (backend.Failed()) | 410 | if (backend.Failed()) |
| 409 | return backend.Code(); | 411 | return backend.Code(); |
| 410 | 412 | ||
| 411 | auto directory = Kernel::SharedPtr<Directory>(new Directory(backend.MoveFrom(), path)); | 413 | auto directory = std::shared_ptr<Directory>(new Directory(backend.MoveFrom(), path)); |
| 412 | return MakeResult<Kernel::SharedPtr<Directory>>(std::move(directory)); | 414 | return MakeResult<std::shared_ptr<Directory>>(std::move(directory)); |
| 413 | } | 415 | } |
| 414 | 416 | ||
| 415 | ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle) { | 417 | ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle) { |
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index 87089bd92..7ba62ede0 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h | |||
| @@ -8,7 +8,7 @@ | |||
| 8 | #include <string> | 8 | #include <string> |
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "core/file_sys/archive_backend.h" | 10 | #include "core/file_sys/archive_backend.h" |
| 11 | #include "core/hle/kernel/session.h" | 11 | #include "core/hle/kernel/server_session.h" |
| 12 | #include "core/hle/result.h" | 12 | #include "core/hle/result.h" |
| 13 | 13 | ||
| 14 | namespace FileSys { | 14 | namespace FileSys { |
| @@ -43,33 +43,37 @@ enum class MediaType : u32 { NAND = 0, SDMC = 1, GameCard = 2 }; | |||
| 43 | 43 | ||
| 44 | typedef u64 ArchiveHandle; | 44 | typedef u64 ArchiveHandle; |
| 45 | 45 | ||
| 46 | class File : public Kernel::Session { | 46 | class File final : public SessionRequestHandler, public std::enable_shared_from_this<File> { |
| 47 | public: | 47 | public: |
| 48 | File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path); | 48 | File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path); |
| 49 | ~File(); | 49 | ~File(); |
| 50 | 50 | ||
| 51 | std::string GetName() const override { | 51 | std::string GetName() const { |
| 52 | return "Path: " + path.DebugStr(); | 52 | return "Path: " + path.DebugStr(); |
| 53 | } | 53 | } |
| 54 | ResultVal<bool> SyncRequest() override; | ||
| 55 | 54 | ||
| 56 | FileSys::Path path; ///< Path of the file | 55 | FileSys::Path path; ///< Path of the file |
| 57 | u32 priority; ///< Priority of the file. TODO(Subv): Find out what this means | 56 | u32 priority; ///< Priority of the file. TODO(Subv): Find out what this means |
| 58 | std::unique_ptr<FileSys::FileBackend> backend; ///< File backend interface | 57 | std::unique_ptr<FileSys::FileBackend> backend; ///< File backend interface |
| 58 | |||
| 59 | protected: | ||
| 60 | void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) override; | ||
| 59 | }; | 61 | }; |
| 60 | 62 | ||
| 61 | class Directory : public Kernel::Session { | 63 | class Directory final : public SessionRequestHandler { |
| 62 | public: | 64 | public: |
| 63 | Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path); | 65 | Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path); |
| 64 | ~Directory(); | 66 | ~Directory(); |
| 65 | 67 | ||
| 66 | std::string GetName() const override { | 68 | std::string GetName() const { |
| 67 | return "Directory: " + path.DebugStr(); | 69 | return "Directory: " + path.DebugStr(); |
| 68 | } | 70 | } |
| 69 | ResultVal<bool> SyncRequest() override; | ||
| 70 | 71 | ||
| 71 | FileSys::Path path; ///< Path of the directory | 72 | FileSys::Path path; ///< Path of the directory |
| 72 | std::unique_ptr<FileSys::DirectoryBackend> backend; ///< File backend interface | 73 | std::unique_ptr<FileSys::DirectoryBackend> backend; ///< File backend interface |
| 74 | |||
| 75 | protected: | ||
| 76 | void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) override; | ||
| 73 | }; | 77 | }; |
| 74 | 78 | ||
| 75 | /** | 79 | /** |
| @@ -99,11 +103,11 @@ ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factor | |||
| 99 | * @param archive_handle Handle to an open Archive object | 103 | * @param archive_handle Handle to an open Archive object |
| 100 | * @param path Path to the File inside of the Archive | 104 | * @param path Path to the File inside of the Archive |
| 101 | * @param mode Mode under which to open the File | 105 | * @param mode Mode under which to open the File |
| 102 | * @return The opened File object as a Session | 106 | * @return The opened File object |
| 103 | */ | 107 | */ |
| 104 | ResultVal<Kernel::SharedPtr<File>> OpenFileFromArchive(ArchiveHandle archive_handle, | 108 | ResultVal<std::shared_ptr<File>> OpenFileFromArchive(ArchiveHandle archive_handle, |
| 105 | const FileSys::Path& path, | 109 | const FileSys::Path& path, |
| 106 | const FileSys::Mode mode); | 110 | const FileSys::Mode mode); |
| 107 | 111 | ||
| 108 | /** | 112 | /** |
| 109 | * Delete a File from an Archive | 113 | * Delete a File from an Archive |
| @@ -178,10 +182,10 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, | |||
| 178 | * Open a Directory from an Archive | 182 | * Open a Directory from an Archive |
| 179 | * @param archive_handle Handle to an open Archive object | 183 | * @param archive_handle Handle to an open Archive object |
| 180 | * @param path Path to the Directory inside of the Archive | 184 | * @param path Path to the Directory inside of the Archive |
| 181 | * @return The opened Directory object as a Session | 185 | * @return The opened Directory object |
| 182 | */ | 186 | */ |
| 183 | ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle, | 187 | ResultVal<std::shared_ptr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle, |
| 184 | const FileSys::Path& path); | 188 | const FileSys::Path& path); |
| 185 | 189 | ||
| 186 | /** | 190 | /** |
| 187 | * Get the free space in an Archive | 191 | * Get the free space in an Archive |
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index d6ab5b065..337da1387 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | #include "common/scope_exit.h" | 9 | #include "common/scope_exit.h" |
| 10 | #include "common/string_util.h" | 10 | #include "common/string_util.h" |
| 11 | #include "core/hle/kernel/client_session.h" | ||
| 11 | #include "core/hle/result.h" | 12 | #include "core/hle/result.h" |
| 12 | #include "core/hle/service/fs/archive.h" | 13 | #include "core/hle/service/fs/archive.h" |
| 13 | #include "core/hle/service/fs/fs_user.h" | 14 | #include "core/hle/service/fs/fs_user.h" |
| @@ -17,7 +18,7 @@ | |||
| 17 | // Namespace FS_User | 18 | // Namespace FS_User |
| 18 | 19 | ||
| 19 | using Kernel::SharedPtr; | 20 | using Kernel::SharedPtr; |
| 20 | using Kernel::Session; | 21 | using Kernel::ServerSession; |
| 21 | 22 | ||
| 22 | namespace Service { | 23 | namespace Service { |
| 23 | namespace FS { | 24 | namespace FS { |
| @@ -67,10 +68,16 @@ static void OpenFile(Service::Interface* self) { | |||
| 67 | LOG_DEBUG(Service_FS, "path=%s, mode=%u attrs=%u", file_path.DebugStr().c_str(), mode.hex, | 68 | LOG_DEBUG(Service_FS, "path=%s, mode=%u attrs=%u", file_path.DebugStr().c_str(), mode.hex, |
| 68 | attributes); | 69 | attributes); |
| 69 | 70 | ||
| 70 | ResultVal<SharedPtr<File>> file_res = OpenFileFromArchive(archive_handle, file_path, mode); | 71 | ResultVal<std::shared_ptr<File>> file_res = |
| 72 | OpenFileFromArchive(archive_handle, file_path, mode); | ||
| 71 | cmd_buff[1] = file_res.Code().raw; | 73 | cmd_buff[1] = file_res.Code().raw; |
| 72 | if (file_res.Succeeded()) { | 74 | if (file_res.Succeeded()) { |
| 73 | cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom(); | 75 | std::shared_ptr<File> file = *file_res; |
| 76 | auto sessions = ServerSession::CreateSessionPair(file->GetName(), file); | ||
| 77 | file->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); | ||
| 78 | cmd_buff[3] = Kernel::g_handle_table | ||
| 79 | .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)) | ||
| 80 | .MoveFrom(); | ||
| 74 | } else { | 81 | } else { |
| 75 | cmd_buff[3] = 0; | 82 | cmd_buff[3] = 0; |
| 76 | LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); | 83 | LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); |
| @@ -127,10 +134,16 @@ static void OpenFileDirectly(Service::Interface* self) { | |||
| 127 | } | 134 | } |
| 128 | SCOPE_EXIT({ CloseArchive(*archive_handle); }); | 135 | SCOPE_EXIT({ CloseArchive(*archive_handle); }); |
| 129 | 136 | ||
| 130 | ResultVal<SharedPtr<File>> file_res = OpenFileFromArchive(*archive_handle, file_path, mode); | 137 | ResultVal<std::shared_ptr<File>> file_res = |
| 138 | OpenFileFromArchive(*archive_handle, file_path, mode); | ||
| 131 | cmd_buff[1] = file_res.Code().raw; | 139 | cmd_buff[1] = file_res.Code().raw; |
| 132 | if (file_res.Succeeded()) { | 140 | if (file_res.Succeeded()) { |
| 133 | cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom(); | 141 | std::shared_ptr<File> file = *file_res; |
| 142 | auto sessions = ServerSession::CreateSessionPair(file->GetName(), file); | ||
| 143 | file->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); | ||
| 144 | cmd_buff[3] = Kernel::g_handle_table | ||
| 145 | .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)) | ||
| 146 | .MoveFrom(); | ||
| 134 | } else { | 147 | } else { |
| 135 | cmd_buff[3] = 0; | 148 | cmd_buff[3] = 0; |
| 136 | LOG_ERROR(Service_FS, "failed to get a handle for file %s mode=%u attributes=%u", | 149 | LOG_ERROR(Service_FS, "failed to get a handle for file %s mode=%u attributes=%u", |
| @@ -388,10 +401,16 @@ static void OpenDirectory(Service::Interface* self) { | |||
| 388 | LOG_DEBUG(Service_FS, "type=%u size=%u data=%s", static_cast<u32>(dirname_type), dirname_size, | 401 | LOG_DEBUG(Service_FS, "type=%u size=%u data=%s", static_cast<u32>(dirname_type), dirname_size, |
| 389 | dir_path.DebugStr().c_str()); | 402 | dir_path.DebugStr().c_str()); |
| 390 | 403 | ||
| 391 | ResultVal<SharedPtr<Directory>> dir_res = OpenDirectoryFromArchive(archive_handle, dir_path); | 404 | ResultVal<std::shared_ptr<Directory>> dir_res = |
| 405 | OpenDirectoryFromArchive(archive_handle, dir_path); | ||
| 392 | cmd_buff[1] = dir_res.Code().raw; | 406 | cmd_buff[1] = dir_res.Code().raw; |
| 393 | if (dir_res.Succeeded()) { | 407 | if (dir_res.Succeeded()) { |
| 394 | cmd_buff[3] = Kernel::g_handle_table.Create(*dir_res).MoveFrom(); | 408 | std::shared_ptr<Directory> directory = *dir_res; |
| 409 | auto sessions = ServerSession::CreateSessionPair(directory->GetName(), directory); | ||
| 410 | directory->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions)); | ||
| 411 | cmd_buff[3] = Kernel::g_handle_table | ||
| 412 | .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions)) | ||
| 413 | .MoveFrom(); | ||
| 395 | } else { | 414 | } else { |
| 396 | LOG_ERROR(Service_FS, "failed to get a handle for directory type=%d size=%d data=%s", | 415 | LOG_ERROR(Service_FS, "failed to get a handle for directory type=%d size=%d data=%s", |
| 397 | dirname_type, dirname_size, dir_path.DebugStr().c_str()); | 416 | dirname_type, dirname_size, dir_path.DebugStr().c_str()); |
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index effecc043..2bc3fdc82 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp | |||
| @@ -2,8 +2,12 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <boost/range/algorithm_ext/erase.hpp> | ||
| 6 | |||
| 5 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| 6 | #include "common/string_util.h" | 8 | #include "common/string_util.h" |
| 9 | |||
| 10 | #include "core/hle/kernel/server_port.h" | ||
| 7 | #include "core/hle/service/ac_u.h" | 11 | #include "core/hle/service/ac_u.h" |
| 8 | #include "core/hle/service/act_a.h" | 12 | #include "core/hle/service/act_a.h" |
| 9 | #include "core/hle/service/act_u.h" | 13 | #include "core/hle/service/act_u.h" |
| @@ -44,8 +48,8 @@ | |||
| 44 | 48 | ||
| 45 | namespace Service { | 49 | namespace Service { |
| 46 | 50 | ||
| 47 | std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_ports; | 51 | std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports; |
| 48 | std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services; | 52 | std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_srv_services; |
| 49 | 53 | ||
| 50 | /** | 54 | /** |
| 51 | * Creates a function string for logging, complete with the name (or header code, depending | 55 | * Creates a function string for logging, complete with the name (or header code, depending |
| @@ -64,7 +68,23 @@ static std::string MakeFunctionString(const char* name, const char* port_name, | |||
| 64 | return function_string; | 68 | return function_string; |
| 65 | } | 69 | } |
| 66 | 70 | ||
| 67 | ResultVal<bool> Interface::SyncRequest() { | 71 | void SessionRequestHandler::ClientConnected( |
| 72 | Kernel::SharedPtr<Kernel::ServerSession> server_session) { | ||
| 73 | connected_sessions.push_back(server_session); | ||
| 74 | } | ||
| 75 | |||
| 76 | void SessionRequestHandler::ClientDisconnected( | ||
| 77 | Kernel::SharedPtr<Kernel::ServerSession> server_session) { | ||
| 78 | boost::range::remove_erase(connected_sessions, server_session); | ||
| 79 | } | ||
| 80 | |||
| 81 | Interface::Interface(u32 max_sessions) : max_sessions(max_sessions) {} | ||
| 82 | Interface::~Interface() = default; | ||
| 83 | |||
| 84 | void Interface::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) { | ||
| 85 | // TODO(Subv): Make use of the server_session in the HLE service handlers to distinguish which | ||
| 86 | // session triggered each command. | ||
| 87 | |||
| 68 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 88 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 69 | auto itr = m_functions.find(cmd_buff[0]); | 89 | auto itr = m_functions.find(cmd_buff[0]); |
| 70 | 90 | ||
| @@ -78,14 +98,12 @@ ResultVal<bool> Interface::SyncRequest() { | |||
| 78 | 98 | ||
| 79 | // TODO(bunnei): Hack - ignore error | 99 | // TODO(bunnei): Hack - ignore error |
| 80 | cmd_buff[1] = 0; | 100 | cmd_buff[1] = 0; |
| 81 | return MakeResult<bool>(false); | 101 | return; |
| 82 | } | 102 | } |
| 83 | LOG_TRACE(Service, "%s", | 103 | LOG_TRACE(Service, "%s", |
| 84 | MakeFunctionString(itr->second.name, GetPortName().c_str(), cmd_buff).c_str()); | 104 | MakeFunctionString(itr->second.name, GetPortName().c_str(), cmd_buff).c_str()); |
| 85 | 105 | ||
| 86 | itr->second.func(this); | 106 | itr->second.func(this); |
| 87 | |||
| 88 | return MakeResult<bool>(false); // TODO: Implement return from actual function | ||
| 89 | } | 107 | } |
| 90 | 108 | ||
| 91 | void Interface::Register(const FunctionInfo* functions, size_t n) { | 109 | void Interface::Register(const FunctionInfo* functions, size_t n) { |
| @@ -100,11 +118,19 @@ void Interface::Register(const FunctionInfo* functions, size_t n) { | |||
| 100 | // Module interface | 118 | // Module interface |
| 101 | 119 | ||
| 102 | static void AddNamedPort(Interface* interface_) { | 120 | static void AddNamedPort(Interface* interface_) { |
| 103 | g_kernel_named_ports.emplace(interface_->GetPortName(), interface_); | 121 | auto ports = |
| 122 | Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(), | ||
| 123 | std::shared_ptr<Interface>(interface_)); | ||
| 124 | auto client_port = std::get<Kernel::SharedPtr<Kernel::ClientPort>>(ports); | ||
| 125 | g_kernel_named_ports.emplace(interface_->GetPortName(), std::move(client_port)); | ||
| 104 | } | 126 | } |
| 105 | 127 | ||
| 106 | void AddService(Interface* interface_) { | 128 | void AddService(Interface* interface_) { |
| 107 | g_srv_services.emplace(interface_->GetPortName(), interface_); | 129 | auto ports = |
| 130 | Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(), | ||
| 131 | std::shared_ptr<Interface>(interface_)); | ||
| 132 | auto client_port = std::get<Kernel::SharedPtr<Kernel::ClientPort>>(ports); | ||
| 133 | g_srv_services.emplace(interface_->GetPortName(), std::move(client_port)); | ||
| 108 | } | 134 | } |
| 109 | 135 | ||
| 110 | /// Initialize ServiceManager | 136 | /// Initialize ServiceManager |
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 29daacfc4..a7ba7688f 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h | |||
| @@ -9,8 +9,15 @@ | |||
| 9 | #include <unordered_map> | 9 | #include <unordered_map> |
| 10 | #include <boost/container/flat_map.hpp> | 10 | #include <boost/container/flat_map.hpp> |
| 11 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | #include "core/hle/kernel/session.h" | 12 | #include "core/hle/ipc.h" |
| 13 | #include "core/hle/kernel/client_port.h" | ||
| 14 | #include "core/hle/kernel/thread.h" | ||
| 13 | #include "core/hle/result.h" | 15 | #include "core/hle/result.h" |
| 16 | #include "core/memory.h" | ||
| 17 | |||
| 18 | namespace Kernel { | ||
| 19 | class ServerSession; | ||
| 20 | } | ||
| 14 | 21 | ||
| 15 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 22 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 16 | // Namespace Service | 23 | // Namespace Service |
| @@ -18,14 +25,63 @@ | |||
| 18 | namespace Service { | 25 | namespace Service { |
| 19 | 26 | ||
| 20 | static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters) | 27 | static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters) |
| 28 | /// Arbitrary default number of maximum connections to an HLE service. | ||
| 29 | static const u32 DefaultMaxSessions = 10; | ||
| 30 | |||
| 31 | /** | ||
| 32 | * Interface implemented by HLE Session handlers. | ||
| 33 | * This can be provided to a ServerSession in order to hook into several relevant events | ||
| 34 | * (such as a new connection or a SyncRequest) so they can be implemented in the emulator. | ||
| 35 | */ | ||
| 36 | class SessionRequestHandler { | ||
| 37 | public: | ||
| 38 | /** | ||
| 39 | * Handles a sync request from the emulated application. | ||
| 40 | * @param server_session The ServerSession that was triggered for this sync request, | ||
| 41 | * it should be used to differentiate which client (As in ClientSession) we're answering to. | ||
| 42 | * TODO(Subv): Use a wrapper structure to hold all the information relevant to | ||
| 43 | * this request (ServerSession, Originator thread, Translated command buffer, etc). | ||
| 44 | * @returns ResultCode the result code of the translate operation. | ||
| 45 | */ | ||
| 46 | virtual void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) = 0; | ||
| 47 | |||
| 48 | /** | ||
| 49 | * Signals that a client has just connected to this HLE handler and keeps the | ||
| 50 | * associated ServerSession alive for the duration of the connection. | ||
| 51 | * @param server_session Owning pointer to the ServerSession associated with the connection. | ||
| 52 | */ | ||
| 53 | void ClientConnected(Kernel::SharedPtr<Kernel::ServerSession> server_session); | ||
| 54 | |||
| 55 | /** | ||
| 56 | * Signals that a client has just disconnected from this HLE handler and releases the | ||
| 57 | * associated ServerSession. | ||
| 58 | * @param server_session ServerSession associated with the connection. | ||
| 59 | */ | ||
| 60 | void ClientDisconnected(Kernel::SharedPtr<Kernel::ServerSession> server_session); | ||
| 21 | 61 | ||
| 22 | /// Interface to a CTROS service | 62 | protected: |
| 23 | class Interface : public Kernel::Session { | 63 | /// List of sessions that are connected to this handler. |
| 24 | // TODO(yuriks): An "Interface" being a Kernel::Object is mostly non-sense. Interface should be | 64 | /// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list |
| 25 | // just something that encapsulates a session and acts as a helper to implement service | 65 | // for the duration of the connection. |
| 26 | // processes. | 66 | std::vector<Kernel::SharedPtr<Kernel::ServerSession>> connected_sessions; |
| 67 | }; | ||
| 68 | |||
| 69 | /** | ||
| 70 | * Framework for implementing HLE service handlers which dispatch incoming SyncRequests based on a | ||
| 71 | * table mapping header ids to handler functions. | ||
| 72 | */ | ||
| 73 | class Interface : public SessionRequestHandler { | ||
| 27 | public: | 74 | public: |
| 28 | std::string GetName() const override { | 75 | /** |
| 76 | * Creates an HLE interface with the specified max sessions. | ||
| 77 | * @param max_sessions Maximum number of sessions that can be | ||
| 78 | * connected to this service at the same time. | ||
| 79 | */ | ||
| 80 | Interface(u32 max_sessions = DefaultMaxSessions); | ||
| 81 | |||
| 82 | virtual ~Interface(); | ||
| 83 | |||
| 84 | std::string GetName() const { | ||
| 29 | return GetPortName(); | 85 | return GetPortName(); |
| 30 | } | 86 | } |
| 31 | 87 | ||
| @@ -33,6 +89,15 @@ public: | |||
| 33 | version.raw = raw_version; | 89 | version.raw = raw_version; |
| 34 | } | 90 | } |
| 35 | 91 | ||
| 92 | /** | ||
| 93 | * Gets the maximum allowed number of sessions that can be connected to this service | ||
| 94 | * at the same time. | ||
| 95 | * @returns The maximum number of connections allowed. | ||
| 96 | */ | ||
| 97 | u32 GetMaxSessions() const { | ||
| 98 | return max_sessions; | ||
| 99 | } | ||
| 100 | |||
| 36 | typedef void (*Function)(Interface*); | 101 | typedef void (*Function)(Interface*); |
| 37 | 102 | ||
| 38 | struct FunctionInfo { | 103 | struct FunctionInfo { |
| @@ -49,9 +114,9 @@ public: | |||
| 49 | return "[UNKNOWN SERVICE PORT]"; | 114 | return "[UNKNOWN SERVICE PORT]"; |
| 50 | } | 115 | } |
| 51 | 116 | ||
| 52 | ResultVal<bool> SyncRequest() override; | ||
| 53 | |||
| 54 | protected: | 117 | protected: |
| 118 | void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) override; | ||
| 119 | |||
| 55 | /** | 120 | /** |
| 56 | * Registers the functions in the service | 121 | * Registers the functions in the service |
| 57 | */ | 122 | */ |
| @@ -71,6 +136,7 @@ protected: | |||
| 71 | } version = {}; | 136 | } version = {}; |
| 72 | 137 | ||
| 73 | private: | 138 | private: |
| 139 | u32 max_sessions; ///< Maximum number of concurrent sessions that this service can handle. | ||
| 74 | boost::container::flat_map<u32, FunctionInfo> m_functions; | 140 | boost::container::flat_map<u32, FunctionInfo> m_functions; |
| 75 | }; | 141 | }; |
| 76 | 142 | ||
| @@ -81,9 +147,9 @@ void Init(); | |||
| 81 | void Shutdown(); | 147 | void Shutdown(); |
| 82 | 148 | ||
| 83 | /// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort SVC. | 149 | /// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort SVC. |
| 84 | extern std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_ports; | 150 | extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports; |
| 85 | /// Map of services registered with the "srv:" service, retrieved using GetServiceHandle. | 151 | /// Map of services registered with the "srv:" service, retrieved using GetServiceHandle. |
| 86 | extern std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services; | 152 | extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_srv_services; |
| 87 | 153 | ||
| 88 | /// Adds a service to the services table | 154 | /// Adds a service to the services table |
| 89 | void AddService(Interface* interface_); | 155 | void AddService(Interface* interface_); |
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp index fd251fc0a..c3918cdd0 100644 --- a/src/core/hle/service/soc_u.cpp +++ b/src/core/hle/service/soc_u.cpp | |||
| @@ -11,7 +11,7 @@ | |||
| 11 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | #include "common/logging/log.h" | 12 | #include "common/logging/log.h" |
| 13 | #include "common/scope_exit.h" | 13 | #include "common/scope_exit.h" |
| 14 | #include "core/hle/kernel/session.h" | 14 | #include "core/hle/kernel/server_session.h" |
| 15 | #include "core/hle/result.h" | 15 | #include "core/hle/result.h" |
| 16 | #include "core/hle/service/soc_u.h" | 16 | #include "core/hle/service/soc_u.h" |
| 17 | #include "core/memory.h" | 17 | #include "core/memory.h" |
diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index f8df38c42..3bd787147 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp | |||
| @@ -2,9 +2,13 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <tuple> | ||
| 6 | |||
| 5 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 6 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | #include "core/hle/kernel/client_session.h" | ||
| 7 | #include "core/hle/kernel/event.h" | 10 | #include "core/hle/kernel/event.h" |
| 11 | #include "core/hle/kernel/server_session.h" | ||
| 8 | #include "core/hle/service/srv.h" | 12 | #include "core/hle/service/srv.h" |
| 9 | 13 | ||
| 10 | namespace Service { | 14 | namespace Service { |
| @@ -79,7 +83,15 @@ static void GetServiceHandle(Interface* self) { | |||
| 79 | auto it = Service::g_srv_services.find(port_name); | 83 | auto it = Service::g_srv_services.find(port_name); |
| 80 | 84 | ||
| 81 | if (it != Service::g_srv_services.end()) { | 85 | if (it != Service::g_srv_services.end()) { |
| 82 | cmd_buff[3] = Kernel::g_handle_table.Create(it->second).MoveFrom(); | 86 | auto client_port = it->second; |
| 87 | |||
| 88 | auto client_session = client_port->Connect(); | ||
| 89 | res = client_session.Code(); | ||
| 90 | |||
| 91 | if (client_session.Succeeded()) { | ||
| 92 | // Return the client session | ||
| 93 | cmd_buff[3] = Kernel::g_handle_table.Create(*client_session).MoveFrom(); | ||
| 94 | } | ||
| 83 | LOG_TRACE(Service_SRV, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]); | 95 | LOG_TRACE(Service_SRV, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]); |
| 84 | } else { | 96 | } else { |
| 85 | LOG_ERROR(Service_SRV, "(UNIMPLEMENTED) called port=%s", port_name.c_str()); | 97 | LOG_ERROR(Service_SRV, "(UNIMPLEMENTED) called port=%s", port_name.c_str()); |
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index c6b80dc50..e5ba9a484 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include "core/hle/function_wrappers.h" | 13 | #include "core/hle/function_wrappers.h" |
| 14 | #include "core/hle/kernel/address_arbiter.h" | 14 | #include "core/hle/kernel/address_arbiter.h" |
| 15 | #include "core/hle/kernel/client_port.h" | 15 | #include "core/hle/kernel/client_port.h" |
| 16 | #include "core/hle/kernel/client_session.h" | ||
| 16 | #include "core/hle/kernel/event.h" | 17 | #include "core/hle/kernel/event.h" |
| 17 | #include "core/hle/kernel/memory.h" | 18 | #include "core/hle/kernel/memory.h" |
| 18 | #include "core/hle/kernel/mutex.h" | 19 | #include "core/hle/kernel/mutex.h" |
| @@ -20,6 +21,7 @@ | |||
| 20 | #include "core/hle/kernel/resource_limit.h" | 21 | #include "core/hle/kernel/resource_limit.h" |
| 21 | #include "core/hle/kernel/semaphore.h" | 22 | #include "core/hle/kernel/semaphore.h" |
| 22 | #include "core/hle/kernel/server_port.h" | 23 | #include "core/hle/kernel/server_port.h" |
| 24 | #include "core/hle/kernel/server_session.h" | ||
| 23 | #include "core/hle/kernel/shared_memory.h" | 25 | #include "core/hle/kernel/shared_memory.h" |
| 24 | #include "core/hle/kernel/thread.h" | 26 | #include "core/hle/kernel/thread.h" |
| 25 | #include "core/hle/kernel/timer.h" | 27 | #include "core/hle/kernel/timer.h" |
| @@ -222,20 +224,29 @@ static ResultCode ConnectToPort(Handle* out_handle, const char* port_name) { | |||
| 222 | return ERR_NOT_FOUND; | 224 | return ERR_NOT_FOUND; |
| 223 | } | 225 | } |
| 224 | 226 | ||
| 225 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(it->second)); | 227 | auto client_port = it->second; |
| 228 | |||
| 229 | SharedPtr<Kernel::ClientSession> client_session; | ||
| 230 | CASCADE_RESULT(client_session, client_port->Connect()); | ||
| 231 | |||
| 232 | // Return the client session | ||
| 233 | CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(client_session)); | ||
| 226 | return RESULT_SUCCESS; | 234 | return RESULT_SUCCESS; |
| 227 | } | 235 | } |
| 228 | 236 | ||
| 229 | /// Synchronize to an OS service | 237 | /// Makes a blocking IPC call to an OS service. |
| 230 | static ResultCode SendSyncRequest(Handle handle) { | 238 | static ResultCode SendSyncRequest(Handle handle) { |
| 231 | SharedPtr<Kernel::Session> session = Kernel::g_handle_table.Get<Kernel::Session>(handle); | 239 | SharedPtr<Kernel::ClientSession> session = |
| 240 | Kernel::g_handle_table.Get<Kernel::ClientSession>(handle); | ||
| 232 | if (session == nullptr) { | 241 | if (session == nullptr) { |
| 233 | return ERR_INVALID_HANDLE; | 242 | return ERR_INVALID_HANDLE; |
| 234 | } | 243 | } |
| 235 | 244 | ||
| 236 | LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s)", handle, session->GetName().c_str()); | 245 | LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s)", handle, session->GetName().c_str()); |
| 237 | 246 | ||
| 238 | return session->SyncRequest().Code(); | 247 | // TODO(Subv): svcSendSyncRequest should put the caller thread to sleep while the server |
| 248 | // responds and cause a reschedule. | ||
| 249 | return session->SendSyncRequest(); | ||
| 239 | } | 250 | } |
| 240 | 251 | ||
| 241 | /// Close a handle | 252 | /// Close a handle |