server_session.cpp 7.4 KB

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