diff options
| author | bunnei <bunneidev@gmail.com> | 2023-01-27 15:06:09 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-01-27 15:06:09 -0800 |
| commit | 32b2a72e7b68427c619d2dae4daef963a826bb9e (patch) | |
| tree | 50129dff54c382ab8dfe7bd1c0af803dcc9cf851 /src/core/hle/kernel/kernel.cpp | |
| parent | e54d08fc1fa79f6c0e66f2e2ef06f21ca36cf881 (diff) | |
| parent | 693cad8e9b45cb61370bbc05e8e0022ea42044f9 (diff) | |
Merge pull request #9666 from liamwhite/wait-for-me
kernel: fix incorrect locking order in suspension
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() { |
