summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorGravatar bunnei2019-11-30 18:56:35 -0500
committerGravatar GitHub2019-11-30 18:56:35 -0500
commit5c7253f8d3c010c0a0e5c91db497819829cb4a43 (patch)
treec2aa6989d3f081c07c72c3ab4a698c73ecd8c429 /src/core
parentMerge pull request #3184 from ReinUsesLisp/framebuffer-cache (diff)
parentkernel: Implement a more accurate IPC dispatch. (diff)
downloadyuzu-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')
-rw-r--r--src/core/CMakeLists.txt1
-rw-r--r--src/core/hle/ipc_helpers.h6
-rw-r--r--src/core/hle/kernel/client_port.cpp14
-rw-r--r--src/core/hle/kernel/client_session.cpp40
-rw-r--r--src/core/hle/kernel/client_session.h21
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp2
-rw-r--r--src/core/hle/kernel/hle_ipc.h13
-rw-r--r--src/core/hle/kernel/object.cpp1
-rw-r--r--src/core/hle/kernel/object.h1
-rw-r--r--src/core/hle/kernel/server_session.cpp117
-rw-r--r--src/core/hle/kernel/server_session.h49
-rw-r--r--src/core/hle/kernel/session.cpp32
-rw-r--r--src/core/hle/kernel/session.h57
-rw-r--r--src/core/hle/kernel/svc.cpp9
-rw-r--r--src/core/hle/service/nfp/nfp.cpp2
-rw-r--r--src/core/hle/service/service.cpp4
-rw-r--r--src/core/hle/service/sm/controller.cpp5
-rw-r--r--src/core/hle/service/sm/sm.cpp33
-rw-r--r--src/core/hle/service/sm/sm.h6
19 files changed, 246 insertions, 167 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 2dfdcb0d7..7fd226050 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -170,6 +170,7 @@ add_library(core STATIC
170 hle/kernel/server_port.h 170 hle/kernel/server_port.h
171 hle/kernel/server_session.cpp 171 hle/kernel/server_session.cpp
172 hle/kernel/server_session.h 172 hle/kernel/server_session.h
173 hle/kernel/session.cpp
173 hle/kernel/session.h 174 hle/kernel/session.h
174 hle/kernel/shared_memory.cpp 175 hle/kernel/shared_memory.cpp
175 hle/kernel/shared_memory.h 176 hle/kernel/shared_memory.h
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index b9f9ae1fa..0dc6a4a43 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -19,6 +19,7 @@
19#include "core/hle/kernel/hle_ipc.h" 19#include "core/hle/kernel/hle_ipc.h"
20#include "core/hle/kernel/object.h" 20#include "core/hle/kernel/object.h"
21#include "core/hle/kernel/server_session.h" 21#include "core/hle/kernel/server_session.h"
22#include "core/hle/kernel/session.h"
22#include "core/hle/result.h" 23#include "core/hle/result.h"
23 24
24namespace IPC { 25namespace IPC {
@@ -139,10 +140,9 @@ public:
139 context->AddDomainObject(std::move(iface)); 140 context->AddDomainObject(std::move(iface));
140 } else { 141 } else {
141 auto& kernel = Core::System::GetInstance().Kernel(); 142 auto& kernel = Core::System::GetInstance().Kernel();
142 auto [server, client] = 143 auto [client, server] = Kernel::Session::Create(kernel, iface->GetServiceName());
143 Kernel::ServerSession::CreateSessionPair(kernel, iface->GetServiceName());
144 iface->ClientConnected(server);
145 context->AddMoveObject(std::move(client)); 144 context->AddMoveObject(std::move(client));
145 iface->ClientConnected(std::move(server));
146 } 146 }
147 } 147 }
148 148
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
13namespace Kernel { 14namespace Kernel {
14 15
@@ -20,28 +21,23 @@ std::shared_ptr<ServerPort> ClientPort::GetServerPort() const {
20} 21}
21 22
22ResultVal<std::shared_ptr<ClientSession>> ClientPort::Connect() { 23ResultVal<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
47void ClientPort::ConnectionClosed() { 43void 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
13namespace Kernel { 13namespace Kernel {
14 14
15ClientSession::ClientSession(KernelCore& kernel) : Object{kernel} {} 15ClientSession::ClientSession(KernelCore& kernel) : WaitObject{kernel} {}
16
16ClientSession::~ClientSession() { 17ClientSession::~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
24ResultCode ClientSession::SendSyncRequest(Thread* thread, Memory::Memory& memory) { 25bool 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
30void ClientSession::Acquire(Thread* thread) {
31 UNIMPLEMENTED();
32}
33
34ResultVal<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
45ResultCode 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
11union ResultCode; 13union ResultCode;
12 14
@@ -18,15 +20,14 @@ namespace Kernel {
18 20
19class KernelCore; 21class KernelCore;
20class Session; 22class Session;
21class ServerSession;
22class Thread; 23class Thread;
23 24
24class ClientSession final : public Object { 25class ClientSession final : public WaitObject {
25public: 26public:
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
46private: 51private:
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
267private: 279private:
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
34class Object : NonCopyable, public std::enable_shared_from_this<Object> { 35class 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 @@
24namespace Kernel { 25namespace Kernel {
25 26
26ServerSession::ServerSession(KernelCore& kernel) : WaitObject{kernel} {} 27ServerSession::ServerSession(KernelCore& kernel) : WaitObject{kernel} {}
27ServerSession::~ServerSession() { 28ServerSession::~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
37ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel, 30ResultVal<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
47bool ServerSession::ShouldWait(const Thread* thread) const { 43bool 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
57void ServerSession::Acquire(Thread* thread) { 53void 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
131ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread, 127ResultCode 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
138ResultCode 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();
190ServerSession::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)); 170ResultCode 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 {
17class Memory; 17class Memory;
18} 18}
19 19
20namespace Core::Timing {
21struct EventType;
22}
23
20namespace Kernel { 24namespace Kernel {
21 25
22class ClientPort;
23class ClientSession;
24class HLERequestContext; 26class HLERequestContext;
25class KernelCore; 27class KernelCore;
26class ServerSession;
27class Session; 28class Session;
28class SessionRequestHandler; 29class SessionRequestHandler;
29class Thread; 30class 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
130private: 125private:
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
8namespace Kernel { 10namespace Kernel {
9 11
10Session::Session() {} 12Session::Session(KernelCore& kernel) : WaitObject{kernel} {}
11Session::~Session() {} 13Session::~Session() = default;
14
15Session::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
27bool Session::ShouldWait(const Thread* thread) const {
28 UNIMPLEMENTED();
29 return {};
30}
31
32void 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
9namespace Kernel { 13namespace Kernel {
10 14
11class ClientSession; 15class ClientSession;
12class ClientPort;
13class ServerSession; 16class 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 */
21class Session final { 22class Session final : public WaitObject {
22public: 23public:
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
58private:
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.
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index ec0367978..4b79eb81d 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -189,7 +189,7 @@ private:
189 LOG_DEBUG(Service_NFP, "called"); 189 LOG_DEBUG(Service_NFP, "called");
190 190
191 auto nfc_event = nfp_interface.GetNFCEvent(); 191 auto nfc_event = nfp_interface.GetNFCEvent();
192 if (!nfc_event->ShouldWait(Kernel::GetCurrentThread()) && !has_attached_handle) { 192 if (!nfc_event->ShouldWait(&ctx.GetThread()) && !has_attached_handle) {
193 device_state = DeviceState::TagFound; 193 device_state = DeviceState::TagFound;
194 nfc_event->Clear(); 194 nfc_event->Clear();
195 } 195 }
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 5698f429f..fa5347af9 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -186,7 +186,7 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co
186 UNIMPLEMENTED_MSG("command_type={}", static_cast<int>(context.GetCommandType())); 186 UNIMPLEMENTED_MSG("command_type={}", static_cast<int>(context.GetCommandType()));
187 } 187 }
188 188
189 context.WriteToOutgoingCommandBuffer(*Kernel::GetCurrentThread()); 189 context.WriteToOutgoingCommandBuffer(context.GetThread());
190 190
191 return RESULT_SUCCESS; 191 return RESULT_SUCCESS;
192} 192}
@@ -201,7 +201,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {
201 auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system); 201 auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system);
202 system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false); 202 system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false);
203 203
204 SM::ServiceManager::InstallInterfaces(sm); 204 SM::ServiceManager::InstallInterfaces(sm, system.Kernel());
205 205
206 Account::InstallInterfaces(system); 206 Account::InstallInterfaces(system);
207 AM::InstallInterfaces(*sm, nv_flinger, system); 207 AM::InstallInterfaces(*sm, nv_flinger, system);
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp
index af2fadcef..c45b285f8 100644
--- a/src/core/hle/service/sm/controller.cpp
+++ b/src/core/hle/service/sm/controller.cpp
@@ -30,10 +30,7 @@ void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) {
30 30
31 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; 31 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
32 rb.Push(RESULT_SUCCESS); 32 rb.Push(RESULT_SUCCESS);
33 std::shared_ptr<Kernel::ClientSession> session{ctx.Session()->GetParent()->client}; 33 rb.PushMoveObjects(ctx.Session()->GetParent()->Client());
34 rb.PushMoveObjects(session);
35
36 LOG_DEBUG(Service, "session={}", session->GetObjectId());
37} 34}
38 35
39void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) { 36void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index a0a7206bb..88909504d 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -36,10 +36,11 @@ static ResultCode ValidateServiceName(const std::string& name) {
36 return RESULT_SUCCESS; 36 return RESULT_SUCCESS;
37} 37}
38 38
39void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self) { 39void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self,
40 Kernel::KernelCore& kernel) {
40 ASSERT(self->sm_interface.expired()); 41 ASSERT(self->sm_interface.expired());
41 42
42 auto sm = std::make_shared<SM>(self); 43 auto sm = std::make_shared<SM>(self, kernel);
43 sm->InstallAsNamedPort(); 44 sm->InstallAsNamedPort();
44 self->sm_interface = sm; 45 self->sm_interface = sm;
45 self->controller_interface = std::make_unique<Controller>(); 46 self->controller_interface = std::make_unique<Controller>();
@@ -114,8 +115,6 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
114 115
115 std::string name(name_buf.begin(), end); 116 std::string name(name_buf.begin(), end);
116 117
117 // TODO(yuriks): Permission checks go here
118
119 auto client_port = service_manager->GetServicePort(name); 118 auto client_port = service_manager->GetServicePort(name);
120 if (client_port.Failed()) { 119 if (client_port.Failed()) {
121 IPC::ResponseBuilder rb{ctx, 2}; 120 IPC::ResponseBuilder rb{ctx, 2};
@@ -127,14 +126,22 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
127 return; 126 return;
128 } 127 }
129 128
130 auto session = client_port.Unwrap()->Connect(); 129 auto [client, server] = Kernel::Session::Create(kernel, name);
131 ASSERT(session.Succeeded()); 130
132 if (session.Succeeded()) { 131 const auto& server_port = client_port.Unwrap()->GetServerPort();
133 LOG_DEBUG(Service_SM, "called service={} -> session={}", name, (*session)->GetObjectId()); 132 if (server_port->GetHLEHandler()) {
134 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; 133 server_port->GetHLEHandler()->ClientConnected(server);
135 rb.Push(session.Code()); 134 } else {
136 rb.PushMoveObjects(std::move(session).Unwrap()); 135 server_port->AppendPendingSession(server);
137 } 136 }
137
138 // Wake the threads waiting on the ServerPort
139 server_port->WakeupAllWaitingThreads();
140
141 LOG_DEBUG(Service_SM, "called service={} -> session={}", name, client->GetObjectId());
142 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
143 rb.Push(RESULT_SUCCESS);
144 rb.PushMoveObjects(std::move(client));
138} 145}
139 146
140void SM::RegisterService(Kernel::HLERequestContext& ctx) { 147void SM::RegisterService(Kernel::HLERequestContext& ctx) {
@@ -178,8 +185,8 @@ void SM::UnregisterService(Kernel::HLERequestContext& ctx) {
178 rb.Push(service_manager->UnregisterService(name)); 185 rb.Push(service_manager->UnregisterService(name));
179} 186}
180 187
181SM::SM(std::shared_ptr<ServiceManager> service_manager) 188SM::SM(std::shared_ptr<ServiceManager> service_manager, Kernel::KernelCore& kernel)
182 : ServiceFramework("sm:", 4), service_manager(std::move(service_manager)) { 189 : ServiceFramework{"sm:", 4}, service_manager{std::move(service_manager)}, kernel{kernel} {
183 static const FunctionInfo functions[] = { 190 static const FunctionInfo functions[] = {
184 {0x00000000, &SM::Initialize, "Initialize"}, 191 {0x00000000, &SM::Initialize, "Initialize"},
185 {0x00000001, &SM::GetService, "GetService"}, 192 {0x00000001, &SM::GetService, "GetService"},
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index 3de22268b..b06d2f103 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -18,6 +18,7 @@
18namespace Kernel { 18namespace Kernel {
19class ClientPort; 19class ClientPort;
20class ClientSession; 20class ClientSession;
21class KernelCore;
21class ServerPort; 22class ServerPort;
22class SessionRequestHandler; 23class SessionRequestHandler;
23} // namespace Kernel 24} // namespace Kernel
@@ -29,7 +30,7 @@ class Controller;
29/// Interface to "sm:" service 30/// Interface to "sm:" service
30class SM final : public ServiceFramework<SM> { 31class SM final : public ServiceFramework<SM> {
31public: 32public:
32 explicit SM(std::shared_ptr<ServiceManager> service_manager); 33 explicit SM(std::shared_ptr<ServiceManager> service_manager, Kernel::KernelCore& kernel);
33 ~SM() override; 34 ~SM() override;
34 35
35private: 36private:
@@ -39,11 +40,12 @@ private:
39 void UnregisterService(Kernel::HLERequestContext& ctx); 40 void UnregisterService(Kernel::HLERequestContext& ctx);
40 41
41 std::shared_ptr<ServiceManager> service_manager; 42 std::shared_ptr<ServiceManager> service_manager;
43 Kernel::KernelCore& kernel;
42}; 44};
43 45
44class ServiceManager { 46class ServiceManager {
45public: 47public:
46 static void InstallInterfaces(std::shared_ptr<ServiceManager> self); 48 static void InstallInterfaces(std::shared_ptr<ServiceManager> self, Kernel::KernelCore& kernel);
47 49
48 ServiceManager(); 50 ServiceManager();
49 ~ServiceManager(); 51 ~ServiceManager();