|
|
|
@ -1204,39 +1204,48 @@ const Kernel::KSharedMemory& KernelCore::GetHidBusSharedMem() const { |
|
|
|
return *impl->hidbus_shared_mem; |
|
|
|
} |
|
|
|
|
|
|
|
void KernelCore::SuspendApplication(bool suspended) { |
|
|
|
void KernelCore::SuspendEmulation(bool suspended) { |
|
|
|
const bool should_suspend{exception_exited || suspended}; |
|
|
|
const auto activity = |
|
|
|
should_suspend ? Svc::ProcessActivity::Paused : Svc::ProcessActivity::Runnable; |
|
|
|
auto processes = GetProcessList(); |
|
|
|
|
|
|
|
// Get the application process.
|
|
|
|
KScopedAutoObject<KProcess> process = ApplicationProcess(); |
|
|
|
if (process.IsNull()) { |
|
|
|
return; |
|
|
|
for (auto& process : processes) { |
|
|
|
KScopedLightLock ll{process->GetListLock()}; |
|
|
|
|
|
|
|
for (auto& thread : process->GetThreadList()) { |
|
|
|
if (should_suspend) { |
|
|
|
thread.RequestSuspend(SuspendType::System); |
|
|
|
} else { |
|
|
|
thread.Resume(SuspendType::System); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Set the new activity.
|
|
|
|
process->SetActivity(activity); |
|
|
|
if (!should_suspend) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// Wait for process execution to stop.
|
|
|
|
bool must_wait{should_suspend}; |
|
|
|
|
|
|
|
// KernelCore::SuspendApplication must be called from locked context,
|
|
|
|
// or we could race another call to SetActivity, interfering with waiting.
|
|
|
|
while (must_wait) { |
|
|
|
// KernelCore::SuspendEmulation must be called from locked context,
|
|
|
|
// or we could race another call, interfering with waiting.
|
|
|
|
const auto TryWait = [&]() { |
|
|
|
KScopedSchedulerLock sl{*this}; |
|
|
|
|
|
|
|
// Assume that all threads have finished running.
|
|
|
|
must_wait = false; |
|
|
|
|
|
|
|
for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) { |
|
|
|
if (Scheduler(i).GetSchedulerCurrentThread()->GetOwnerProcess() == |
|
|
|
process.GetPointerUnsafe()) { |
|
|
|
// A thread has not finished running yet.
|
|
|
|
// Continue waiting.
|
|
|
|
must_wait = true; |
|
|
|
for (auto& process : processes) { |
|
|
|
for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) { |
|
|
|
if (Scheduler(i).GetSchedulerCurrentThread()->GetOwnerProcess() == |
|
|
|
process.GetPointerUnsafe()) { |
|
|
|
// A thread has not finished running yet.
|
|
|
|
// Continue waiting.
|
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return true; |
|
|
|
}; |
|
|
|
|
|
|
|
while (!TryWait()) { |
|
|
|
// ...
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -1260,7 +1269,7 @@ bool KernelCore::IsShuttingDown() const { |
|
|
|
|
|
|
|
void KernelCore::ExceptionalExitApplication() { |
|
|
|
exception_exited = true; |
|
|
|
SuspendApplication(true); |
|
|
|
SuspendEmulation(true); |
|
|
|
} |
|
|
|
|
|
|
|
void KernelCore::EnterSVCProfile() { |
|
|
|
|