Kernel/IPC: Add a small delay after each SyncRequest to prevent thread starvation.

In a real 3DS, threads that call svcSyncRequest are put to sleep until the server responds via svcReplyAndReceive. Our HLE services don't implement this mechanism and are effectively immediate from the 3DS's point of view. This commit makes it so that we at least simulate the IPC delay.

Specific HLE handlers might need to put their callers to sleep for a longer period of time to simulate IO timings. This is their responsibility but doing so is currently not implemented.

See https://gist.github.com/ds84182/4a7690c5376e045cab9129ca4185bbeb for a test that was not passing before this commit.
This commit is contained in:
Subv 2017-11-07 19:58:29 -05:00
parent 040006fa6b
commit e90daa6a4f

View File

@ -67,13 +67,28 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
// If this ServerSession has an associated HLE handler, forward the request to it. // If this ServerSession has an associated HLE handler, forward the request to it.
if (hle_handler != nullptr) { if (hle_handler != nullptr) {
hle_handler->HandleSyncRequest(SharedPtr<ServerSession>(this)); hle_handler->HandleSyncRequest(SharedPtr<ServerSession>(this));
} else { }
if (thread->status == THREADSTATUS_RUNNING) {
// Put the thread to sleep until the server replies, it will be awoken in // Put the thread to sleep until the server replies, it will be awoken in
// svcReplyAndReceive. // svcReplyAndReceive for LLE servers.
thread->status = THREADSTATUS_WAIT_IPC; thread->status = THREADSTATUS_WAIT_IPC;
// Add the thread to the list of threads that have issued a sync request with this
// server. if (hle_handler != nullptr) {
pending_requesting_threads.push_back(std::move(thread)); // 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.
// TODO(Subv): Figure out a good value for this.
static constexpr u64 IPCDelayNanoseconds = 100;
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 // If this ServerSession does not have an HLE implementation, just wake up the threads waiting