summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/hle/kernel/hle_ipc.h9
-rw-r--r--src/core/hle/service/server_manager.cpp100
-rw-r--r--src/core/hle/service/server_manager.h16
-rw-r--r--src/core/hle/service/sm/sm.cpp29
-rw-r--r--src/core/hle/service/sm/sm.h5
5 files changed, 151 insertions, 8 deletions
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 059b21991..6cbc974fe 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -358,6 +358,14 @@ public:
358 return manager.lock(); 358 return manager.lock();
359 } 359 }
360 360
361 bool GetIsDeferred() const {
362 return is_deferred;
363 }
364
365 void SetIsDeferred(bool is_deferred_ = true) {
366 is_deferred = is_deferred_;
367 }
368
361private: 369private:
362 friend class IPC::ResponseBuilder; 370 friend class IPC::ResponseBuilder;
363 371
@@ -392,6 +400,7 @@ private:
392 u32 domain_offset{}; 400 u32 domain_offset{};
393 401
394 std::weak_ptr<SessionRequestManager> manager{}; 402 std::weak_ptr<SessionRequestManager> manager{};
403 bool is_deferred{false};
395 404
396 KernelCore& kernel; 405 KernelCore& kernel;
397 Core::Memory::Memory& memory; 406 Core::Memory::Memory& memory;
diff --git a/src/core/hle/service/server_manager.cpp b/src/core/hle/service/server_manager.cpp
index 55788ddeb..1b3db3caf 100644
--- a/src/core/hle/service/server_manager.cpp
+++ b/src/core/hle/service/server_manager.cpp
@@ -25,6 +25,7 @@ constexpr size_t MaximumWaitObjects = 0x40;
25enum HandleType { 25enum HandleType {
26 Port, 26 Port,
27 Session, 27 Session,
28 DeferEvent,
28 Event, 29 Event,
29}; 30};
30 31
@@ -53,9 +54,18 @@ ServerManager::~ServerManager() {
53 session->Close(); 54 session->Close();
54 } 55 }
55 56
57 for (const auto& request : m_deferrals) {
58 request.session->Close();
59 }
60
56 // Close event. 61 // Close event.
57 m_event->GetReadableEvent().Close(); 62 m_event->GetReadableEvent().Close();
58 m_event->Close(); 63 m_event->Close();
64
65 if (m_deferral_event) {
66 m_deferral_event->GetReadableEvent().Close();
67 // Write event is owned by ServiceManager
68 }
59} 69}
60 70
61void ServerManager::RunServer(std::unique_ptr<ServerManager>&& server_manager) { 71void ServerManager::RunServer(std::unique_ptr<ServerManager>&& server_manager) {
@@ -142,6 +152,21 @@ Result ServerManager::ManageNamedPort(const std::string& service_name,
142 R_SUCCEED(); 152 R_SUCCEED();
143} 153}
144 154
155Result ServerManager::ManageDeferral(Kernel::KEvent** out_event) {
156 // Create a new event.
157 m_deferral_event = Kernel::KEvent::Create(m_system.Kernel());
158 ASSERT(m_deferral_event != nullptr);
159
160 // Initialize the event.
161 m_deferral_event->Initialize(nullptr);
162
163 // Set the output.
164 *out_event = m_deferral_event;
165
166 // We succeeded.
167 R_SUCCEED();
168}
169
145void ServerManager::StartAdditionalHostThreads(const char* name, size_t num_threads) { 170void ServerManager::StartAdditionalHostThreads(const char* name, size_t num_threads) {
146 for (size_t i = 0; i < num_threads; i++) { 171 for (size_t i = 0; i < num_threads; i++) {
147 auto thread_name = fmt::format("{}:{}", name, i + 1); 172 auto thread_name = fmt::format("{}:{}", name, i + 1);
@@ -207,6 +232,11 @@ Result ServerManager::WaitAndProcessImpl() {
207 } 232 }
208 } 233 }
209 234
235 // Add the deferral wakeup event.
236 if (m_deferral_event != nullptr) {
237 AddWaiter(std::addressof(m_deferral_event->GetReadableEvent()), HandleType::DeferEvent);
238 }
239
210 // Add the wakeup event. 240 // Add the wakeup event.
211 AddWaiter(std::addressof(m_event->GetReadableEvent()), HandleType::Event); 241 AddWaiter(std::addressof(m_event->GetReadableEvent()), HandleType::Event);
212 242
@@ -270,6 +300,23 @@ Result ServerManager::WaitAndProcessImpl() {
270 // Finish. 300 // Finish.
271 R_RETURN(this->OnSessionEvent(session, std::move(manager))); 301 R_RETURN(this->OnSessionEvent(session, std::move(manager)));
272 } 302 }
303 case HandleType::DeferEvent: {
304 // Clear event.
305 ASSERT(R_SUCCEEDED(m_deferral_event->Clear()));
306
307 // Drain the list of deferrals while we process.
308 std::list<RequestState> deferrals;
309 {
310 std::scoped_lock ll{m_list_mutex};
311 m_deferrals.swap(deferrals);
312 }
313
314 // Allow other threads to serve.
315 sl.unlock();
316
317 // Finish.
318 R_RETURN(this->OnDeferralEvent(std::move(deferrals)));
319 }
273 case HandleType::Event: { 320 case HandleType::Event: {
274 // Clear event and finish. 321 // Clear event and finish.
275 R_RETURN(m_event->Clear()); 322 R_RETURN(m_event->Clear());
@@ -308,7 +355,6 @@ Result ServerManager::OnPortEvent(Kernel::KServerPort* port,
308Result ServerManager::OnSessionEvent(Kernel::KServerSession* session, 355Result ServerManager::OnSessionEvent(Kernel::KServerSession* session,
309 std::shared_ptr<Kernel::SessionRequestManager>&& manager) { 356 std::shared_ptr<Kernel::SessionRequestManager>&& manager) {
310 Result rc{ResultSuccess}; 357 Result rc{ResultSuccess};
311 Result service_rc{ResultSuccess};
312 358
313 // Try to receive a message. 359 // Try to receive a message.
314 std::shared_ptr<Kernel::HLERequestContext> context; 360 std::shared_ptr<Kernel::HLERequestContext> context;
@@ -324,16 +370,43 @@ Result ServerManager::OnSessionEvent(Kernel::KServerSession* session,
324 } 370 }
325 ASSERT(R_SUCCEEDED(rc)); 371 ASSERT(R_SUCCEEDED(rc));
326 372
373 RequestState request{
374 .session = session,
375 .context = std::move(context),
376 .manager = std::move(manager),
377 };
378
379 // Complete the sync request with deferral handling.
380 R_RETURN(this->CompleteSyncRequest(std::move(request)));
381}
382
383Result ServerManager::CompleteSyncRequest(RequestState&& request) {
384 Result rc{ResultSuccess};
385 Result service_rc{ResultSuccess};
386
387 // Mark the request as not deferred.
388 request.context->SetIsDeferred(false);
389
327 // Complete the request. We have exclusive access to this session. 390 // Complete the request. We have exclusive access to this session.
328 service_rc = manager->CompleteSyncRequest(session, *context); 391 service_rc = request.manager->CompleteSyncRequest(request.session, *request.context);
392
393 // If we've been deferred, we're done.
394 if (request.context->GetIsDeferred()) {
395 // Insert into deferral list.
396 std::scoped_lock ll{m_list_mutex};
397 m_deferrals.emplace_back(std::move(request));
398
399 // Finish.
400 R_SUCCEED();
401 }
329 402
330 // Send the reply. 403 // Send the reply.
331 rc = session->SendReplyHLE(); 404 rc = request.session->SendReplyHLE();
332 405
333 // If the session has been closed, we're done. 406 // If the session has been closed, we're done.
334 if (rc == Kernel::ResultSessionClosed || service_rc == IPC::ERR_REMOTE_PROCESS_DEAD) { 407 if (rc == Kernel::ResultSessionClosed || service_rc == IPC::ERR_REMOTE_PROCESS_DEAD) {
335 // Close the session. 408 // Close the session.
336 session->Close(); 409 request.session->Close();
337 410
338 // Finish. 411 // Finish.
339 R_SUCCEED(); 412 R_SUCCEED();
@@ -345,7 +418,7 @@ Result ServerManager::OnSessionEvent(Kernel::KServerSession* session,
345 // Reinsert the session. 418 // Reinsert the session.
346 { 419 {
347 std::scoped_lock ll{m_list_mutex}; 420 std::scoped_lock ll{m_list_mutex};
348 m_sessions.emplace(session, std::move(manager)); 421 m_sessions.emplace(request.session, std::move(request.manager));
349 } 422 }
350 423
351 // Signal the wakeup event. 424 // Signal the wakeup event.
@@ -355,4 +428,21 @@ Result ServerManager::OnSessionEvent(Kernel::KServerSession* session,
355 R_SUCCEED(); 428 R_SUCCEED();
356} 429}
357 430
431Result ServerManager::OnDeferralEvent(std::list<RequestState>&& deferrals) {
432 ON_RESULT_FAILURE {
433 std::scoped_lock ll{m_list_mutex};
434 m_deferrals.splice(m_deferrals.end(), deferrals);
435 };
436
437 while (!deferrals.empty()) {
438 RequestState request = deferrals.front();
439 deferrals.pop_front();
440
441 // Try again to complete the request.
442 R_TRY(this->CompleteSyncRequest(std::move(request)));
443 }
444
445 R_SUCCEED();
446}
447
358} // namespace Service 448} // namespace Service
diff --git a/src/core/hle/service/server_manager.h b/src/core/hle/service/server_manager.h
index b26557172..57b954ae8 100644
--- a/src/core/hle/service/server_manager.h
+++ b/src/core/hle/service/server_manager.h
@@ -5,6 +5,7 @@
5 5
6#include <atomic> 6#include <atomic>
7#include <functional> 7#include <functional>
8#include <list>
8#include <map> 9#include <map>
9#include <mutex> 10#include <mutex>
10#include <string_view> 11#include <string_view>
@@ -19,6 +20,7 @@ class System;
19} 20}
20 21
21namespace Kernel { 22namespace Kernel {
23class HLERequestContext;
22class KEvent; 24class KEvent;
23class KServerPort; 25class KServerPort;
24class KServerSession; 26class KServerSession;
@@ -42,6 +44,7 @@ public:
42 Result ManageNamedPort(const std::string& service_name, 44 Result ManageNamedPort(const std::string& service_name,
43 std::shared_ptr<Kernel::SessionRequestHandler>&& handler, 45 std::shared_ptr<Kernel::SessionRequestHandler>&& handler,
44 u32 max_sessions = 64); 46 u32 max_sessions = 64);
47 Result ManageDeferral(Kernel::KEvent** out_event);
45 48
46 Result LoopProcess(); 49 Result LoopProcess();
47 void StartAdditionalHostThreads(const char* name, size_t num_threads); 50 void StartAdditionalHostThreads(const char* name, size_t num_threads);
@@ -49,12 +52,16 @@ public:
49 static void RunServer(std::unique_ptr<ServerManager>&& server); 52 static void RunServer(std::unique_ptr<ServerManager>&& server);
50 53
51private: 54private:
55 struct RequestState;
56
52 Result LoopProcessImpl(); 57 Result LoopProcessImpl();
53 Result WaitAndProcessImpl(); 58 Result WaitAndProcessImpl();
54 Result OnPortEvent(Kernel::KServerPort* port, 59 Result OnPortEvent(Kernel::KServerPort* port,
55 std::shared_ptr<Kernel::SessionRequestHandler>&& handler); 60 std::shared_ptr<Kernel::SessionRequestHandler>&& handler);
56 Result OnSessionEvent(Kernel::KServerSession* session, 61 Result OnSessionEvent(Kernel::KServerSession* session,
57 std::shared_ptr<Kernel::SessionRequestManager>&& manager); 62 std::shared_ptr<Kernel::SessionRequestManager>&& manager);
63 Result OnDeferralEvent(std::list<RequestState>&& deferrals);
64 Result CompleteSyncRequest(RequestState&& state);
58 65
59private: 66private:
60 Core::System& m_system; 67 Core::System& m_system;
@@ -65,6 +72,15 @@ private:
65 std::map<Kernel::KServerPort*, std::shared_ptr<Kernel::SessionRequestHandler>> m_ports{}; 72 std::map<Kernel::KServerPort*, std::shared_ptr<Kernel::SessionRequestHandler>> m_ports{};
66 std::map<Kernel::KServerSession*, std::shared_ptr<Kernel::SessionRequestManager>> m_sessions{}; 73 std::map<Kernel::KServerSession*, std::shared_ptr<Kernel::SessionRequestManager>> m_sessions{};
67 Kernel::KEvent* m_event{}; 74 Kernel::KEvent* m_event{};
75 Kernel::KEvent* m_deferral_event{};
76
77 // Deferral tracking
78 struct RequestState {
79 Kernel::KServerSession* session;
80 std::shared_ptr<Kernel::HLERequestContext> context;
81 std::shared_ptr<Kernel::SessionRequestManager> manager;
82 };
83 std::list<RequestState> m_deferrals{};
68 84
69 // Host state tracking 85 // Host state tracking
70 std::atomic<bool> m_stopped{}; 86 std::atomic<bool> m_stopped{};
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 0de32b05d..6eba48f03 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -32,6 +32,10 @@ ServiceManager::~ServiceManager() {
32 port->GetClientPort().Close(); 32 port->GetClientPort().Close();
33 port->GetServerPort().Close(); 33 port->GetServerPort().Close();
34 } 34 }
35
36 if (deferral_event) {
37 deferral_event->Close();
38 }
35} 39}
36 40
37void ServiceManager::InvokeControlRequest(Kernel::HLERequestContext& context) { 41void ServiceManager::InvokeControlRequest(Kernel::HLERequestContext& context) {
@@ -62,6 +66,9 @@ Result ServiceManager::RegisterService(std::string name, u32 max_sessions,
62 66
63 service_ports.emplace(name, port); 67 service_ports.emplace(name, port);
64 registered_services.emplace(name, handler); 68 registered_services.emplace(name, handler);
69 if (deferral_event) {
70 deferral_event->Signal();
71 }
65 72
66 return ResultSuccess; 73 return ResultSuccess;
67} 74}
@@ -88,7 +95,7 @@ ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name
88 std::scoped_lock lk{lock}; 95 std::scoped_lock lk{lock};
89 auto it = service_ports.find(name); 96 auto it = service_ports.find(name);
90 if (it == service_ports.end()) { 97 if (it == service_ports.end()) {
91 LOG_ERROR(Service_SM, "Server is not registered! service={}", name); 98 LOG_WARNING(Service_SM, "Server is not registered! service={}", name);
92 return ERR_SERVICE_NOT_REGISTERED; 99 return ERR_SERVICE_NOT_REGISTERED;
93 } 100 }
94 101
@@ -113,6 +120,11 @@ void SM::Initialize(Kernel::HLERequestContext& ctx) {
113 120
114void SM::GetService(Kernel::HLERequestContext& ctx) { 121void SM::GetService(Kernel::HLERequestContext& ctx) {
115 auto result = GetServiceImpl(ctx); 122 auto result = GetServiceImpl(ctx);
123 if (ctx.GetIsDeferred()) {
124 // Don't overwrite the command buffer.
125 return;
126 }
127
116 if (result.Succeeded()) { 128 if (result.Succeeded()) {
117 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; 129 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
118 rb.Push(result.Code()); 130 rb.Push(result.Code());
@@ -125,6 +137,11 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
125 137
126void SM::GetServiceTipc(Kernel::HLERequestContext& ctx) { 138void SM::GetServiceTipc(Kernel::HLERequestContext& ctx) {
127 auto result = GetServiceImpl(ctx); 139 auto result = GetServiceImpl(ctx);
140 if (ctx.GetIsDeferred()) {
141 // Don't overwrite the command buffer.
142 return;
143 }
144
128 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; 145 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
129 rb.Push(result.Code()); 146 rb.Push(result.Code());
130 rb.PushMoveObjects(result.Succeeded() ? result.Unwrap() : nullptr); 147 rb.PushMoveObjects(result.Succeeded() ? result.Unwrap() : nullptr);
@@ -152,8 +169,9 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext&
152 // Find the named port. 169 // Find the named port.
153 auto port_result = service_manager.GetServicePort(name); 170 auto port_result = service_manager.GetServicePort(name);
154 if (port_result.Failed()) { 171 if (port_result.Failed()) {
155 LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, port_result.Code().raw); 172 LOG_INFO(Service_SM, "Waiting for service {} to become available", name);
156 return port_result.Code(); 173 ctx.SetIsDeferred();
174 return ERR_SERVICE_NOT_REGISTERED;
157 } 175 }
158 auto& port = port_result.Unwrap(); 176 auto& port = port_result.Unwrap();
159 177
@@ -228,8 +246,13 @@ SM::SM(ServiceManager& service_manager_, Core::System& system_)
228SM::~SM() = default; 246SM::~SM() = default;
229 247
230void LoopProcess(Core::System& system) { 248void LoopProcess(Core::System& system) {
249 auto& service_manager = system.ServiceManager();
231 auto server_manager = std::make_unique<ServerManager>(system); 250 auto server_manager = std::make_unique<ServerManager>(system);
232 251
252 Kernel::KEvent* deferral_event{};
253 server_manager->ManageDeferral(&deferral_event);
254 service_manager.SetDeferralEvent(deferral_event);
255
233 server_manager->ManageNamedPort("sm:", std::make_shared<SM>(system.ServiceManager(), system)); 256 server_manager->ManageNamedPort("sm:", std::make_shared<SM>(system.ServiceManager(), system));
234 ServerManager::RunServer(std::move(server_manager)); 257 ServerManager::RunServer(std::move(server_manager));
235} 258}
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index 22ca720f8..b7eeafdd6 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -71,6 +71,10 @@ public:
71 71
72 void InvokeControlRequest(Kernel::HLERequestContext& context); 72 void InvokeControlRequest(Kernel::HLERequestContext& context);
73 73
74 void SetDeferralEvent(Kernel::KEvent* deferral_event_) {
75 deferral_event = deferral_event_;
76 }
77
74private: 78private:
75 std::shared_ptr<SM> sm_interface; 79 std::shared_ptr<SM> sm_interface;
76 std::unique_ptr<Controller> controller_interface; 80 std::unique_ptr<Controller> controller_interface;
@@ -82,6 +86,7 @@ private:
82 86
83 /// Kernel context 87 /// Kernel context
84 Kernel::KernelCore& kernel; 88 Kernel::KernelCore& kernel;
89 Kernel::KEvent* deferral_event{};
85}; 90};
86 91
87/// Runs SM services. 92/// Runs SM services.