summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel
diff options
context:
space:
mode:
authorGravatar Liam2022-10-16 01:53:56 -0400
committerGravatar Liam2022-10-31 17:44:06 -0400
commit983f2b70741f17f30fe2321451f10cabecc013d2 (patch)
treec1ac3c1033fdeefaabe76590ca204c4c1b2a98cd /src/core/hle/kernel
parentMerge pull request #9159 from liamwhite/kbork (diff)
downloadyuzu-983f2b70741f17f30fe2321451f10cabecc013d2.tar.gz
yuzu-983f2b70741f17f30fe2321451f10cabecc013d2.tar.xz
yuzu-983f2b70741f17f30fe2321451f10cabecc013d2.zip
kernel: invert session request handling flow
Diffstat (limited to 'src/core/hle/kernel')
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp55
-rw-r--r--src/core/hle/kernel/hle_ipc.h29
-rw-r--r--src/core/hle/kernel/k_client_port.cpp5
-rw-r--r--src/core/hle/kernel/k_client_port.h3
-rw-r--r--src/core/hle/kernel/k_port.cpp6
-rw-r--r--src/core/hle/kernel/k_server_port.cpp5
-rw-r--r--src/core/hle/kernel/k_server_port.h19
-rw-r--r--src/core/hle/kernel/k_server_session.cpp187
-rw-r--r--src/core/hle/kernel/k_server_session.h37
-rw-r--r--src/core/hle/kernel/k_session.cpp5
-rw-r--r--src/core/hle/kernel/k_session.h3
-rw-r--r--src/core/hle/kernel/kernel.cpp24
-rw-r--r--src/core/hle/kernel/kernel.h9
-rw-r--r--src/core/hle/kernel/service_thread.cpp232
-rw-r--r--src/core/hle/kernel/service_thread.h6
-rw-r--r--src/core/hle/kernel/svc.cpp6
16 files changed, 381 insertions, 250 deletions
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index e4f43a053..fd354d484 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -16,6 +16,7 @@
16#include "core/hle/kernel/k_auto_object.h" 16#include "core/hle/kernel/k_auto_object.h"
17#include "core/hle/kernel/k_handle_table.h" 17#include "core/hle/kernel/k_handle_table.h"
18#include "core/hle/kernel/k_process.h" 18#include "core/hle/kernel/k_process.h"
19#include "core/hle/kernel/k_server_port.h"
19#include "core/hle/kernel/k_server_session.h" 20#include "core/hle/kernel/k_server_session.h"
20#include "core/hle/kernel/k_thread.h" 21#include "core/hle/kernel/k_thread.h"
21#include "core/hle/kernel/kernel.h" 22#include "core/hle/kernel/kernel.h"
@@ -35,7 +36,21 @@ SessionRequestHandler::SessionRequestHandler(KernelCore& kernel_, const char* se
35} 36}
36 37
37SessionRequestHandler::~SessionRequestHandler() { 38SessionRequestHandler::~SessionRequestHandler() {
38 kernel.ReleaseServiceThread(service_thread); 39 kernel.ReleaseServiceThread(service_thread.lock());
40}
41
42void SessionRequestHandler::AcceptSession(KServerPort* server_port) {
43 auto* server_session = server_port->AcceptSession();
44 ASSERT(server_session != nullptr);
45
46 RegisterSession(server_session, std::make_shared<SessionRequestManager>(kernel));
47}
48
49void SessionRequestHandler::RegisterSession(KServerSession* server_session,
50 std::shared_ptr<SessionRequestManager> manager) {
51 manager->SetSessionHandler(shared_from_this());
52 service_thread.lock()->RegisterServerSession(server_session, manager);
53 server_session->Close();
39} 54}
40 55
41SessionRequestManager::SessionRequestManager(KernelCore& kernel_) : kernel{kernel_} {} 56SessionRequestManager::SessionRequestManager(KernelCore& kernel_) : kernel{kernel_} {}
@@ -92,7 +107,7 @@ Result SessionRequestManager::HandleDomainSyncRequest(KServerSession* server_ses
92 } 107 }
93 108
94 // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs 109 // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs
95 context.SetSessionRequestManager(server_session->GetSessionRequestManager()); 110 ASSERT(context.GetManager().get() == this);
96 111
97 // If there is a DomainMessageHeader, then this is CommandType "Request" 112 // If there is a DomainMessageHeader, then this is CommandType "Request"
98 const auto& domain_message_header = context.GetDomainMessageHeader(); 113 const auto& domain_message_header = context.GetDomainMessageHeader();
@@ -130,31 +145,6 @@ Result SessionRequestManager::HandleDomainSyncRequest(KServerSession* server_ses
130 return ResultSuccess; 145 return ResultSuccess;
131} 146}
132 147
133Result SessionRequestManager::QueueSyncRequest(KSession* parent,
134 std::shared_ptr<HLERequestContext>&& context) {
135 // Ensure we have a session request handler
136 if (this->HasSessionRequestHandler(*context)) {
137 if (auto strong_ptr = this->GetServiceThread().lock()) {
138 strong_ptr->QueueSyncRequest(*parent, std::move(context));
139 } else {
140 ASSERT_MSG(false, "strong_ptr is nullptr!");
141 }
142 } else {
143 ASSERT_MSG(false, "handler is invalid!");
144 }
145
146 return ResultSuccess;
147}
148
149void SessionRequestHandler::ClientConnected(KServerSession* session) {
150 session->GetSessionRequestManager()->SetSessionHandler(shared_from_this());
151
152 // Ensure our server session is tracked globally.
153 kernel.RegisterServerObject(session);
154}
155
156void SessionRequestHandler::ClientDisconnected(KServerSession* session) {}
157
158HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_, 148HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_,
159 KServerSession* server_session_, KThread* thread_) 149 KServerSession* server_session_, KThread* thread_)
160 : server_session(server_session_), thread(thread_), kernel{kernel_}, memory{memory_} { 150 : server_session(server_session_), thread(thread_), kernel{kernel_}, memory{memory_} {
@@ -214,7 +204,7 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32
214 // Padding to align to 16 bytes 204 // Padding to align to 16 bytes
215 rp.AlignWithPadding(); 205 rp.AlignWithPadding();
216 206
217 if (Session()->GetSessionRequestManager()->IsDomain() && 207 if (GetManager()->IsDomain() &&
218 ((command_header->type == IPC::CommandType::Request || 208 ((command_header->type == IPC::CommandType::Request ||
219 command_header->type == IPC::CommandType::RequestWithContext) || 209 command_header->type == IPC::CommandType::RequestWithContext) ||
220 !incoming)) { 210 !incoming)) {
@@ -223,7 +213,7 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32
223 if (incoming || domain_message_header) { 213 if (incoming || domain_message_header) {
224 domain_message_header = rp.PopRaw<IPC::DomainMessageHeader>(); 214 domain_message_header = rp.PopRaw<IPC::DomainMessageHeader>();
225 } else { 215 } else {
226 if (Session()->GetSessionRequestManager()->IsDomain()) { 216 if (GetManager()->IsDomain()) {
227 LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!"); 217 LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!");
228 } 218 }
229 } 219 }
@@ -316,12 +306,11 @@ Result HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_threa
316 // Write the domain objects to the command buffer, these go after the raw untranslated data. 306 // Write the domain objects to the command buffer, these go after the raw untranslated data.
317 // TODO(Subv): This completely ignores C buffers. 307 // TODO(Subv): This completely ignores C buffers.
318 308
319 if (server_session->GetSessionRequestManager()->IsDomain()) { 309 if (GetManager()->IsDomain()) {
320 current_offset = domain_offset - static_cast<u32>(outgoing_domain_objects.size()); 310 current_offset = domain_offset - static_cast<u32>(outgoing_domain_objects.size());
321 for (auto& object : outgoing_domain_objects) { 311 for (auto& object : outgoing_domain_objects) {
322 server_session->GetSessionRequestManager()->AppendDomainHandler(std::move(object)); 312 GetManager()->AppendDomainHandler(std::move(object));
323 cmd_buf[current_offset++] = static_cast<u32_le>( 313 cmd_buf[current_offset++] = static_cast<u32_le>(GetManager()->DomainHandlerCount());
324 server_session->GetSessionRequestManager()->DomainHandlerCount());
325 } 314 }
326 } 315 }
327 316
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 1083638a9..67da8e7e1 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -45,11 +45,13 @@ class KAutoObject;
45class KernelCore; 45class KernelCore;
46class KEvent; 46class KEvent;
47class KHandleTable; 47class KHandleTable;
48class KServerPort;
48class KProcess; 49class KProcess;
49class KServerSession; 50class KServerSession;
50class KThread; 51class KThread;
51class KReadableEvent; 52class KReadableEvent;
52class KSession; 53class KSession;
54class SessionRequestManager;
53class ServiceThread; 55class ServiceThread;
54 56
55enum class ThreadWakeupReason; 57enum class ThreadWakeupReason;
@@ -76,19 +78,9 @@ public:
76 virtual Result HandleSyncRequest(Kernel::KServerSession& session, 78 virtual Result HandleSyncRequest(Kernel::KServerSession& session,
77 Kernel::HLERequestContext& context) = 0; 79 Kernel::HLERequestContext& context) = 0;
78 80
79 /** 81 void AcceptSession(KServerPort* server_port);
80 * Signals that a client has just connected to this HLE handler and keeps the 82 void RegisterSession(KServerSession* server_session,
81 * associated ServerSession alive for the duration of the connection. 83 std::shared_ptr<SessionRequestManager> manager);
82 * @param server_session Owning pointer to the ServerSession associated with the connection.
83 */
84 void ClientConnected(KServerSession* session);
85
86 /**
87 * Signals that a client has just disconnected from this HLE handler and releases the
88 * associated ServerSession.
89 * @param server_session ServerSession associated with the connection.
90 */
91 void ClientDisconnected(KServerSession* session);
92 84
93 std::weak_ptr<ServiceThread> GetServiceThread() const { 85 std::weak_ptr<ServiceThread> GetServiceThread() const {
94 return service_thread; 86 return service_thread;
@@ -170,7 +162,6 @@ public:
170 162
171 Result HandleDomainSyncRequest(KServerSession* server_session, HLERequestContext& context); 163 Result HandleDomainSyncRequest(KServerSession* server_session, HLERequestContext& context);
172 Result CompleteSyncRequest(KServerSession* server_session, HLERequestContext& context); 164 Result CompleteSyncRequest(KServerSession* server_session, HLERequestContext& context);
173 Result QueueSyncRequest(KSession* parent, std::shared_ptr<HLERequestContext>&& context);
174 165
175private: 166private:
176 bool convert_to_domain{}; 167 bool convert_to_domain{};
@@ -350,11 +341,11 @@ public:
350 341
351 template <typename T> 342 template <typename T>
352 std::shared_ptr<T> GetDomainHandler(std::size_t index) const { 343 std::shared_ptr<T> GetDomainHandler(std::size_t index) const {
353 return std::static_pointer_cast<T>(manager.lock()->DomainHandler(index).lock()); 344 return std::static_pointer_cast<T>(GetManager()->DomainHandler(index).lock());
354 } 345 }
355 346
356 void SetSessionRequestManager(std::weak_ptr<SessionRequestManager> manager_) { 347 void SetSessionRequestManager(std::weak_ptr<SessionRequestManager> manager_) {
357 manager = std::move(manager_); 348 manager = manager_;
358 } 349 }
359 350
360 std::string Description() const; 351 std::string Description() const;
@@ -363,6 +354,10 @@ public:
363 return *thread; 354 return *thread;
364 } 355 }
365 356
357 std::shared_ptr<SessionRequestManager> GetManager() const {
358 return manager.lock();
359 }
360
366private: 361private:
367 friend class IPC::ResponseBuilder; 362 friend class IPC::ResponseBuilder;
368 363
@@ -396,7 +391,7 @@ private:
396 u32 handles_offset{}; 391 u32 handles_offset{};
397 u32 domain_offset{}; 392 u32 domain_offset{};
398 393
399 std::weak_ptr<SessionRequestManager> manager; 394 std::weak_ptr<SessionRequestManager> manager{};
400 395
401 KernelCore& kernel; 396 KernelCore& kernel;
402 Core::Memory::Memory& memory; 397 Core::Memory::Memory& memory;
diff --git a/src/core/hle/kernel/k_client_port.cpp b/src/core/hle/kernel/k_client_port.cpp
index 3cb22ff4d..eaa2e094c 100644
--- a/src/core/hle/kernel/k_client_port.cpp
+++ b/src/core/hle/kernel/k_client_port.cpp
@@ -58,8 +58,7 @@ bool KClientPort::IsSignaled() const {
58 return num_sessions < max_sessions; 58 return num_sessions < max_sessions;
59} 59}
60 60
61Result KClientPort::CreateSession(KClientSession** out, 61Result KClientPort::CreateSession(KClientSession** out) {
62 std::shared_ptr<SessionRequestManager> session_manager) {
63 // Reserve a new session from the resource limit. 62 // Reserve a new session from the resource limit.
64 KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(), 63 KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(),
65 LimitableResource::Sessions); 64 LimitableResource::Sessions);
@@ -104,7 +103,7 @@ Result KClientPort::CreateSession(KClientSession** out,
104 } 103 }
105 104
106 // Initialize the session. 105 // Initialize the session.
107 session->Initialize(this, parent->GetName(), session_manager); 106 session->Initialize(this, parent->GetName());
108 107
109 // Commit the session reservation. 108 // Commit the session reservation.
110 session_reservation.Commit(); 109 session_reservation.Commit();
diff --git a/src/core/hle/kernel/k_client_port.h b/src/core/hle/kernel/k_client_port.h
index e17eff28f..81046fb86 100644
--- a/src/core/hle/kernel/k_client_port.h
+++ b/src/core/hle/kernel/k_client_port.h
@@ -52,8 +52,7 @@ public:
52 void Destroy() override; 52 void Destroy() override;
53 bool IsSignaled() const override; 53 bool IsSignaled() const override;
54 54
55 Result CreateSession(KClientSession** out, 55 Result CreateSession(KClientSession** out);
56 std::shared_ptr<SessionRequestManager> session_manager = nullptr);
57 56
58private: 57private:
59 std::atomic<s32> num_sessions{}; 58 std::atomic<s32> num_sessions{};
diff --git a/src/core/hle/kernel/k_port.cpp b/src/core/hle/kernel/k_port.cpp
index 7a5a9dc2a..77d00ae2c 100644
--- a/src/core/hle/kernel/k_port.cpp
+++ b/src/core/hle/kernel/k_port.cpp
@@ -57,12 +57,6 @@ Result KPort::EnqueueSession(KServerSession* session) {
57 57
58 server.EnqueueSession(session); 58 server.EnqueueSession(session);
59 59
60 if (auto session_ptr = server.GetSessionRequestHandler().lock()) {
61 session_ptr->ClientConnected(server.AcceptSession());
62 } else {
63 ASSERT(false);
64 }
65
66 return ResultSuccess; 60 return ResultSuccess;
67} 61}
68 62
diff --git a/src/core/hle/kernel/k_server_port.cpp b/src/core/hle/kernel/k_server_port.cpp
index e968f26ad..12e0c3ffb 100644
--- a/src/core/hle/kernel/k_server_port.cpp
+++ b/src/core/hle/kernel/k_server_port.cpp
@@ -19,6 +19,8 @@ void KServerPort::Initialize(KPort* parent_port_, std::string&& name_) {
19 // Set member variables. 19 // Set member variables.
20 parent = parent_port_; 20 parent = parent_port_;
21 name = std::move(name_); 21 name = std::move(name_);
22
23 kernel.RegisterServerObject(this);
22} 24}
23 25
24bool KServerPort::IsLight() const { 26bool KServerPort::IsLight() const {
@@ -62,9 +64,6 @@ void KServerPort::Destroy() {
62 // Close our reference to our parent. 64 // Close our reference to our parent.
63 parent->Close(); 65 parent->Close();
64 66
65 // Release host emulation members.
66 session_handler.reset();
67
68 // Ensure that the global list tracking server objects does not hold on to a reference. 67 // Ensure that the global list tracking server objects does not hold on to a reference.
69 kernel.UnregisterServerObject(this); 68 kernel.UnregisterServerObject(this);
70} 69}
diff --git a/src/core/hle/kernel/k_server_port.h b/src/core/hle/kernel/k_server_port.h
index fd4f4bd20..5fc7ee683 100644
--- a/src/core/hle/kernel/k_server_port.h
+++ b/src/core/hle/kernel/k_server_port.h
@@ -27,24 +27,6 @@ public:
27 27
28 void Initialize(KPort* parent_port_, std::string&& name_); 28 void Initialize(KPort* parent_port_, std::string&& name_);
29 29
30 /// Whether or not this server port has an HLE handler available.
31 bool HasSessionRequestHandler() const {
32 return !session_handler.expired();
33 }
34
35 /// Gets the HLE handler for this port.
36 SessionRequestHandlerWeakPtr GetSessionRequestHandler() const {
37 return session_handler;
38 }
39
40 /**
41 * Sets the HLE handler template for the port. ServerSessions crated by connecting to this port
42 * will inherit a reference to this handler.
43 */
44 void SetSessionHandler(SessionRequestHandlerWeakPtr&& handler) {
45 session_handler = std::move(handler);
46 }
47
48 void EnqueueSession(KServerSession* pending_session); 30 void EnqueueSession(KServerSession* pending_session);
49 31
50 KServerSession* AcceptSession(); 32 KServerSession* AcceptSession();
@@ -65,7 +47,6 @@ private:
65 void CleanupSessions(); 47 void CleanupSessions();
66 48
67 SessionList session_list; 49 SessionList session_list;
68 SessionRequestHandlerWeakPtr session_handler;
69 KPort* parent{}; 50 KPort* parent{};
70}; 51};
71 52
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp
index faf03fcc8..aa1941f01 100644
--- a/src/core/hle/kernel/k_server_session.cpp
+++ b/src/core/hle/kernel/k_server_session.cpp
@@ -1,4 +1,4 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <tuple> 4#include <tuple>
@@ -33,12 +33,10 @@ KServerSession::KServerSession(KernelCore& kernel_)
33 33
34KServerSession::~KServerSession() = default; 34KServerSession::~KServerSession() = default;
35 35
36void KServerSession::Initialize(KSession* parent_session_, std::string&& name_, 36void KServerSession::Initialize(KSession* parent_session_, std::string&& name_) {
37 std::shared_ptr<SessionRequestManager> manager_) {
38 // Set member variables. 37 // Set member variables.
39 parent = parent_session_; 38 parent = parent_session_;
40 name = std::move(name_); 39 name = std::move(name_);
41 manager = manager_;
42} 40}
43 41
44void KServerSession::Destroy() { 42void KServerSession::Destroy() {
@@ -47,18 +45,99 @@ void KServerSession::Destroy() {
47 this->CleanupRequests(); 45 this->CleanupRequests();
48 46
49 parent->Close(); 47 parent->Close();
50
51 // Release host emulation members.
52 manager.reset();
53
54 // Ensure that the global list tracking server objects does not hold on to a reference.
55 kernel.UnregisterServerObject(this);
56} 48}
57 49
58void KServerSession::OnClientClosed() { 50void KServerSession::OnClientClosed() {
59 if (manager && manager->HasSessionHandler()) { 51 KScopedLightLock lk{m_lock};
60 manager->SessionHandler().ClientDisconnected(this); 52
53 // Handle any pending requests.
54 KSessionRequest* prev_request = nullptr;
55 while (true) {
56 // Declare variables for processing the request.
57 KSessionRequest* request = nullptr;
58 KEvent* event = nullptr;
59 KThread* thread = nullptr;
60 bool cur_request = false;
61 bool terminate = false;
62
63 // Get the next request.
64 {
65 KScopedSchedulerLock sl{kernel};
66
67 if (m_current_request != nullptr && m_current_request != prev_request) {
68 // Set the request, open a reference as we process it.
69 request = m_current_request;
70 request->Open();
71 cur_request = true;
72
73 // Get thread and event for the request.
74 thread = request->GetThread();
75 event = request->GetEvent();
76
77 // If the thread is terminating, handle that.
78 if (thread->IsTerminationRequested()) {
79 request->ClearThread();
80 request->ClearEvent();
81 terminate = true;
82 }
83
84 prev_request = request;
85 } else if (!m_request_list.empty()) {
86 // Pop the request from the front of the list.
87 request = std::addressof(m_request_list.front());
88 m_request_list.pop_front();
89
90 // Get thread and event for the request.
91 thread = request->GetThread();
92 event = request->GetEvent();
93 }
94 }
95
96 // If there are no requests, we're done.
97 if (request == nullptr) {
98 break;
99 }
100
101 // All requests must have threads.
102 ASSERT(thread != nullptr);
103
104 // Ensure that we close the request when done.
105 SCOPE_EXIT({ request->Close(); });
106
107 // If we're terminating, close a reference to the thread and event.
108 if (terminate) {
109 thread->Close();
110 if (event != nullptr) {
111 event->Close();
112 }
113 }
114
115 // If we need to, reply.
116 if (event != nullptr && !cur_request) {
117 // There must be no mappings.
118 ASSERT(request->GetSendCount() == 0);
119 ASSERT(request->GetReceiveCount() == 0);
120 ASSERT(request->GetExchangeCount() == 0);
121
122 // // Get the process and page table.
123 // KProcess *client_process = thread->GetOwnerProcess();
124 // auto &client_pt = client_process->GetPageTable();
125
126 // // Reply to the request.
127 // ReplyAsyncError(client_process, request->GetAddress(), request->GetSize(),
128 // ResultSessionClosed);
129
130 // // Unlock the buffer.
131 // // NOTE: Nintendo does not check the result of this.
132 // client_pt.UnlockForIpcUserBuffer(request->GetAddress(), request->GetSize());
133
134 // Signal the event.
135 event->Signal();
136 }
61 } 137 }
138
139 // Notify.
140 this->NotifyAvailable(ResultSessionClosed);
62} 141}
63 142
64bool KServerSession::IsSignaled() const { 143bool KServerSession::IsSignaled() const {
@@ -73,24 +152,6 @@ bool KServerSession::IsSignaled() const {
73 return !m_request_list.empty() && m_current_request == nullptr; 152 return !m_request_list.empty() && m_current_request == nullptr;
74} 153}
75 154
76Result KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory) {
77 u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(thread->GetTLSAddress()))};
78 auto context = std::make_shared<HLERequestContext>(kernel, memory, this, thread);
79
80 context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
81
82 return manager->QueueSyncRequest(parent, std::move(context));
83}
84
85Result KServerSession::CompleteSyncRequest(HLERequestContext& context) {
86 Result result = manager->CompleteSyncRequest(this, context);
87
88 // The calling thread is waiting for this request to complete, so wake it up.
89 context.GetThread().EndWait(result);
90
91 return result;
92}
93
94Result KServerSession::OnRequest(KSessionRequest* request) { 155Result KServerSession::OnRequest(KSessionRequest* request) {
95 // Create the wait queue. 156 // Create the wait queue.
96 ThreadQueueImplForKServerSessionRequest wait_queue{kernel}; 157 ThreadQueueImplForKServerSessionRequest wait_queue{kernel};
@@ -105,24 +166,16 @@ Result KServerSession::OnRequest(KSessionRequest* request) {
105 // Check that we're not terminating. 166 // Check that we're not terminating.
106 R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), ResultTerminationRequested); 167 R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), ResultTerminationRequested);
107 168
108 if (manager) { 169 // Get whether we're empty.
109 // HLE request. 170 const bool was_empty = m_request_list.empty();
110 auto& memory{kernel.System().Memory()};
111 this->QueueSyncRequest(GetCurrentThreadPointer(kernel), memory);
112 } else {
113 // Non-HLE request.
114
115 // Get whether we're empty.
116 const bool was_empty = m_request_list.empty();
117 171
118 // Add the request to the list. 172 // Add the request to the list.
119 request->Open(); 173 request->Open();
120 m_request_list.push_back(*request); 174 m_request_list.push_back(*request);
121 175
122 // If we were empty, signal. 176 // If we were empty, signal.
123 if (was_empty) { 177 if (was_empty) {
124 this->NotifyAvailable(); 178 this->NotifyAvailable();
125 }
126 } 179 }
127 180
128 // If we have a request event, this is asynchronous, and we don't need to wait. 181 // If we have a request event, this is asynchronous, and we don't need to wait.
@@ -136,7 +189,7 @@ Result KServerSession::OnRequest(KSessionRequest* request) {
136 return GetCurrentThread(kernel).GetWaitResult(); 189 return GetCurrentThread(kernel).GetWaitResult();
137} 190}
138 191
139Result KServerSession::SendReply() { 192Result KServerSession::SendReply(bool is_hle) {
140 // Lock the session. 193 // Lock the session.
141 KScopedLightLock lk{m_lock}; 194 KScopedLightLock lk{m_lock};
142 195
@@ -171,13 +224,18 @@ Result KServerSession::SendReply() {
171 Result result = ResultSuccess; 224 Result result = ResultSuccess;
172 if (!closed) { 225 if (!closed) {
173 // If we're not closed, send the reply. 226 // If we're not closed, send the reply.
174 Core::Memory::Memory& memory{kernel.System().Memory()}; 227 if (is_hle) {
175 KThread* server_thread{GetCurrentThreadPointer(kernel)}; 228 // HLE servers write directly to a pointer to the thread command buffer. Therefore
176 UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess()); 229 // the reply has already been written in this case.
230 } else {
231 Core::Memory::Memory& memory{kernel.System().Memory()};
232 KThread* server_thread{GetCurrentThreadPointer(kernel)};
233 UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
177 234
178 auto* src_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress()); 235 auto* src_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress());
179 auto* dst_msg_buffer = memory.GetPointer(client_message); 236 auto* dst_msg_buffer = memory.GetPointer(client_message);
180 std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size); 237 std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
238 }
181 } else { 239 } else {
182 result = ResultSessionClosed; 240 result = ResultSessionClosed;
183 } 241 }
@@ -223,7 +281,8 @@ Result KServerSession::SendReply() {
223 return result; 281 return result;
224} 282}
225 283
226Result KServerSession::ReceiveRequest() { 284Result KServerSession::ReceiveRequest(std::shared_ptr<HLERequestContext>* out_context,
285 std::weak_ptr<SessionRequestManager> manager) {
227 // Lock the session. 286 // Lock the session.
228 KScopedLightLock lk{m_lock}; 287 KScopedLightLock lk{m_lock};
229 288
@@ -267,12 +326,22 @@ Result KServerSession::ReceiveRequest() {
267 326
268 // Receive the message. 327 // Receive the message.
269 Core::Memory::Memory& memory{kernel.System().Memory()}; 328 Core::Memory::Memory& memory{kernel.System().Memory()};
270 KThread* server_thread{GetCurrentThreadPointer(kernel)}; 329 if (out_context != nullptr) {
271 UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess()); 330 // HLE request.
331 u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(client_message))};
332 *out_context = std::make_shared<HLERequestContext>(kernel, memory, this, client_thread);
333 (*out_context)->SetSessionRequestManager(manager);
334 (*out_context)
335 ->PopulateFromIncomingCommandBuffer(client_thread->GetOwnerProcess()->GetHandleTable(),
336 cmd_buf);
337 } else {
338 KThread* server_thread{GetCurrentThreadPointer(kernel)};
339 UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
272 340
273 auto* src_msg_buffer = memory.GetPointer(client_message); 341 auto* src_msg_buffer = memory.GetPointer(client_message);
274 auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress()); 342 auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress());
275 std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size); 343 std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
344 }
276 345
277 // We succeeded. 346 // We succeeded.
278 return ResultSuccess; 347 return ResultSuccess;
diff --git a/src/core/hle/kernel/k_server_session.h b/src/core/hle/kernel/k_server_session.h
index 188aef4af..e4698d3f5 100644
--- a/src/core/hle/kernel/k_server_session.h
+++ b/src/core/hle/kernel/k_server_session.h
@@ -1,4 +1,4 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#pragma once 4#pragma once
@@ -16,21 +16,11 @@
16#include "core/hle/kernel/k_synchronization_object.h" 16#include "core/hle/kernel/k_synchronization_object.h"
17#include "core/hle/result.h" 17#include "core/hle/result.h"
18 18
19namespace Core::Memory {
20class Memory;
21}
22
23namespace Core::Timing {
24class CoreTiming;
25struct EventType;
26} // namespace Core::Timing
27
28namespace Kernel { 19namespace Kernel {
29 20
30class HLERequestContext; 21class HLERequestContext;
31class KernelCore; 22class KernelCore;
32class KSession; 23class KSession;
33class SessionRequestHandler;
34class SessionRequestManager; 24class SessionRequestManager;
35class KThread; 25class KThread;
36 26
@@ -46,8 +36,7 @@ public:
46 36
47 void Destroy() override; 37 void Destroy() override;
48 38
49 void Initialize(KSession* parent_session_, std::string&& name_, 39 void Initialize(KSession* parent_session_, std::string&& name_);
50 std::shared_ptr<SessionRequestManager> manager_);
51 40
52 KSession* GetParent() { 41 KSession* GetParent() {
53 return parent; 42 return parent;
@@ -60,32 +49,16 @@ public:
60 bool IsSignaled() const override; 49 bool IsSignaled() const override;
61 void OnClientClosed(); 50 void OnClientClosed();
62 51
63 /// Gets the session request manager, which forwards requests to the underlying service
64 std::shared_ptr<SessionRequestManager>& GetSessionRequestManager() {
65 return manager;
66 }
67
68 /// TODO: flesh these out to match the real kernel 52 /// TODO: flesh these out to match the real kernel
69 Result OnRequest(KSessionRequest* request); 53 Result OnRequest(KSessionRequest* request);
70 Result SendReply(); 54 Result SendReply(bool is_hle = false);
71 Result ReceiveRequest(); 55 Result ReceiveRequest(std::shared_ptr<HLERequestContext>* out_context = nullptr,
56 std::weak_ptr<SessionRequestManager> manager = {});
72 57
73private: 58private:
74 /// Frees up waiting client sessions when this server session is about to die 59 /// Frees up waiting client sessions when this server session is about to die
75 void CleanupRequests(); 60 void CleanupRequests();
76 61
77 /// Queues a sync request from the emulated application.
78 Result QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory);
79
80 /// Completes a sync request from the emulated application.
81 Result CompleteSyncRequest(HLERequestContext& context);
82
83 /// This session's HLE request handlers; if nullptr, this is not an HLE server
84 std::shared_ptr<SessionRequestManager> manager;
85
86 /// When set to True, converts the session to a domain at the end of the command
87 bool convert_to_domain{};
88
89 /// KSession that owns this KServerSession 62 /// KSession that owns this KServerSession
90 KSession* parent{}; 63 KSession* parent{};
91 64
diff --git a/src/core/hle/kernel/k_session.cpp b/src/core/hle/kernel/k_session.cpp
index ee05aa282..7a6534ac3 100644
--- a/src/core/hle/kernel/k_session.cpp
+++ b/src/core/hle/kernel/k_session.cpp
@@ -13,8 +13,7 @@ KSession::KSession(KernelCore& kernel_)
13 : KAutoObjectWithSlabHeapAndContainer{kernel_}, server{kernel_}, client{kernel_} {} 13 : KAutoObjectWithSlabHeapAndContainer{kernel_}, server{kernel_}, client{kernel_} {}
14KSession::~KSession() = default; 14KSession::~KSession() = default;
15 15
16void KSession::Initialize(KClientPort* port_, const std::string& name_, 16void KSession::Initialize(KClientPort* port_, const std::string& name_) {
17 std::shared_ptr<SessionRequestManager> manager_) {
18 // Increment reference count. 17 // Increment reference count.
19 // Because reference count is one on creation, this will result 18 // Because reference count is one on creation, this will result
20 // in a reference count of two. Thus, when both server and client are closed 19 // in a reference count of two. Thus, when both server and client are closed
@@ -26,7 +25,7 @@ void KSession::Initialize(KClientPort* port_, const std::string& name_,
26 KAutoObject::Create(std::addressof(client)); 25 KAutoObject::Create(std::addressof(client));
27 26
28 // Initialize our sub sessions. 27 // Initialize our sub sessions.
29 server.Initialize(this, name_ + ":Server", manager_); 28 server.Initialize(this, name_ + ":Server");
30 client.Initialize(this, name_ + ":Client"); 29 client.Initialize(this, name_ + ":Client");
31 30
32 // Set state and name. 31 // Set state and name.
diff --git a/src/core/hle/kernel/k_session.h b/src/core/hle/kernel/k_session.h
index c6ead403b..93e5e6f71 100644
--- a/src/core/hle/kernel/k_session.h
+++ b/src/core/hle/kernel/k_session.h
@@ -21,8 +21,7 @@ public:
21 explicit KSession(KernelCore& kernel_); 21 explicit KSession(KernelCore& kernel_);
22 ~KSession() override; 22 ~KSession() override;
23 23
24 void Initialize(KClientPort* port_, const std::string& name_, 24 void Initialize(KClientPort* port_, const std::string& name_);
25 std::shared_ptr<SessionRequestManager> manager_ = nullptr);
26 25
27 void Finalize() override; 26 void Finalize() override;
28 27
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index fdc774e30..29e122dfd 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -60,7 +60,6 @@ struct KernelCore::Impl {
60 global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel); 60 global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
61 global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel); 61 global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel);
62 global_handle_table->Initialize(KHandleTable::MaxTableSize); 62 global_handle_table->Initialize(KHandleTable::MaxTableSize);
63 default_service_thread = CreateServiceThread(kernel, "DefaultServiceThread");
64 63
65 is_phantom_mode_for_singlecore = false; 64 is_phantom_mode_for_singlecore = false;
66 65
@@ -86,6 +85,8 @@ struct KernelCore::Impl {
86 } 85 }
87 86
88 RegisterHostThread(); 87 RegisterHostThread();
88
89 default_service_thread = CreateServiceThread(kernel, "DefaultServiceThread");
89 } 90 }
90 91
91 void InitializeCores() { 92 void InitializeCores() {
@@ -703,6 +704,15 @@ struct KernelCore::Impl {
703 return port; 704 return port;
704 } 705 }
705 706
707 void RegisterNamedServiceHandler(std::string name, KServerPort* server_port) {
708 auto search = service_interface_handlers.find(name);
709 if (search == service_interface_handlers.end()) {
710 return;
711 }
712
713 search->second(system.ServiceManager(), server_port);
714 }
715
706 void RegisterServerObject(KAutoObject* server_object) { 716 void RegisterServerObject(KAutoObject* server_object) {
707 std::scoped_lock lk(server_objects_lock); 717 std::scoped_lock lk(server_objects_lock);
708 server_objects.insert(server_object); 718 server_objects.insert(server_object);
@@ -715,7 +725,7 @@ struct KernelCore::Impl {
715 725
716 std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(KernelCore& kernel, 726 std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(KernelCore& kernel,
717 const std::string& name) { 727 const std::string& name) {
718 auto service_thread = std::make_shared<Kernel::ServiceThread>(kernel, 1, name); 728 auto service_thread = std::make_shared<Kernel::ServiceThread>(kernel, name);
719 729
720 service_threads_manager.QueueWork( 730 service_threads_manager.QueueWork(
721 [this, service_thread]() { service_threads.emplace(service_thread); }); 731 [this, service_thread]() { service_threads.emplace(service_thread); });
@@ -774,6 +784,7 @@ struct KernelCore::Impl {
774 /// Map of named ports managed by the kernel, which can be retrieved using 784 /// Map of named ports managed by the kernel, which can be retrieved using
775 /// the ConnectToPort SVC. 785 /// the ConnectToPort SVC.
776 std::unordered_map<std::string, ServiceInterfaceFactory> service_interface_factory; 786 std::unordered_map<std::string, ServiceInterfaceFactory> service_interface_factory;
787 std::unordered_map<std::string, ServiceInterfaceHandlerFn> service_interface_handlers;
777 NamedPortTable named_ports; 788 NamedPortTable named_ports;
778 std::unordered_set<KAutoObject*> server_objects; 789 std::unordered_set<KAutoObject*> server_objects;
779 std::unordered_set<KAutoObject*> registered_objects; 790 std::unordered_set<KAutoObject*> registered_objects;
@@ -981,10 +992,19 @@ void KernelCore::RegisterNamedService(std::string name, ServiceInterfaceFactory&
981 impl->service_interface_factory.emplace(std::move(name), factory); 992 impl->service_interface_factory.emplace(std::move(name), factory);
982} 993}
983 994
995void KernelCore::RegisterInterfaceForNamedService(std::string name,
996 ServiceInterfaceHandlerFn&& handler) {
997 impl->service_interface_handlers.emplace(std::move(name), handler);
998}
999
984KClientPort* KernelCore::CreateNamedServicePort(std::string name) { 1000KClientPort* KernelCore::CreateNamedServicePort(std::string name) {
985 return impl->CreateNamedServicePort(std::move(name)); 1001 return impl->CreateNamedServicePort(std::move(name));
986} 1002}
987 1003
1004void KernelCore::RegisterNamedServiceHandler(std::string name, KServerPort* server_port) {
1005 impl->RegisterNamedServiceHandler(std::move(name), server_port);
1006}
1007
988void KernelCore::RegisterServerObject(KAutoObject* server_object) { 1008void KernelCore::RegisterServerObject(KAutoObject* server_object) {
989 impl->RegisterServerObject(server_object); 1009 impl->RegisterServerObject(server_object);
990} 1010}
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 266be2bc4..670f93ee3 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -45,6 +45,7 @@ class KPort;
45class KProcess; 45class KProcess;
46class KResourceLimit; 46class KResourceLimit;
47class KScheduler; 47class KScheduler;
48class KServerPort;
48class KServerSession; 49class KServerSession;
49class KSession; 50class KSession;
50class KSessionRequest; 51class KSessionRequest;
@@ -63,6 +64,8 @@ class TimeManager;
63using ServiceInterfaceFactory = 64using ServiceInterfaceFactory =
64 std::function<KClientPort&(Service::SM::ServiceManager&, Core::System&)>; 65 std::function<KClientPort&(Service::SM::ServiceManager&, Core::System&)>;
65 66
67using ServiceInterfaceHandlerFn = std::function<void(Service::SM::ServiceManager&, KServerPort*)>;
68
66namespace Init { 69namespace Init {
67struct KSlabResourceCounts; 70struct KSlabResourceCounts;
68} 71}
@@ -192,9 +195,15 @@ public:
192 /// Registers a named HLE service, passing a factory used to open a port to that service. 195 /// Registers a named HLE service, passing a factory used to open a port to that service.
193 void RegisterNamedService(std::string name, ServiceInterfaceFactory&& factory); 196 void RegisterNamedService(std::string name, ServiceInterfaceFactory&& factory);
194 197
198 /// Registers a setup function for the named HLE service.
199 void RegisterInterfaceForNamedService(std::string name, ServiceInterfaceHandlerFn&& handler);
200
195 /// Opens a port to a service previously registered with RegisterNamedService. 201 /// Opens a port to a service previously registered with RegisterNamedService.
196 KClientPort* CreateNamedServicePort(std::string name); 202 KClientPort* CreateNamedServicePort(std::string name);
197 203
204 /// Accepts a session on a port created by CreateNamedServicePort.
205 void RegisterNamedServiceHandler(std::string name, KServerPort* server_port);
206
198 /// Registers a server session or port with the gobal emulation state, to be freed on shutdown. 207 /// Registers a server session or port with the gobal emulation state, to be freed on shutdown.
199 /// This is necessary because we do not emulate processes for HLE sessions and ports. 208 /// This is necessary because we do not emulate processes for HLE sessions and ports.
200 void RegisterServerObject(KAutoObject* server_object); 209 void RegisterServerObject(KAutoObject* server_object);
diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp
index d23d76706..1fc2edf52 100644
--- a/src/core/hle/kernel/service_thread.cpp
+++ b/src/core/hle/kernel/service_thread.cpp
@@ -1,15 +1,17 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <condition_variable>
5#include <functional> 4#include <functional>
6#include <mutex> 5#include <mutex>
7#include <thread> 6#include <thread>
8#include <vector> 7#include <vector>
9#include <queue>
10 8
11#include "common/scope_exit.h" 9#include "common/scope_exit.h"
12#include "common/thread.h" 10#include "common/thread.h"
11#include "core/hle/ipc_helpers.h"
12#include "core/hle/kernel/hle_ipc.h"
13#include "core/hle/kernel/k_event.h"
14#include "core/hle/kernel/k_scoped_resource_reservation.h"
13#include "core/hle/kernel/k_session.h" 15#include "core/hle/kernel/k_session.h"
14#include "core/hle/kernel/k_thread.h" 16#include "core/hle/kernel/k_thread.h"
15#include "core/hle/kernel/kernel.h" 17#include "core/hle/kernel/kernel.h"
@@ -19,101 +21,201 @@ namespace Kernel {
19 21
20class ServiceThread::Impl final { 22class ServiceThread::Impl final {
21public: 23public:
22 explicit Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name); 24 explicit Impl(KernelCore& kernel, const std::string& service_name);
23 ~Impl(); 25 ~Impl();
24 26
25 void QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context); 27 void WaitAndProcessImpl();
28 void SessionClosed(KServerSession* server_session,
29 std::shared_ptr<SessionRequestManager> manager);
30 void LoopProcess();
31
32 void RegisterServerSession(KServerSession* session,
33 std::shared_ptr<SessionRequestManager> manager);
26 34
27private: 35private:
28 std::vector<std::jthread> threads; 36 KernelCore& kernel;
29 std::queue<std::function<void()>> requests; 37
30 std::mutex queue_mutex; 38 std::jthread m_thread;
31 std::condition_variable_any condition; 39 std::mutex m_session_mutex;
32 const std::string service_name; 40 std::vector<KServerSession*> m_sessions;
41 std::vector<std::shared_ptr<SessionRequestManager>> m_managers;
42 KEvent* m_wakeup_event;
43 KProcess* m_process;
44 std::atomic<bool> m_shutdown_requested;
45 const std::string m_service_name;
33}; 46};
34 47
35ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name) 48void ServiceThread::Impl::WaitAndProcessImpl() {
36 : service_name{name} { 49 // Create local list of waitable sessions.
37 for (std::size_t i = 0; i < num_threads; ++i) { 50 std::vector<KSynchronizationObject*> objs;
38 threads.emplace_back([this, &kernel](std::stop_token stop_token) { 51 std::vector<std::shared_ptr<SessionRequestManager>> managers;
39 Common::SetCurrentThreadName(std::string{service_name}.c_str());
40 52
41 // Wait for first request before trying to acquire a render context 53 {
42 { 54 // Lock to get the list.
43 std::unique_lock lock{queue_mutex}; 55 std::scoped_lock lk{m_session_mutex};
44 condition.wait(lock, stop_token, [this] { return !requests.empty(); });
45 }
46 56
47 if (stop_token.stop_requested()) { 57 // Resize to the needed quantity.
48 return; 58 objs.resize(m_sessions.size() + 1);
49 } 59 managers.resize(m_managers.size());
50 60
51 // Allocate a dummy guest thread for this host thread. 61 // Copy to our local list.
52 kernel.RegisterHostThread(); 62 std::copy(m_sessions.begin(), m_sessions.end(), objs.begin());
63 std::copy(m_managers.begin(), m_managers.end(), managers.begin());
53 64
54 while (true) { 65 // Insert the wakeup event at the end.
55 std::function<void()> task; 66 objs.back() = &m_wakeup_event->GetReadableEvent();
67 }
56 68
57 { 69 // Wait on the list of sessions.
58 std::unique_lock lock{queue_mutex}; 70 s32 index{-1};
59 condition.wait(lock, stop_token, [this] { return !requests.empty(); }); 71 Result rc = KSynchronizationObject::Wait(kernel, &index, objs.data(),
72 static_cast<s32>(objs.size()), -1);
73 ASSERT(!rc.IsFailure());
74
75 // If this was the wakeup event, clear it and finish.
76 if (index >= static_cast<s64>(objs.size() - 1)) {
77 m_wakeup_event->Clear();
78 return;
79 }
60 80
61 if (stop_token.stop_requested()) { 81 // This event is from a server session.
62 return; 82 auto* server_session = static_cast<KServerSession*>(objs[index]);
63 } 83 auto& manager = managers[index];
64 84
65 if (requests.empty()) { 85 // Fetch the HLE request context.
66 continue; 86 std::shared_ptr<HLERequestContext> context;
67 } 87 rc = server_session->ReceiveRequest(&context, manager);
68 88
69 task = std::move(requests.front()); 89 // If the session was closed, handle that.
70 requests.pop(); 90 if (rc == ResultSessionClosed) {
71 } 91 SessionClosed(server_session, manager);
72 92
73 task(); 93 // Finish.
74 } 94 return;
75 });
76 } 95 }
96
97 // TODO: handle other cases
98 ASSERT(rc == ResultSuccess);
99
100 // Perform the request.
101 Result service_rc = manager->CompleteSyncRequest(server_session, *context);
102
103 // Reply to the client.
104 rc = server_session->SendReply(true);
105
106 if (rc == ResultSessionClosed || service_rc == IPC::ERR_REMOTE_PROCESS_DEAD) {
107 SessionClosed(server_session, manager);
108 return;
109 }
110
111 // TODO: handle other cases
112 ASSERT(rc == ResultSuccess);
113 ASSERT(service_rc == ResultSuccess);
77} 114}
78 115
79void ServiceThread::Impl::QueueSyncRequest(KSession& session, 116void ServiceThread::Impl::SessionClosed(KServerSession* server_session,
80 std::shared_ptr<HLERequestContext>&& context) { 117 std::shared_ptr<SessionRequestManager> manager) {
81 { 118 {
82 std::unique_lock lock{queue_mutex}; 119 // Lock to get the list.
120 std::scoped_lock lk{m_session_mutex};
121
122 // Get the index of the session.
123 const auto index =
124 std::find(m_sessions.begin(), m_sessions.end(), server_session) - m_sessions.begin();
125 ASSERT(index < static_cast<s64>(m_sessions.size()));
126
127 // Remove the session and its manager.
128 m_sessions.erase(m_sessions.begin() + index);
129 m_managers.erase(m_managers.begin() + index);
130 }
83 131
84 auto* server_session{&session.GetServerSession()}; 132 // Close our reference to the server session.
133 server_session->Close();
134}
85 135
86 // Open a reference to the session to ensure it is not closes while the service request 136void ServiceThread::Impl::LoopProcess() {
87 // completes asynchronously. 137 Common::SetCurrentThreadName(m_service_name.c_str());
88 server_session->Open();
89 138
90 requests.emplace([server_session, context{std::move(context)}]() { 139 kernel.RegisterHostThread();
91 // Close the reference.
92 SCOPE_EXIT({ server_session->Close(); });
93 140
94 // Complete the service request. 141 while (!m_shutdown_requested.load()) {
95 server_session->CompleteSyncRequest(*context); 142 WaitAndProcessImpl();
96 });
97 } 143 }
98 condition.notify_one(); 144}
145
146void ServiceThread::Impl::RegisterServerSession(KServerSession* server_session,
147 std::shared_ptr<SessionRequestManager> manager) {
148 // Open the server session.
149 server_session->Open();
150
151 {
152 // Lock to get the list.
153 std::scoped_lock lk{m_session_mutex};
154
155 // Insert the session and manager.
156 m_sessions.push_back(server_session);
157 m_managers.push_back(manager);
158 }
159
160 // Signal the wakeup event.
161 m_wakeup_event->Signal();
99} 162}
100 163
101ServiceThread::Impl::~Impl() { 164ServiceThread::Impl::~Impl() {
102 condition.notify_all(); 165 // Shut down the processing thread.
103 for (auto& thread : threads) { 166 m_shutdown_requested.store(true);
104 thread.request_stop(); 167 m_wakeup_event->Signal();
105 thread.join(); 168 m_thread.join();
169
170 // Lock mutex.
171 m_session_mutex.lock();
172
173 // Close all remaining sessions.
174 for (size_t i = 0; i < m_sessions.size(); i++) {
175 m_sessions[i]->Close();
106 } 176 }
177
178 // Close event.
179 m_wakeup_event->GetReadableEvent().Close();
180 m_wakeup_event->Close();
181
182 // Close process.
183 m_process->Close();
184}
185
186ServiceThread::Impl::Impl(KernelCore& kernel_, const std::string& service_name)
187 : kernel{kernel_}, m_service_name{service_name} {
188 // Initialize process.
189 m_process = KProcess::Create(kernel);
190 KProcess::Initialize(m_process, kernel.System(), service_name,
191 KProcess::ProcessType::KernelInternal, kernel.GetSystemResourceLimit());
192
193 // Reserve a new event from the process resource limit
194 KScopedResourceReservation event_reservation(m_process, LimitableResource::Events);
195 ASSERT(event_reservation.Succeeded());
196
197 // Initialize event.
198 m_wakeup_event = KEvent::Create(kernel);
199 m_wakeup_event->Initialize(m_process);
200
201 // Commit the event reservation.
202 event_reservation.Commit();
203
204 // Register the event.
205 KEvent::Register(kernel, m_wakeup_event);
206
207 // Start thread.
208 m_thread = std::jthread([this] { LoopProcess(); });
107} 209}
108 210
109ServiceThread::ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name) 211ServiceThread::ServiceThread(KernelCore& kernel, const std::string& name)
110 : impl{std::make_unique<Impl>(kernel, num_threads, name)} {} 212 : impl{std::make_unique<Impl>(kernel, name)} {}
111 213
112ServiceThread::~ServiceThread() = default; 214ServiceThread::~ServiceThread() = default;
113 215
114void ServiceThread::QueueSyncRequest(KSession& session, 216void ServiceThread::RegisterServerSession(KServerSession* session,
115 std::shared_ptr<HLERequestContext>&& context) { 217 std::shared_ptr<SessionRequestManager> manager) {
116 impl->QueueSyncRequest(session, std::move(context)); 218 impl->RegisterServerSession(session, manager);
117} 219}
118 220
119} // namespace Kernel 221} // namespace Kernel
diff --git a/src/core/hle/kernel/service_thread.h b/src/core/hle/kernel/service_thread.h
index c5896f2bd..fb4325531 100644
--- a/src/core/hle/kernel/service_thread.h
+++ b/src/core/hle/kernel/service_thread.h
@@ -11,13 +11,15 @@ namespace Kernel {
11class HLERequestContext; 11class HLERequestContext;
12class KernelCore; 12class KernelCore;
13class KSession; 13class KSession;
14class SessionRequestManager;
14 15
15class ServiceThread final { 16class ServiceThread final {
16public: 17public:
17 explicit ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name); 18 explicit ServiceThread(KernelCore& kernel, const std::string& name);
18 ~ServiceThread(); 19 ~ServiceThread();
19 20
20 void QueueSyncRequest(KSession& session, std::shared_ptr<HLERequestContext>&& context); 21 void RegisterServerSession(KServerSession* session,
22 std::shared_ptr<SessionRequestManager> manager);
21 23
22private: 24private:
23 class Impl; 25 class Impl;
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 4aca5b27d..8d2c7d6b7 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -24,6 +24,7 @@
24#include "core/hle/kernel/k_memory_block.h" 24#include "core/hle/kernel/k_memory_block.h"
25#include "core/hle/kernel/k_memory_layout.h" 25#include "core/hle/kernel/k_memory_layout.h"
26#include "core/hle/kernel/k_page_table.h" 26#include "core/hle/kernel/k_page_table.h"
27#include "core/hle/kernel/k_port.h"
27#include "core/hle/kernel/k_process.h" 28#include "core/hle/kernel/k_process.h"
28#include "core/hle/kernel/k_readable_event.h" 29#include "core/hle/kernel/k_readable_event.h"
29#include "core/hle/kernel/k_resource_limit.h" 30#include "core/hle/kernel/k_resource_limit.h"
@@ -382,10 +383,11 @@ static Result ConnectToNamedPort(Core::System& system, Handle* out, VAddr port_n
382 383
383 // Create a session. 384 // Create a session.
384 KClientSession* session{}; 385 KClientSession* session{};
385 R_TRY(port->CreateSession(std::addressof(session), 386 R_TRY(port->CreateSession(std::addressof(session)));
386 std::make_shared<SessionRequestManager>(kernel)));
387 port->Close(); 387 port->Close();
388 388
389 kernel.RegisterNamedServiceHandler(port_name, &port->GetParent()->GetServerPort());
390
389 // Register the session in the table, close the extra reference. 391 // Register the session in the table, close the extra reference.
390 handle_table.Register(*out, session); 392 handle_table.Register(*out, session);
391 session->Close(); 393 session->Close();