|
|
@@ -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() {
|