diff options
Diffstat (limited to 'src/core/hle/kernel/kernel.cpp')
-rw-r--r-- | src/core/hle/kernel/kernel.cpp | 39 |
1 files changed, 23 insertions, 16 deletions
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 1fb25f221..d9eafe261 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -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() { |