service_thread.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <functional>
  4. #include <map>
  5. #include <mutex>
  6. #include <thread>
  7. #include <vector>
  8. #include "common/scope_exit.h"
  9. #include "common/thread.h"
  10. #include "core/hle/ipc_helpers.h"
  11. #include "core/hle/kernel/hle_ipc.h"
  12. #include "core/hle/kernel/k_event.h"
  13. #include "core/hle/kernel/k_scoped_resource_reservation.h"
  14. #include "core/hle/kernel/k_session.h"
  15. #include "core/hle/kernel/k_thread.h"
  16. #include "core/hle/kernel/kernel.h"
  17. #include "core/hle/kernel/service_thread.h"
  18. namespace Kernel {
  19. class ServiceThread::Impl final {
  20. public:
  21. explicit Impl(KernelCore& kernel, const std::string& service_name);
  22. ~Impl();
  23. void WaitAndProcessImpl();
  24. void SessionClosed(KServerSession* server_session,
  25. std::shared_ptr<SessionRequestManager> manager);
  26. void LoopProcess();
  27. void RegisterServerSession(KServerSession* session,
  28. std::shared_ptr<SessionRequestManager> manager);
  29. private:
  30. KernelCore& kernel;
  31. std::jthread m_host_thread;
  32. std::mutex m_session_mutex;
  33. std::map<KServerSession*, std::shared_ptr<SessionRequestManager>> m_sessions;
  34. KEvent* m_wakeup_event;
  35. KProcess* m_process;
  36. KThread* m_thread;
  37. std::atomic<bool> m_shutdown_requested;
  38. const std::string m_service_name;
  39. };
  40. void ServiceThread::Impl::WaitAndProcessImpl() {
  41. // Create local list of waitable sessions.
  42. std::vector<KSynchronizationObject*> objs;
  43. std::vector<std::shared_ptr<SessionRequestManager>> managers;
  44. {
  45. // Lock to get the set.
  46. std::scoped_lock lk{m_session_mutex};
  47. // Reserve the needed quantity.
  48. objs.reserve(m_sessions.size() + 1);
  49. managers.reserve(m_sessions.size());
  50. // Copy to our local list.
  51. for (const auto& [session, manager] : m_sessions) {
  52. objs.push_back(session);
  53. managers.push_back(manager);
  54. }
  55. // Insert the wakeup event at the end.
  56. objs.push_back(&m_wakeup_event->GetReadableEvent());
  57. }
  58. // Wait on the list of sessions.
  59. s32 index{-1};
  60. Result rc = KSynchronizationObject::Wait(kernel, &index, objs.data(),
  61. static_cast<s32>(objs.size()), -1);
  62. ASSERT(!rc.IsFailure());
  63. // If this was the wakeup event, clear it and finish.
  64. if (index >= static_cast<s64>(objs.size() - 1)) {
  65. m_wakeup_event->Clear();
  66. return;
  67. }
  68. // This event is from a server session.
  69. auto* server_session = static_cast<KServerSession*>(objs[index]);
  70. auto& manager = managers[index];
  71. // Fetch the HLE request context.
  72. std::shared_ptr<HLERequestContext> context;
  73. rc = server_session->ReceiveRequest(&context, manager);
  74. // If the session was closed, handle that.
  75. if (rc == ResultSessionClosed) {
  76. SessionClosed(server_session, manager);
  77. // Finish.
  78. return;
  79. }
  80. // TODO: handle other cases
  81. ASSERT(rc == ResultSuccess);
  82. // Perform the request.
  83. Result service_rc = manager->CompleteSyncRequest(server_session, *context);
  84. // Reply to the client.
  85. rc = server_session->SendReplyHLE();
  86. if (rc == ResultSessionClosed || service_rc == IPC::ERR_REMOTE_PROCESS_DEAD) {
  87. SessionClosed(server_session, manager);
  88. return;
  89. }
  90. // TODO: handle other cases
  91. ASSERT(rc == ResultSuccess);
  92. ASSERT(service_rc == ResultSuccess);
  93. }
  94. void ServiceThread::Impl::SessionClosed(KServerSession* server_session,
  95. std::shared_ptr<SessionRequestManager> manager) {
  96. {
  97. // Lock to get the set.
  98. std::scoped_lock lk{m_session_mutex};
  99. // Erase the session.
  100. ASSERT(m_sessions.erase(server_session) == 1);
  101. }
  102. // Close our reference to the server session.
  103. server_session->Close();
  104. }
  105. void ServiceThread::Impl::LoopProcess() {
  106. Common::SetCurrentThreadName(m_service_name.c_str());
  107. kernel.RegisterHostThread(m_thread);
  108. while (!m_shutdown_requested.load()) {
  109. WaitAndProcessImpl();
  110. }
  111. }
  112. void ServiceThread::Impl::RegisterServerSession(KServerSession* server_session,
  113. std::shared_ptr<SessionRequestManager> manager) {
  114. // Open the server session.
  115. server_session->Open();
  116. {
  117. // Lock to get the set.
  118. std::scoped_lock lk{m_session_mutex};
  119. // Insert the session and manager.
  120. m_sessions[server_session] = manager;
  121. }
  122. // Signal the wakeup event.
  123. m_wakeup_event->Signal();
  124. }
  125. ServiceThread::Impl::~Impl() {
  126. // Shut down the processing thread.
  127. m_shutdown_requested.store(true);
  128. m_wakeup_event->Signal();
  129. m_host_thread.join();
  130. // Lock mutex.
  131. m_session_mutex.lock();
  132. // Close all remaining sessions.
  133. for (const auto& [server_session, manager] : m_sessions) {
  134. server_session->Close();
  135. }
  136. // Destroy remaining managers.
  137. m_sessions.clear();
  138. // Close event.
  139. m_wakeup_event->GetReadableEvent().Close();
  140. m_wakeup_event->Close();
  141. // Close thread.
  142. m_thread->Close();
  143. // Close process.
  144. m_process->Close();
  145. }
  146. ServiceThread::Impl::Impl(KernelCore& kernel_, const std::string& service_name)
  147. : kernel{kernel_}, m_service_name{service_name} {
  148. // Initialize process.
  149. m_process = KProcess::Create(kernel);
  150. KProcess::Initialize(m_process, kernel.System(), service_name,
  151. KProcess::ProcessType::KernelInternal, kernel.GetSystemResourceLimit());
  152. // Reserve a new event from the process resource limit
  153. KScopedResourceReservation event_reservation(m_process, LimitableResource::EventCountMax);
  154. ASSERT(event_reservation.Succeeded());
  155. // Initialize event.
  156. m_wakeup_event = KEvent::Create(kernel);
  157. m_wakeup_event->Initialize(m_process);
  158. // Commit the event reservation.
  159. event_reservation.Commit();
  160. // Reserve a new thread from the process resource limit
  161. KScopedResourceReservation thread_reservation(m_process, LimitableResource::ThreadCountMax);
  162. ASSERT(thread_reservation.Succeeded());
  163. // Initialize thread.
  164. m_thread = KThread::Create(kernel);
  165. ASSERT(KThread::InitializeDummyThread(m_thread, m_process).IsSuccess());
  166. // Commit the thread reservation.
  167. thread_reservation.Commit();
  168. // Start thread.
  169. m_host_thread = std::jthread([this] { LoopProcess(); });
  170. }
  171. ServiceThread::ServiceThread(KernelCore& kernel, const std::string& name)
  172. : impl{std::make_unique<Impl>(kernel, name)} {}
  173. ServiceThread::~ServiceThread() = default;
  174. void ServiceThread::RegisterServerSession(KServerSession* session,
  175. std::shared_ptr<SessionRequestManager> manager) {
  176. impl->RegisterServerSession(session, manager);
  177. }
  178. } // namespace Kernel