diff options
| author | 2019-11-30 18:56:35 -0500 | |
|---|---|---|
| committer | 2019-11-30 18:56:35 -0500 | |
| commit | 5c7253f8d3c010c0a0e5c91db497819829cb4a43 (patch) | |
| tree | c2aa6989d3f081c07c72c3ab4a698c73ecd8c429 /src/core/hle/kernel | |
| parent | Merge pull request #3184 from ReinUsesLisp/framebuffer-cache (diff) | |
| parent | kernel: Implement a more accurate IPC dispatch. (diff) | |
| download | yuzu-5c7253f8d3c010c0a0e5c91db497819829cb4a43.tar.gz yuzu-5c7253f8d3c010c0a0e5c91db497819829cb4a43.tar.xz yuzu-5c7253f8d3c010c0a0e5c91db497819829cb4a43.zip | |
Merge pull request #3177 from bunnei/new-ipc-req
kernel: Implement a more accurate IPC dispatch.
Diffstat (limited to 'src/core/hle/kernel')
| -rw-r--r-- | src/core/hle/kernel/client_port.cpp | 14 | ||||
| -rw-r--r-- | src/core/hle/kernel/client_session.cpp | 40 | ||||
| -rw-r--r-- | src/core/hle/kernel/client_session.h | 21 | ||||
| -rw-r--r-- | src/core/hle/kernel/hle_ipc.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/hle_ipc.h | 13 | ||||
| -rw-r--r-- | src/core/hle/kernel/object.cpp | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/object.h | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/server_session.cpp | 117 | ||||
| -rw-r--r-- | src/core/hle/kernel/server_session.h | 49 | ||||
| -rw-r--r-- | src/core/hle/kernel/session.cpp | 32 | ||||
| -rw-r--r-- | src/core/hle/kernel/session.h | 57 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 9 |
12 files changed, 214 insertions, 142 deletions
diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index 4637b6017..00bb939a0 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "core/hle/kernel/object.h" | 9 | #include "core/hle/kernel/object.h" |
| 10 | #include "core/hle/kernel/server_port.h" | 10 | #include "core/hle/kernel/server_port.h" |
| 11 | #include "core/hle/kernel/server_session.h" | 11 | #include "core/hle/kernel/server_session.h" |
| 12 | #include "core/hle/kernel/session.h" | ||
| 12 | 13 | ||
| 13 | namespace Kernel { | 14 | namespace Kernel { |
| 14 | 15 | ||
| @@ -20,28 +21,23 @@ std::shared_ptr<ServerPort> ClientPort::GetServerPort() const { | |||
| 20 | } | 21 | } |
| 21 | 22 | ||
| 22 | ResultVal<std::shared_ptr<ClientSession>> ClientPort::Connect() { | 23 | ResultVal<std::shared_ptr<ClientSession>> ClientPort::Connect() { |
| 23 | // Note: Threads do not wait for the server endpoint to call | ||
| 24 | // AcceptSession before returning from this call. | ||
| 25 | |||
| 26 | if (active_sessions >= max_sessions) { | 24 | if (active_sessions >= max_sessions) { |
| 27 | return ERR_MAX_CONNECTIONS_REACHED; | 25 | return ERR_MAX_CONNECTIONS_REACHED; |
| 28 | } | 26 | } |
| 29 | active_sessions++; | 27 | active_sessions++; |
| 30 | 28 | ||
| 31 | // Create a new session pair, let the created sessions inherit the parent port's HLE handler. | 29 | auto [client, server] = Kernel::Session::Create(kernel, name); |
| 32 | auto [server, client] = | ||
| 33 | ServerSession::CreateSessionPair(kernel, server_port->GetName(), SharedFrom(this)); | ||
| 34 | 30 | ||
| 35 | if (server_port->HasHLEHandler()) { | 31 | if (server_port->HasHLEHandler()) { |
| 36 | server_port->GetHLEHandler()->ClientConnected(server); | 32 | server_port->GetHLEHandler()->ClientConnected(std::move(server)); |
| 37 | } else { | 33 | } else { |
| 38 | server_port->AppendPendingSession(server); | 34 | server_port->AppendPendingSession(std::move(server)); |
| 39 | } | 35 | } |
| 40 | 36 | ||
| 41 | // Wake the threads waiting on the ServerPort | 37 | // Wake the threads waiting on the ServerPort |
| 42 | server_port->WakeupAllWaitingThreads(); | 38 | server_port->WakeupAllWaitingThreads(); |
| 43 | 39 | ||
| 44 | return MakeResult(client); | 40 | return MakeResult(std::move(client)); |
| 45 | } | 41 | } |
| 46 | 42 | ||
| 47 | void ClientPort::ConnectionClosed() { | 43 | void ClientPort::ConnectionClosed() { |
diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index 9849dbe91..4669a14ad 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | 1 | // Copyright 2019 yuzu emulator team |
| 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 | ||
| @@ -12,22 +12,44 @@ | |||
| 12 | 12 | ||
| 13 | namespace Kernel { | 13 | namespace Kernel { |
| 14 | 14 | ||
| 15 | ClientSession::ClientSession(KernelCore& kernel) : Object{kernel} {} | 15 | ClientSession::ClientSession(KernelCore& kernel) : WaitObject{kernel} {} |
| 16 | |||
| 16 | ClientSession::~ClientSession() { | 17 | ClientSession::~ClientSession() { |
| 17 | // This destructor will be called automatically when the last ClientSession handle is closed by | 18 | // This destructor will be called automatically when the last ClientSession handle is closed by |
| 18 | // the emulated application. | 19 | // the emulated application. |
| 19 | if (auto server = parent->server.lock()) { | 20 | if (parent->Server()) { |
| 20 | server->ClientDisconnected(); | 21 | parent->Server()->ClientDisconnected(); |
| 21 | } | 22 | } |
| 22 | } | 23 | } |
| 23 | 24 | ||
| 24 | ResultCode ClientSession::SendSyncRequest(Thread* thread, Memory::Memory& memory) { | 25 | bool ClientSession::ShouldWait(const Thread* thread) const { |
| 25 | // Signal the server session that new data is available | 26 | UNIMPLEMENTED(); |
| 26 | if (auto server = parent->server.lock()) { | 27 | return {}; |
| 27 | return server->HandleSyncRequest(SharedFrom(thread), memory); | 28 | } |
| 29 | |||
| 30 | void ClientSession::Acquire(Thread* thread) { | ||
| 31 | UNIMPLEMENTED(); | ||
| 32 | } | ||
| 33 | |||
| 34 | ResultVal<std::shared_ptr<ClientSession>> ClientSession::Create(KernelCore& kernel, | ||
| 35 | std::shared_ptr<Session> parent, | ||
| 36 | std::string name) { | ||
| 37 | std::shared_ptr<ClientSession> client_session{std::make_shared<ClientSession>(kernel)}; | ||
| 38 | |||
| 39 | client_session->name = std::move(name); | ||
| 40 | client_session->parent = std::move(parent); | ||
| 41 | |||
| 42 | return MakeResult(std::move(client_session)); | ||
| 43 | } | ||
| 44 | |||
| 45 | ResultCode ClientSession::SendSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory) { | ||
| 46 | // Keep ServerSession alive until we're done working with it. | ||
| 47 | if (!parent->Server()) { | ||
| 48 | return ERR_SESSION_CLOSED_BY_REMOTE; | ||
| 28 | } | 49 | } |
| 29 | 50 | ||
| 30 | return ERR_SESSION_CLOSED_BY_REMOTE; | 51 | // Signal the server session that new data is available |
| 52 | return parent->Server()->HandleSyncRequest(std::move(thread), memory); | ||
| 31 | } | 53 | } |
| 32 | 54 | ||
| 33 | } // namespace Kernel | 55 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h index 484dd7bc9..b4289a9a8 100644 --- a/src/core/hle/kernel/client_session.h +++ b/src/core/hle/kernel/client_session.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | 1 | // Copyright 2019 yuzu emulator team |
| 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 | ||
| @@ -6,7 +6,9 @@ | |||
| 6 | 6 | ||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <string> | 8 | #include <string> |
| 9 | #include "core/hle/kernel/object.h" | 9 | |
| 10 | #include "core/hle/kernel/wait_object.h" | ||
| 11 | #include "core/hle/result.h" | ||
| 10 | 12 | ||
| 11 | union ResultCode; | 13 | union ResultCode; |
| 12 | 14 | ||
| @@ -18,15 +20,14 @@ namespace Kernel { | |||
| 18 | 20 | ||
| 19 | class KernelCore; | 21 | class KernelCore; |
| 20 | class Session; | 22 | class Session; |
| 21 | class ServerSession; | ||
| 22 | class Thread; | 23 | class Thread; |
| 23 | 24 | ||
| 24 | class ClientSession final : public Object { | 25 | class ClientSession final : public WaitObject { |
| 25 | public: | 26 | public: |
| 26 | explicit ClientSession(KernelCore& kernel); | 27 | explicit ClientSession(KernelCore& kernel); |
| 27 | ~ClientSession() override; | 28 | ~ClientSession() override; |
| 28 | 29 | ||
| 29 | friend class ServerSession; | 30 | friend class Session; |
| 30 | 31 | ||
| 31 | std::string GetTypeName() const override { | 32 | std::string GetTypeName() const override { |
| 32 | return "ClientSession"; | 33 | return "ClientSession"; |
| @@ -41,9 +42,17 @@ public: | |||
| 41 | return HANDLE_TYPE; | 42 | return HANDLE_TYPE; |
| 42 | } | 43 | } |
| 43 | 44 | ||
| 44 | ResultCode SendSyncRequest(Thread* thread, Memory::Memory& memory); | 45 | ResultCode SendSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory); |
| 46 | |||
| 47 | bool ShouldWait(const Thread* thread) const override; | ||
| 48 | |||
| 49 | void Acquire(Thread* thread) override; | ||
| 45 | 50 | ||
| 46 | private: | 51 | private: |
| 52 | static ResultVal<std::shared_ptr<ClientSession>> Create(KernelCore& kernel, | ||
| 53 | std::shared_ptr<Session> parent, | ||
| 54 | std::string name = "Unknown"); | ||
| 55 | |||
| 47 | /// The parent session, which links to the server endpoint. | 56 | /// The parent session, which links to the server endpoint. |
| 48 | std::shared_ptr<Session> parent; | 57 | std::shared_ptr<Session> parent; |
| 49 | 58 | ||
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 8b01567a8..2db28dcf0 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp | |||
| @@ -74,6 +74,8 @@ std::shared_ptr<WritableEvent> HLERequestContext::SleepClientThread( | |||
| 74 | thread->WakeAfterDelay(timeout); | 74 | thread->WakeAfterDelay(timeout); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | is_thread_waiting = true; | ||
| 78 | |||
| 77 | return writable_event; | 79 | return writable_event; |
| 78 | } | 80 | } |
| 79 | 81 | ||
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index dab37ba0d..050ad8fd7 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h | |||
| @@ -264,6 +264,18 @@ public: | |||
| 264 | 264 | ||
| 265 | std::string Description() const; | 265 | std::string Description() const; |
| 266 | 266 | ||
| 267 | Thread& GetThread() { | ||
| 268 | return *thread; | ||
| 269 | } | ||
| 270 | |||
| 271 | const Thread& GetThread() const { | ||
| 272 | return *thread; | ||
| 273 | } | ||
| 274 | |||
| 275 | bool IsThreadWaiting() const { | ||
| 276 | return is_thread_waiting; | ||
| 277 | } | ||
| 278 | |||
| 267 | private: | 279 | private: |
| 268 | void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming); | 280 | void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming); |
| 269 | 281 | ||
| @@ -290,6 +302,7 @@ private: | |||
| 290 | u32_le command{}; | 302 | u32_le command{}; |
| 291 | 303 | ||
| 292 | std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers; | 304 | std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers; |
| 305 | bool is_thread_waiting{}; | ||
| 293 | }; | 306 | }; |
| 294 | 307 | ||
| 295 | } // namespace Kernel | 308 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp index 10431e94c..2c571792b 100644 --- a/src/core/hle/kernel/object.cpp +++ b/src/core/hle/kernel/object.cpp | |||
| @@ -27,6 +27,7 @@ bool Object::IsWaitable() const { | |||
| 27 | case HandleType::ResourceLimit: | 27 | case HandleType::ResourceLimit: |
| 28 | case HandleType::ClientPort: | 28 | case HandleType::ClientPort: |
| 29 | case HandleType::ClientSession: | 29 | case HandleType::ClientSession: |
| 30 | case HandleType::Session: | ||
| 30 | return false; | 31 | return false; |
| 31 | } | 32 | } |
| 32 | 33 | ||
diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h index bbbb4e7cc..e3391e2af 100644 --- a/src/core/hle/kernel/object.h +++ b/src/core/hle/kernel/object.h | |||
| @@ -29,6 +29,7 @@ enum class HandleType : u32 { | |||
| 29 | ServerPort, | 29 | ServerPort, |
| 30 | ClientSession, | 30 | ClientSession, |
| 31 | ServerSession, | 31 | ServerSession, |
| 32 | Session, | ||
| 32 | }; | 33 | }; |
| 33 | 34 | ||
| 34 | class Object : NonCopyable, public std::enable_shared_from_this<Object> { | 35 | class Object : NonCopyable, public std::enable_shared_from_this<Object> { |
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 1198c7a97..7825e1ec4 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | 1 | // Copyright 2019 yuzu emulator team |
| 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 | ||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "common/logging/log.h" | 10 | #include "common/logging/log.h" |
| 11 | #include "core/core.h" | 11 | #include "core/core.h" |
| 12 | #include "core/core_timing.h" | ||
| 12 | #include "core/hle/ipc_helpers.h" | 13 | #include "core/hle/ipc_helpers.h" |
| 13 | #include "core/hle/kernel/client_port.h" | 14 | #include "core/hle/kernel/client_port.h" |
| 14 | #include "core/hle/kernel/client_session.h" | 15 | #include "core/hle/kernel/client_session.h" |
| @@ -24,34 +25,29 @@ | |||
| 24 | namespace Kernel { | 25 | namespace Kernel { |
| 25 | 26 | ||
| 26 | ServerSession::ServerSession(KernelCore& kernel) : WaitObject{kernel} {} | 27 | ServerSession::ServerSession(KernelCore& kernel) : WaitObject{kernel} {} |
| 27 | ServerSession::~ServerSession() { | 28 | ServerSession::~ServerSession() = default; |
| 28 | // This destructor will be called automatically when the last ServerSession handle is closed by | ||
| 29 | // the emulated application. | ||
| 30 | |||
| 31 | // Decrease the port's connection count. | ||
| 32 | if (parent->port) { | ||
| 33 | parent->port->ConnectionClosed(); | ||
| 34 | } | ||
| 35 | } | ||
| 36 | 29 | ||
| 37 | ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel, | 30 | ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel, |
| 31 | std::shared_ptr<Session> parent, | ||
| 38 | std::string name) { | 32 | std::string name) { |
| 39 | std::shared_ptr<ServerSession> server_session = std::make_shared<ServerSession>(kernel); | 33 | std::shared_ptr<ServerSession> session{std::make_shared<ServerSession>(kernel)}; |
| 40 | 34 | ||
| 41 | server_session->name = std::move(name); | 35 | session->request_event = Core::Timing::CreateEvent( |
| 42 | server_session->parent = nullptr; | 36 | name, [session](u64 userdata, s64 cycles_late) { session->CompleteSyncRequest(); }); |
| 37 | session->name = std::move(name); | ||
| 38 | session->parent = std::move(parent); | ||
| 43 | 39 | ||
| 44 | return MakeResult(std::move(server_session)); | 40 | return MakeResult(std::move(session)); |
| 45 | } | 41 | } |
| 46 | 42 | ||
| 47 | bool ServerSession::ShouldWait(const Thread* thread) const { | 43 | bool ServerSession::ShouldWait(const Thread* thread) const { |
| 48 | // Wait if we have no pending requests, or if we're currently handling a request. | 44 | // Closed sessions should never wait, an error will be returned from svcReplyAndReceive. |
| 49 | if (auto client = parent->client.lock()) { | 45 | if (!parent->Client()) { |
| 50 | return pending_requesting_threads.empty() || currently_handling != nullptr; | 46 | return false; |
| 51 | } | 47 | } |
| 52 | 48 | ||
| 53 | // Closed sessions should never wait, an error will be returned from svcReplyAndReceive. | 49 | // Wait if we have no pending requests, or if we're currently handling a request. |
| 54 | return {}; | 50 | return pending_requesting_threads.empty() || currently_handling != nullptr; |
| 55 | } | 51 | } |
| 56 | 52 | ||
| 57 | void ServerSession::Acquire(Thread* thread) { | 53 | void ServerSession::Acquire(Thread* thread) { |
| @@ -128,14 +124,21 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con | |||
| 128 | return RESULT_SUCCESS; | 124 | return RESULT_SUCCESS; |
| 129 | } | 125 | } |
| 130 | 126 | ||
| 131 | ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread, | 127 | ResultCode ServerSession::QueueSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory) { |
| 132 | Memory::Memory& memory) { | 128 | u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(thread->GetTLSAddress()))}; |
| 133 | // The ServerSession received a sync request, this means that there's new data available | 129 | std::shared_ptr<Kernel::HLERequestContext> context{ |
| 134 | // from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or | 130 | std::make_shared<Kernel::HLERequestContext>(SharedFrom(this), std::move(thread))}; |
| 135 | // similar. | 131 | |
| 136 | Kernel::HLERequestContext context(SharedFrom(this), thread); | 132 | context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); |
| 137 | u32* cmd_buf = (u32*)memory.GetPointer(thread->GetTLSAddress()); | 133 | request_queue.Push(std::move(context)); |
| 138 | context.PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); | 134 | |
| 135 | return RESULT_SUCCESS; | ||
| 136 | } | ||
| 137 | |||
| 138 | ResultCode ServerSession::CompleteSyncRequest() { | ||
| 139 | ASSERT(!request_queue.Empty()); | ||
| 140 | |||
| 141 | auto& context = *request_queue.Front(); | ||
| 139 | 142 | ||
| 140 | ResultCode result = RESULT_SUCCESS; | 143 | ResultCode result = RESULT_SUCCESS; |
| 141 | // If the session has been converted to a domain, handle the domain request | 144 | // If the session has been converted to a domain, handle the domain request |
| @@ -147,61 +150,27 @@ ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread, | |||
| 147 | result = hle_handler->HandleSyncRequest(context); | 150 | result = hle_handler->HandleSyncRequest(context); |
| 148 | } | 151 | } |
| 149 | 152 | ||
| 150 | if (thread->GetStatus() == ThreadStatus::Running) { | ||
| 151 | // Put the thread to sleep until the server replies, it will be awoken in | ||
| 152 | // svcReplyAndReceive for LLE servers. | ||
| 153 | thread->SetStatus(ThreadStatus::WaitIPC); | ||
| 154 | |||
| 155 | if (hle_handler != nullptr) { | ||
| 156 | // For HLE services, we put the request threads to sleep for a short duration to | ||
| 157 | // simulate IPC overhead, but only if the HLE handler didn't put the thread to sleep for | ||
| 158 | // other reasons like an async callback. The IPC overhead is needed to prevent | ||
| 159 | // starvation when a thread only does sync requests to HLE services while a | ||
| 160 | // lower-priority thread is waiting to run. | ||
| 161 | |||
| 162 | // This delay was approximated in a homebrew application by measuring the average time | ||
| 163 | // it takes for svcSendSyncRequest to return when performing the SetLcdForceBlack IPC | ||
| 164 | // request to the GSP:GPU service in a n3DS with firmware 11.6. The measured values have | ||
| 165 | // a high variance and vary between models. | ||
| 166 | static constexpr u64 IPCDelayNanoseconds = 39000; | ||
| 167 | thread->WakeAfterDelay(IPCDelayNanoseconds); | ||
| 168 | } else { | ||
| 169 | // Add the thread to the list of threads that have issued a sync request with this | ||
| 170 | // server. | ||
| 171 | pending_requesting_threads.push_back(std::move(thread)); | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 175 | // If this ServerSession does not have an HLE implementation, just wake up the threads waiting | ||
| 176 | // on it. | ||
| 177 | WakeupAllWaitingThreads(); | ||
| 178 | |||
| 179 | // Handle scenario when ConvertToDomain command was issued, as we must do the conversion at the | ||
| 180 | // end of the command such that only commands following this one are handled as domains | ||
| 181 | if (convert_to_domain) { | 153 | if (convert_to_domain) { |
| 182 | ASSERT_MSG(IsSession(), "ServerSession is already a domain instance."); | 154 | ASSERT_MSG(IsSession(), "ServerSession is already a domain instance."); |
| 183 | domain_request_handlers = {hle_handler}; | 155 | domain_request_handlers = {hle_handler}; |
| 184 | convert_to_domain = false; | 156 | convert_to_domain = false; |
| 185 | } | 157 | } |
| 186 | 158 | ||
| 187 | return result; | 159 | // Some service requests require the thread to block |
| 188 | } | 160 | if (!context.IsThreadWaiting()) { |
| 189 | 161 | context.GetThread().ResumeFromWait(); | |
| 190 | ServerSession::SessionPair ServerSession::CreateSessionPair(KernelCore& kernel, | 162 | context.GetThread().SetWaitSynchronizationResult(result); |
| 191 | const std::string& name, | 163 | } |
| 192 | std::shared_ptr<ClientPort> port) { | ||
| 193 | auto server_session = ServerSession::Create(kernel, name + "_Server").Unwrap(); | ||
| 194 | std::shared_ptr<ClientSession> client_session = std::make_shared<ClientSession>(kernel); | ||
| 195 | client_session->name = name + "_Client"; | ||
| 196 | 164 | ||
| 197 | std::shared_ptr<Session> parent = std::make_shared<Session>(); | 165 | request_queue.Pop(); |
| 198 | parent->client = client_session; | ||
| 199 | parent->server = server_session; | ||
| 200 | parent->port = std::move(port); | ||
| 201 | 166 | ||
| 202 | client_session->parent = parent; | 167 | return result; |
| 203 | server_session->parent = parent; | 168 | } |
| 204 | 169 | ||
| 205 | return std::make_pair(std::move(server_session), std::move(client_session)); | 170 | ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread, |
| 171 | Memory::Memory& memory) { | ||
| 172 | Core::System::GetInstance().CoreTiming().ScheduleEvent(20000, request_event, {}); | ||
| 173 | return QueueSyncRequest(std::move(thread), memory); | ||
| 206 | } | 174 | } |
| 175 | |||
| 207 | } // namespace Kernel | 176 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index 641709a45..d6e48109e 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | 1 | // Copyright 2019 yuzu emulator team |
| 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 | ||
| @@ -9,7 +9,7 @@ | |||
| 9 | #include <utility> | 9 | #include <utility> |
| 10 | #include <vector> | 10 | #include <vector> |
| 11 | 11 | ||
| 12 | #include "core/hle/kernel/object.h" | 12 | #include "common/threadsafe_queue.h" |
| 13 | #include "core/hle/kernel/wait_object.h" | 13 | #include "core/hle/kernel/wait_object.h" |
| 14 | #include "core/hle/result.h" | 14 | #include "core/hle/result.h" |
| 15 | 15 | ||
| @@ -17,13 +17,14 @@ namespace Memory { | |||
| 17 | class Memory; | 17 | class Memory; |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | namespace Core::Timing { | ||
| 21 | struct EventType; | ||
| 22 | } | ||
| 23 | |||
| 20 | namespace Kernel { | 24 | namespace Kernel { |
| 21 | 25 | ||
| 22 | class ClientPort; | ||
| 23 | class ClientSession; | ||
| 24 | class HLERequestContext; | 26 | class HLERequestContext; |
| 25 | class KernelCore; | 27 | class KernelCore; |
| 26 | class ServerSession; | ||
| 27 | class Session; | 28 | class Session; |
| 28 | class SessionRequestHandler; | 29 | class SessionRequestHandler; |
| 29 | class Thread; | 30 | class Thread; |
| @@ -45,6 +46,12 @@ public: | |||
| 45 | explicit ServerSession(KernelCore& kernel); | 46 | explicit ServerSession(KernelCore& kernel); |
| 46 | ~ServerSession() override; | 47 | ~ServerSession() override; |
| 47 | 48 | ||
| 49 | friend class Session; | ||
| 50 | |||
| 51 | static ResultVal<std::shared_ptr<ServerSession>> Create(KernelCore& kernel, | ||
| 52 | std::shared_ptr<Session> parent, | ||
| 53 | std::string name = "Unknown"); | ||
| 54 | |||
| 48 | std::string GetTypeName() const override { | 55 | std::string GetTypeName() const override { |
| 49 | return "ServerSession"; | 56 | return "ServerSession"; |
| 50 | } | 57 | } |
| @@ -66,18 +73,6 @@ public: | |||
| 66 | return parent.get(); | 73 | return parent.get(); |
| 67 | } | 74 | } |
| 68 | 75 | ||
| 69 | using SessionPair = std::pair<std::shared_ptr<ServerSession>, std::shared_ptr<ClientSession>>; | ||
| 70 | |||
| 71 | /** | ||
| 72 | * Creates a pair of ServerSession and an associated ClientSession. | ||
| 73 | * @param kernel The kernal instance to create the session pair under. | ||
| 74 | * @param name Optional name of the ports. | ||
| 75 | * @param client_port Optional The ClientPort that spawned this session. | ||
| 76 | * @return The created session tuple | ||
| 77 | */ | ||
| 78 | static SessionPair CreateSessionPair(KernelCore& kernel, const std::string& name = "Unknown", | ||
| 79 | std::shared_ptr<ClientPort> client_port = nullptr); | ||
| 80 | |||
| 81 | /** | 76 | /** |
| 82 | * Sets the HLE handler for the session. This handler will be called to service IPC requests | 77 | * Sets the HLE handler for the session. This handler will be called to service IPC requests |
| 83 | * instead of the regular IPC machinery. (The regular IPC machinery is currently not | 78 | * instead of the regular IPC machinery. (The regular IPC machinery is currently not |
| @@ -128,15 +123,11 @@ public: | |||
| 128 | } | 123 | } |
| 129 | 124 | ||
| 130 | private: | 125 | private: |
| 131 | /** | 126 | /// Queues a sync request from the emulated application. |
| 132 | * Creates a server session. The server session can have an optional HLE handler, | 127 | ResultCode QueueSyncRequest(std::shared_ptr<Thread> thread, Memory::Memory& memory); |
| 133 | * which will be invoked to handle the IPC requests that this session receives. | 128 | |
| 134 | * @param kernel The kernel instance to create this server session under. | 129 | /// Completes a sync request from the emulated application. |
| 135 | * @param name Optional name of the server session. | 130 | ResultCode CompleteSyncRequest(); |
| 136 | * @return The created server session | ||
| 137 | */ | ||
| 138 | static ResultVal<std::shared_ptr<ServerSession>> Create(KernelCore& kernel, | ||
| 139 | std::string name = "Unknown"); | ||
| 140 | 131 | ||
| 141 | /// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an | 132 | /// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an |
| 142 | /// object handle. | 133 | /// object handle. |
| @@ -166,6 +157,12 @@ private: | |||
| 166 | 157 | ||
| 167 | /// The name of this session (optional) | 158 | /// The name of this session (optional) |
| 168 | std::string name; | 159 | std::string name; |
| 160 | |||
| 161 | /// Core timing event used to schedule the service request at some point in the future | ||
| 162 | std::shared_ptr<Core::Timing::EventType> request_event; | ||
| 163 | |||
| 164 | /// Queue of scheduled service requests | ||
| 165 | Common::MPSCQueue<std::shared_ptr<Kernel::HLERequestContext>> request_queue; | ||
| 169 | }; | 166 | }; |
| 170 | 167 | ||
| 171 | } // namespace Kernel | 168 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/session.cpp b/src/core/hle/kernel/session.cpp index 642914744..dee6e2b72 100644 --- a/src/core/hle/kernel/session.cpp +++ b/src/core/hle/kernel/session.cpp | |||
| @@ -1,12 +1,36 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | 1 | // Copyright 2019 yuzu emulator team |
| 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 "common/assert.h" | ||
| 6 | #include "core/hle/kernel/client_session.h" | ||
| 7 | #include "core/hle/kernel/server_session.h" | ||
| 5 | #include "core/hle/kernel/session.h" | 8 | #include "core/hle/kernel/session.h" |
| 6 | #include "core/hle/kernel/thread.h" | ||
| 7 | 9 | ||
| 8 | namespace Kernel { | 10 | namespace Kernel { |
| 9 | 11 | ||
| 10 | Session::Session() {} | 12 | Session::Session(KernelCore& kernel) : WaitObject{kernel} {} |
| 11 | Session::~Session() {} | 13 | Session::~Session() = default; |
| 14 | |||
| 15 | Session::SessionPair Session::Create(KernelCore& kernel, std::string name) { | ||
| 16 | auto session{std::make_shared<Session>(kernel)}; | ||
| 17 | auto client_session{Kernel::ClientSession::Create(kernel, session, name + "_Client").Unwrap()}; | ||
| 18 | auto server_session{Kernel::ServerSession::Create(kernel, session, name + "_Server").Unwrap()}; | ||
| 19 | |||
| 20 | session->name = std::move(name); | ||
| 21 | session->client = client_session; | ||
| 22 | session->server = server_session; | ||
| 23 | |||
| 24 | return std::make_pair(std::move(client_session), std::move(server_session)); | ||
| 25 | } | ||
| 26 | |||
| 27 | bool Session::ShouldWait(const Thread* thread) const { | ||
| 28 | UNIMPLEMENTED(); | ||
| 29 | return {}; | ||
| 30 | } | ||
| 31 | |||
| 32 | void Session::Acquire(Thread* thread) { | ||
| 33 | UNIMPLEMENTED(); | ||
| 34 | } | ||
| 35 | |||
| 12 | } // namespace Kernel | 36 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h index 94395f9f5..5a9d4e9ad 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/kernel/session.h | |||
| @@ -1,27 +1,64 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | 1 | // Copyright 2019 yuzu emulator team |
| 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 "core/hle/kernel/object.h" | 7 | #include <memory> |
| 8 | #include <string> | ||
| 9 | |||
| 10 | #include "core/hle/kernel/wait_object.h" | ||
| 11 | #include "core/hle/result.h" | ||
| 8 | 12 | ||
| 9 | namespace Kernel { | 13 | namespace Kernel { |
| 10 | 14 | ||
| 11 | class ClientSession; | 15 | class ClientSession; |
| 12 | class ClientPort; | ||
| 13 | class ServerSession; | 16 | class ServerSession; |
| 14 | 17 | ||
| 15 | /** | 18 | /** |
| 16 | * Parent structure to link the client and server endpoints of a session with their associated | 19 | * Parent structure to link the client and server endpoints of a session with their associated |
| 17 | * client port. The client port need not exist, as is the case for portless sessions like the | 20 | * client port. |
| 18 | * FS File and Directory sessions. When one of the endpoints of a session is destroyed, its | ||
| 19 | * corresponding field in this structure will be set to nullptr. | ||
| 20 | */ | 21 | */ |
| 21 | class Session final { | 22 | class Session final : public WaitObject { |
| 22 | public: | 23 | public: |
| 23 | std::weak_ptr<ClientSession> client; ///< The client endpoint of the session. | 24 | explicit Session(KernelCore& kernel); |
| 24 | std::weak_ptr<ServerSession> server; ///< The server endpoint of the session. | 25 | ~Session() override; |
| 25 | std::shared_ptr<ClientPort> port; ///< The port that this session is associated with (optional). | 26 | |
| 27 | using SessionPair = std::pair<std::shared_ptr<ClientSession>, std::shared_ptr<ServerSession>>; | ||
| 28 | |||
| 29 | static SessionPair Create(KernelCore& kernel, std::string name = "Unknown"); | ||
| 30 | |||
| 31 | std::string GetName() const override { | ||
| 32 | return name; | ||
| 33 | } | ||
| 34 | |||
| 35 | static constexpr HandleType HANDLE_TYPE = HandleType::Session; | ||
| 36 | HandleType GetHandleType() const override { | ||
| 37 | return HANDLE_TYPE; | ||
| 38 | } | ||
| 39 | |||
| 40 | bool ShouldWait(const Thread* thread) const override; | ||
| 41 | |||
| 42 | void Acquire(Thread* thread) override; | ||
| 43 | |||
| 44 | std::shared_ptr<ClientSession> Client() { | ||
| 45 | if (auto result{client.lock()}) { | ||
| 46 | return result; | ||
| 47 | } | ||
| 48 | return {}; | ||
| 49 | } | ||
| 50 | |||
| 51 | std::shared_ptr<ServerSession> Server() { | ||
| 52 | if (auto result{server.lock()}) { | ||
| 53 | return result; | ||
| 54 | } | ||
| 55 | return {}; | ||
| 56 | } | ||
| 57 | |||
| 58 | private: | ||
| 59 | std::string name; | ||
| 60 | std::weak_ptr<ClientSession> client; | ||
| 61 | std::weak_ptr<ServerSession> server; | ||
| 26 | }; | 62 | }; |
| 63 | |||
| 27 | } // namespace Kernel | 64 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index db3ae3eb8..bd25de478 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -381,11 +381,12 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { | |||
| 381 | 381 | ||
| 382 | LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); | 382 | LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); |
| 383 | 383 | ||
| 384 | system.PrepareReschedule(); | 384 | auto thread = system.CurrentScheduler().GetCurrentThread(); |
| 385 | thread->InvalidateWakeupCallback(); | ||
| 386 | thread->SetStatus(ThreadStatus::WaitIPC); | ||
| 387 | system.PrepareReschedule(thread->GetProcessorID()); | ||
| 385 | 388 | ||
| 386 | // TODO(Subv): svcSendSyncRequest should put the caller thread to sleep while the server | 389 | return session->SendSyncRequest(SharedFrom(thread), system.Memory()); |
| 387 | // responds and cause a reschedule. | ||
| 388 | return session->SendSyncRequest(system.CurrentScheduler().GetCurrentThread(), system.Memory()); | ||
| 389 | } | 390 | } |
| 390 | 391 | ||
| 391 | /// Get the ID for the specified thread. | 392 | /// Get the ID for the specified thread. |