|
|
@@ -57,6 +57,33 @@ void ServerSession::Acquire(Thread* thread) {
|
|
|
pending_requesting_threads.pop_back();
|
|
|
}
|
|
|
|
|
|
+ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) {
|
|
|
+ auto& domain_message_header = context.GetDomainMessageHeader();
|
|
|
+ if (domain_message_header) {
|
|
|
+ // If there is a DomainMessageHeader, then this is CommandType "Request"
|
|
|
+ const u32 object_id{context.GetDomainMessageHeader()->object_id};
|
|
|
+ switch (domain_message_header->command) {
|
|
|
+ case IPC::DomainMessageHeader::CommandType::SendMessage:
|
|
|
+ return domain_request_handlers[object_id - 1]->HandleSyncRequest(context);
|
|
|
+
|
|
|
+ case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: {
|
|
|
+ LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x%08X", object_id);
|
|
|
+
|
|
|
+ domain_request_handlers[object_id - 1] = nullptr;
|
|
|
+
|
|
|
+ IPC::ResponseBuilder rb{context, 2};
|
|
|
+ rb.Push(RESULT_SUCCESS);
|
|
|
+ return RESULT_SUCCESS;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ LOG_CRITICAL(IPC, "Unknown domain command=%d", domain_message_header->command.Value());
|
|
|
+ ASSERT(false);
|
|
|
+ }
|
|
|
+
|
|
|
+ return RESULT_SUCCESS;
|
|
|
+}
|
|
|
+
|
|
|
ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
|
|
|
// The ServerSession received a sync request, this means that there's new data available
|
|
|
// from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or
|
|
|
@@ -67,46 +94,39 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
|
|
|
context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process,
|
|
|
Kernel::g_handle_table);
|
|
|
|
|
|
- // If the session has been converted to a domain, handle the doomain request
|
|
|
+ ResultCode result = RESULT_SUCCESS;
|
|
|
+ // If the session has been converted to a domain, handle the domain request
|
|
|
if (IsDomain()) {
|
|
|
- auto& domain_message_header = context.GetDomainMessageHeader();
|
|
|
- if (domain_message_header) {
|
|
|
- // If there is a DomainMessageHeader, then this is CommandType "Request"
|
|
|
- const u32 object_id{context.GetDomainMessageHeader()->object_id};
|
|
|
- switch (domain_message_header->command) {
|
|
|
- case IPC::DomainMessageHeader::CommandType::SendMessage:
|
|
|
- return domain_request_handlers[object_id - 1]->HandleSyncRequest(context);
|
|
|
-
|
|
|
- case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: {
|
|
|
- LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x%08X", object_id);
|
|
|
-
|
|
|
- domain_request_handlers[object_id - 1] = nullptr;
|
|
|
-
|
|
|
- IPC::ResponseBuilder rb{context, 2};
|
|
|
- rb.Push(RESULT_SUCCESS);
|
|
|
- return RESULT_SUCCESS;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- LOG_CRITICAL(IPC, "Unknown domain command=%d", domain_message_header->command.Value());
|
|
|
- ASSERT(false);
|
|
|
- }
|
|
|
+ result = HandleDomainSyncRequest(context);
|
|
|
// If there is no domain header, the regular session handler is used
|
|
|
+ } else if (hle_handler != nullptr) {
|
|
|
+ // If this ServerSession has an associated HLE handler, forward the request to it.
|
|
|
+ result = hle_handler->HandleSyncRequest(context);
|
|
|
}
|
|
|
|
|
|
- // If this ServerSession has an associated HLE handler, forward the request to it.
|
|
|
- ResultCode result{RESULT_SUCCESS};
|
|
|
- if (hle_handler != nullptr) {
|
|
|
- // Attempt to translate the incoming request's command buffer.
|
|
|
- ResultCode translate_result = TranslateHLERequest(this);
|
|
|
- if (translate_result.IsError())
|
|
|
- return translate_result;
|
|
|
-
|
|
|
- result = hle_handler->HandleSyncRequest(context);
|
|
|
- } else {
|
|
|
- // Add the thread to the list of threads that have issued a sync request with this
|
|
|
- // server.
|
|
|
- pending_requesting_threads.push_back(std::move(thread));
|
|
|
+ if (thread->status == THREADSTATUS_RUNNING) {
|
|
|
+ // Put the thread to sleep until the server replies, it will be awoken in
|
|
|
+ // svcReplyAndReceive for LLE servers.
|
|
|
+ thread->status = THREADSTATUS_WAIT_IPC;
|
|
|
+
|
|
|
+ if (hle_handler != nullptr) {
|
|
|
+ // For HLE services, we put the request threads to sleep for a short duration to
|
|
|
+ // simulate IPC overhead, but only if the HLE handler didn't put the thread to sleep for
|
|
|
+ // other reasons like an async callback. The IPC overhead is needed to prevent
|
|
|
+ // starvation when a thread only does sync requests to HLE services while a
|
|
|
+ // lower-priority thread is waiting to run.
|
|
|
+
|
|
|
+ // This delay was approximated in a homebrew application by measuring the average time
|
|
|
+ // it takes for svcSendSyncRequest to return when performing the SetLcdForceBlack IPC
|
|
|
+ // request to the GSP:GPU service in a n3DS with firmware 11.6. The measured values have
|
|
|
+ // a high variance and vary between models.
|
|
|
+ static constexpr u64 IPCDelayNanoseconds = 39000;
|
|
|
+ thread->WakeAfterDelay(IPCDelayNanoseconds);
|
|
|
+ } else {
|
|
|
+ // Add the thread to the list of threads that have issued a sync request with this
|
|
|
+ // server.
|
|
|
+ pending_requesting_threads.push_back(std::move(thread));
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// If this ServerSession does not have an HLE implementation, just wake up the threads waiting
|
|
|
@@ -140,9 +160,4 @@ ServerSession::SessionPair ServerSession::CreateSessionPair(const std::string& n
|
|
|
|
|
|
return std::make_tuple(std::move(server_session), std::move(client_session));
|
|
|
}
|
|
|
-
|
|
|
-ResultCode TranslateHLERequest(ServerSession* server_session) {
|
|
|
- // TODO(Subv): Implement this function once multiple concurrent processes are supported.
|
|
|
- return RESULT_SUCCESS;
|
|
|
-}
|
|
|
} // namespace Kernel
|