|
|
|
@ -1198,28 +1198,35 @@ void KernelCore::Suspend(bool suspended) { |
|
|
|
const bool should_suspend{exception_exited || suspended}; |
|
|
|
const auto activity = should_suspend ? ProcessActivity::Paused : ProcessActivity::Runnable; |
|
|
|
|
|
|
|
std::vector<KScopedAutoObject<KThread>> process_threads; |
|
|
|
{ |
|
|
|
KScopedSchedulerLock sl{*this}; |
|
|
|
//! This refers to the application process, not the current process.
|
|
|
|
KScopedAutoObject<KProcess> process = CurrentProcess(); |
|
|
|
if (process.IsNull()) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if (auto* process = CurrentProcess(); process != nullptr) { |
|
|
|
process->SetActivity(activity); |
|
|
|
// Set the new activity.
|
|
|
|
process->SetActivity(activity); |
|
|
|
|
|
|
|
if (!should_suspend) { |
|
|
|
// Runnable now; no need to wait.
|
|
|
|
return; |
|
|
|
} |
|
|
|
// Wait for process execution to stop.
|
|
|
|
bool must_wait{should_suspend}; |
|
|
|
|
|
|
|
// KernelCore::Suspend must be called from locked context, or we
|
|
|
|
// could race another call to SetActivity, interfering with waiting.
|
|
|
|
while (must_wait) { |
|
|
|
KScopedSchedulerLock sl{*this}; |
|
|
|
|
|
|
|
// Assume that all threads have finished running.
|
|
|
|
must_wait = false; |
|
|
|
|
|
|
|
for (auto* thread : process->GetThreadList()) { |
|
|
|
process_threads.emplace_back(thread); |
|
|
|
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; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Wait for execution to stop.
|
|
|
|
for (auto& thread : process_threads) { |
|
|
|
thread->WaitUntilSuspended(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void KernelCore::ShutdownCores() { |
|
|
|
|