server_session.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. // Copyright 2019 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <tuple>
  5. #include <utility>
  6. #include "common/assert.h"
  7. #include "common/common_types.h"
  8. #include "common/logging/log.h"
  9. #include "core/core.h"
  10. #include "core/core_timing.h"
  11. #include "core/hle/ipc_helpers.h"
  12. #include "core/hle/kernel/client_port.h"
  13. #include "core/hle/kernel/client_session.h"
  14. #include "core/hle/kernel/handle_table.h"
  15. #include "core/hle/kernel/hle_ipc.h"
  16. #include "core/hle/kernel/kernel.h"
  17. #include "core/hle/kernel/process.h"
  18. #include "core/hle/kernel/server_session.h"
  19. #include "core/hle/kernel/session.h"
  20. #include "core/hle/kernel/scheduler.h"
  21. #include "core/hle/kernel/thread.h"
  22. #include "core/memory.h"
  23. namespace Kernel {
  24. ServerSession::ServerSession(KernelCore& kernel) : SynchronizationObject{kernel} {}
  25. ServerSession::~ServerSession() = default;
  26. ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel,
  27. std::shared_ptr<Session> parent,
  28. std::string name) {
  29. std::shared_ptr<ServerSession> session{std::make_shared<ServerSession>(kernel)};
  30. session->request_event = Core::Timing::CreateEvent(
  31. name, [session](u64 userdata, s64 cycles_late) { session->CompleteSyncRequest(); });
  32. session->name = std::move(name);
  33. session->parent = std::move(parent);
  34. return MakeResult(std::move(session));
  35. }
  36. bool ServerSession::ShouldWait(const Thread* thread) const {
  37. // Closed sessions should never wait, an error will be returned from svcReplyAndReceive.
  38. if (!parent->Client()) {
  39. return false;
  40. }
  41. // Wait if we have no pending requests, or if we're currently handling a request.
  42. return pending_requesting_threads.empty() || currently_handling != nullptr;
  43. }
  44. bool ServerSession::IsSignaled() const {
  45. // Closed sessions should never wait, an error will be returned from svcReplyAndReceive.
  46. if (!parent->Client()) {
  47. return true;
  48. }
  49. // Wait if we have no pending requests, or if we're currently handling a request.
  50. return !pending_requesting_threads.empty() && currently_handling == nullptr;
  51. }
  52. void ServerSession::Acquire(Thread* thread) {
  53. ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
  54. // We are now handling a request, pop it from the stack.
  55. // TODO(Subv): What happens if the client endpoint is closed before any requests are made?
  56. ASSERT(!pending_requesting_threads.empty());
  57. currently_handling = pending_requesting_threads.back();
  58. pending_requesting_threads.pop_back();
  59. }
  60. void ServerSession::ClientDisconnected() {
  61. // We keep a shared pointer to the hle handler to keep it alive throughout
  62. // the call to ClientDisconnected, as ClientDisconnected invalidates the
  63. // hle_handler member itself during the course of the function executing.
  64. std::shared_ptr<SessionRequestHandler> handler = hle_handler;
  65. if (handler) {
  66. // Note that after this returns, this server session's hle_handler is
  67. // invalidated (set to null).
  68. handler->ClientDisconnected(SharedFrom(this));
  69. }
  70. // Clean up the list of client threads with pending requests, they are unneeded now that the
  71. // client endpoint is closed.
  72. pending_requesting_threads.clear();
  73. currently_handling = nullptr;
  74. }
  75. void ServerSession::AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler) {
  76. domain_request_handlers.push_back(std::move(handler));
  77. }
  78. std::size_t ServerSession::NumDomainRequestHandlers() const {
  79. return domain_request_handlers.size();
  80. }
  81. ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) {
  82. if (!context.HasDomainMessageHeader()) {
  83. return RESULT_SUCCESS;
  84. }
  85. // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs
  86. context.SetDomainRequestHandlers(domain_request_handlers);
  87. // If there is a DomainMessageHeader, then this is CommandType "Request"
  88. const auto& domain_message_header = context.GetDomainMessageHeader();
  89. const u32 object_id{domain_message_header.object_id};
  90. switch (domain_message_header.command) {
  91. case IPC::DomainMessageHeader::CommandType::SendMessage:
  92. if (object_id > domain_request_handlers.size()) {
  93. LOG_CRITICAL(IPC,
  94. "object_id {} is too big! This probably means a recent service call "
  95. "to {} needed to return a new interface!",
  96. object_id, name);
  97. UNREACHABLE();
  98. return RESULT_SUCCESS; // Ignore error if asserts are off
  99. }
  100. return domain_request_handlers[object_id - 1]->HandleSyncRequest(context);
  101. case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: {
  102. LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id);
  103. domain_request_handlers[object_id - 1] = nullptr;
  104. IPC::ResponseBuilder rb{context, 2};
  105. rb.Push(RESULT_SUCCESS);
  106. return RESULT_SUCCESS;
  107. }
  108. }
  109. LOG_CRITICAL(IPC, "Unknown domain command={}",
  110. static_cast<int>(domain_message_header.command.Value()));
  111. ASSERT(false);
  112. return RESULT_SUCCESS;
  113. }
  114. ResultCode ServerSession::QueueSyncRequest(std::shared_ptr<Thread> thread,
  115. Core::Memory::Memory& memory) {
  116. u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(thread->GetTLSAddress()))};
  117. auto context =
  118. std::make_shared<HLERequestContext>(kernel, memory, SharedFrom(this), std::move(thread));
  119. context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
  120. request_queue.Push(std::move(context));
  121. return RESULT_SUCCESS;
  122. }
  123. ResultCode ServerSession::CompleteSyncRequest() {
  124. ASSERT(!request_queue.Empty());
  125. auto& context = *request_queue.Front();
  126. ResultCode result = RESULT_SUCCESS;
  127. // If the session has been converted to a domain, handle the domain request
  128. if (IsDomain() && context.HasDomainMessageHeader()) {
  129. result = HandleDomainSyncRequest(context);
  130. // If there is no domain header, the regular session handler is used
  131. } else if (hle_handler != nullptr) {
  132. // If this ServerSession has an associated HLE handler, forward the request to it.
  133. result = hle_handler->HandleSyncRequest(context);
  134. }
  135. if (convert_to_domain) {
  136. ASSERT_MSG(IsSession(), "ServerSession is already a domain instance.");
  137. domain_request_handlers = {hle_handler};
  138. convert_to_domain = false;
  139. }
  140. // Some service requests require the thread to block
  141. {
  142. SchedulerLock lock(kernel);
  143. if (!context.IsThreadWaiting()) {
  144. context.GetThread().ResumeFromWait();
  145. context.GetThread().SetSynchronizationResults(nullptr, result);
  146. }
  147. }
  148. request_queue.Pop();
  149. return result;
  150. }
  151. ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread,
  152. Core::Memory::Memory& memory) {
  153. ResultCode result = QueueSyncRequest(std::move(thread), memory);
  154. const u64 delay = kernel.IsMulticore() ? 0U : 20000U;
  155. Core::System::GetInstance().CoreTiming().ScheduleEvent(delay, request_event, {});
  156. return result;
  157. }
  158. } // namespace Kernel