summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2018-02-18 14:11:34 -0500
committerGravatar GitHub2018-02-18 14:11:34 -0500
commitec39c9eb321e88697448091b95842adb18cb485f (patch)
tree49cd0eb8264d5ac6eb47179b41c83848f25078a9 /src
parentMerge pull request #200 from Subv/bufferproducerfence (diff)
parent Kernel/IPC: Add a small delay after each SyncRequest to prevent thread starv... (diff)
downloadyuzu-ec39c9eb321e88697448091b95842adb18cb485f.tar.gz
yuzu-ec39c9eb321e88697448091b95842adb18cb485f.tar.xz
yuzu-ec39c9eb321e88697448091b95842adb18cb485f.zip
Merge pull request #201 from Subv/ipc_delay_
Kernel/IPC: Add a small delay after each SyncRequest to prevent thread starvation.
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/kernel/server_session.cpp97
-rw-r--r--src/core/hle/kernel/server_session.h14
-rw-r--r--src/core/hle/kernel/thread.cpp1
-rw-r--r--src/core/hle/kernel/thread.h1
4 files changed, 63 insertions, 50 deletions
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 54481f7f1..5608418c3 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -57,6 +57,33 @@ void ServerSession::Acquire(Thread* thread) {
57 pending_requesting_threads.pop_back(); 57 pending_requesting_threads.pop_back();
58} 58}
59 59
60ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) {
61 auto& domain_message_header = context.GetDomainMessageHeader();
62 if (domain_message_header) {
63 // If there is a DomainMessageHeader, then this is CommandType "Request"
64 const u32 object_id{context.GetDomainMessageHeader()->object_id};
65 switch (domain_message_header->command) {
66 case IPC::DomainMessageHeader::CommandType::SendMessage:
67 return domain_request_handlers[object_id - 1]->HandleSyncRequest(context);
68
69 case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: {
70 LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x%08X", object_id);
71
72 domain_request_handlers[object_id - 1] = nullptr;
73
74 IPC::ResponseBuilder rb{context, 2};
75 rb.Push(RESULT_SUCCESS);
76 return RESULT_SUCCESS;
77 }
78 }
79
80 LOG_CRITICAL(IPC, "Unknown domain command=%d", domain_message_header->command.Value());
81 ASSERT(false);
82 }
83
84 return RESULT_SUCCESS;
85}
86
60ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) { 87ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
61 // The ServerSession received a sync request, this means that there's new data available 88 // The ServerSession received a sync request, this means that there's new data available
62 // from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or 89 // 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) {
67 context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process, 94 context.PopulateFromIncomingCommandBuffer(cmd_buf, *Kernel::g_current_process,
68 Kernel::g_handle_table); 95 Kernel::g_handle_table);
69 96
70 // If the session has been converted to a domain, handle the doomain request 97 ResultCode result = RESULT_SUCCESS;
98 // If the session has been converted to a domain, handle the domain request
71 if (IsDomain()) { 99 if (IsDomain()) {
72 auto& domain_message_header = context.GetDomainMessageHeader(); 100 result = HandleDomainSyncRequest(context);
73 if (domain_message_header) {
74 // If there is a DomainMessageHeader, then this is CommandType "Request"
75 const u32 object_id{context.GetDomainMessageHeader()->object_id};
76 switch (domain_message_header->command) {
77 case IPC::DomainMessageHeader::CommandType::SendMessage:
78 return domain_request_handlers[object_id - 1]->HandleSyncRequest(context);
79
80 case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: {
81 LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x%08X", object_id);
82
83 domain_request_handlers[object_id - 1] = nullptr;
84
85 IPC::ResponseBuilder rb{context, 2};
86 rb.Push(RESULT_SUCCESS);
87 return RESULT_SUCCESS;
88 }
89 }
90
91 LOG_CRITICAL(IPC, "Unknown domain command=%d", domain_message_header->command.Value());
92 ASSERT(false);
93 }
94 // If there is no domain header, the regular session handler is used 101 // If there is no domain header, the regular session handler is used
102 } else if (hle_handler != nullptr) {
103 // If this ServerSession has an associated HLE handler, forward the request to it.
104 result = hle_handler->HandleSyncRequest(context);
95 } 105 }
96 106
97 // If this ServerSession has an associated HLE handler, forward the request to it. 107 if (thread->status == THREADSTATUS_RUNNING) {
98 ResultCode result{RESULT_SUCCESS}; 108 // Put the thread to sleep until the server replies, it will be awoken in
99 if (hle_handler != nullptr) { 109 // svcReplyAndReceive for LLE servers.
100 // Attempt to translate the incoming request's command buffer. 110 thread->status = THREADSTATUS_WAIT_IPC;
101 ResultCode translate_result = TranslateHLERequest(this); 111
102 if (translate_result.IsError()) 112 if (hle_handler != nullptr) {
103 return translate_result; 113 // For HLE services, we put the request threads to sleep for a short duration to
104 114 // simulate IPC overhead, but only if the HLE handler didn't put the thread to sleep for
105 result = hle_handler->HandleSyncRequest(context); 115 // other reasons like an async callback. The IPC overhead is needed to prevent
106 } else { 116 // starvation when a thread only does sync requests to HLE services while a
107 // Add the thread to the list of threads that have issued a sync request with this 117 // lower-priority thread is waiting to run.
108 // server. 118
109 pending_requesting_threads.push_back(std::move(thread)); 119 // This delay was approximated in a homebrew application by measuring the average time
120 // it takes for svcSendSyncRequest to return when performing the SetLcdForceBlack IPC
121 // request to the GSP:GPU service in a n3DS with firmware 11.6. The measured values have
122 // a high variance and vary between models.
123 static constexpr u64 IPCDelayNanoseconds = 39000;
124 thread->WakeAfterDelay(IPCDelayNanoseconds);
125 } else {
126 // Add the thread to the list of threads that have issued a sync request with this
127 // server.
128 pending_requesting_threads.push_back(std::move(thread));
129 }
110 } 130 }
111 131
112 // If this ServerSession does not have an HLE implementation, just wake up the threads waiting 132 // 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
140 160
141 return std::make_tuple(std::move(server_session), std::move(client_session)); 161 return std::make_tuple(std::move(server_session), std::move(client_session));
142} 162}
143
144ResultCode TranslateHLERequest(ServerSession* server_session) {
145 // TODO(Subv): Implement this function once multiple concurrent processes are supported.
146 return RESULT_SUCCESS;
147}
148} // namespace Kernel 163} // namespace Kernel
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index 144692106..2da807042 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -21,6 +21,7 @@ class ServerSession;
21class Session; 21class Session;
22class SessionRequestHandler; 22class SessionRequestHandler;
23class Thread; 23class Thread;
24class HLERequestContext;
24 25
25/** 26/**
26 * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS 27 * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS
@@ -116,17 +117,12 @@ private:
116 */ 117 */
117 static ResultVal<SharedPtr<ServerSession>> Create(std::string name = "Unknown"); 118 static ResultVal<SharedPtr<ServerSession>> Create(std::string name = "Unknown");
118 119
120 /// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an
121 /// object handle.
122 ResultCode HandleDomainSyncRequest(Kernel::HLERequestContext& context);
123
119 /// When set to True, converts the session to a domain at the end of the command 124 /// When set to True, converts the session to a domain at the end of the command
120 bool convert_to_domain{}; 125 bool convert_to_domain{};
121}; 126};
122 127
123/**
124 * Performs command buffer translation for an HLE IPC request.
125 * The command buffer from the ServerSession thread's TLS is copied into a
126 * buffer and all descriptors in the buffer are processed.
127 * TODO(Subv): Implement this function, currently we do not support multiple processes running at
128 * once, but once that is implemented we'll need to properly translate all descriptors
129 * in the command buffer.
130 */
131ResultCode TranslateHLERequest(ServerSession* server_session);
132} // namespace Kernel 128} // namespace Kernel
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 1a33cc6cb..130b669a0 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -284,6 +284,7 @@ void Thread::ResumeFromWait() {
284 case THREADSTATUS_WAIT_SYNCH_ANY: 284 case THREADSTATUS_WAIT_SYNCH_ANY:
285 case THREADSTATUS_WAIT_ARB: 285 case THREADSTATUS_WAIT_ARB:
286 case THREADSTATUS_WAIT_SLEEP: 286 case THREADSTATUS_WAIT_SLEEP:
287 case THREADSTATUS_WAIT_IPC:
287 break; 288 break;
288 289
289 case THREADSTATUS_READY: 290 case THREADSTATUS_READY:
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 0a1ada27d..bbffaf4cf 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -40,6 +40,7 @@ enum ThreadStatus {
40 THREADSTATUS_READY, ///< Ready to run 40 THREADSTATUS_READY, ///< Ready to run
41 THREADSTATUS_WAIT_ARB, ///< Waiting on an address arbiter 41 THREADSTATUS_WAIT_ARB, ///< Waiting on an address arbiter
42 THREADSTATUS_WAIT_SLEEP, ///< Waiting due to a SleepThread SVC 42 THREADSTATUS_WAIT_SLEEP, ///< Waiting due to a SleepThread SVC
43 THREADSTATUS_WAIT_IPC, ///< Waiting for the reply from an IPC request
43 THREADSTATUS_WAIT_SYNCH_ANY, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false 44 THREADSTATUS_WAIT_SYNCH_ANY, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false
44 THREADSTATUS_WAIT_SYNCH_ALL, ///< Waiting due to WaitSynchronizationN with wait_all = true 45 THREADSTATUS_WAIT_SYNCH_ALL, ///< Waiting due to WaitSynchronizationN with wait_all = true
45 THREADSTATUS_DORMANT, ///< Created but not yet made ready 46 THREADSTATUS_DORMANT, ///< Created but not yet made ready