diff options
| author | 2023-01-23 14:56:06 -0500 | |
|---|---|---|
| committer | 2023-01-23 17:14:41 -0500 | |
| commit | 5086380a63bfbaa118ff48da14f505f842ac19cc (patch) | |
| tree | 8129ee6653bbb551ac77e45f86ee2ee959b58969 /src/core/hle/kernel/kernel.cpp | |
| parent | Merge pull request #9660 from german77/koreaToTaiwan (diff) | |
| download | yuzu-5086380a63bfbaa118ff48da14f505f842ac19cc.tar.gz yuzu-5086380a63bfbaa118ff48da14f505f842ac19cc.tar.xz yuzu-5086380a63bfbaa118ff48da14f505f842ac19cc.zip | |
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) { | |||
| 1198 | const bool should_suspend{exception_exited || suspended}; | 1198 | const bool should_suspend{exception_exited || suspended}; |
| 1199 | const auto activity = should_suspend ? ProcessActivity::Paused : ProcessActivity::Runnable; | 1199 | const auto activity = should_suspend ? ProcessActivity::Paused : ProcessActivity::Runnable; |
| 1200 | 1200 | ||
| 1201 | std::vector<KScopedAutoObject<KThread>> process_threads; | 1201 | //! This refers to the application process, not the current process. |
| 1202 | { | 1202 | KScopedAutoObject<KProcess> process = CurrentProcess(); |
| 1203 | KScopedSchedulerLock sl{*this}; | 1203 | if (process.IsNull()) { |
| 1204 | return; | ||
| 1205 | } | ||
| 1204 | 1206 | ||
| 1205 | if (auto* process = CurrentProcess(); process != nullptr) { | 1207 | // Set the new activity. |
| 1206 | process->SetActivity(activity); | 1208 | process->SetActivity(activity); |
| 1207 | 1209 | ||
| 1208 | if (!should_suspend) { | 1210 | // Wait for process execution to stop. |
| 1209 | // Runnable now; no need to wait. | 1211 | bool must_wait{should_suspend}; |
| 1210 | return; | 1212 | |
| 1211 | } | 1213 | // KernelCore::Suspend must be called from locked context, or we |
| 1214 | // could race another call to SetActivity, interfering with waiting. | ||
| 1215 | while (must_wait) { | ||
| 1216 | KScopedSchedulerLock sl{*this}; | ||
| 1217 | |||
| 1218 | // Assume that all threads have finished running. | ||
| 1219 | must_wait = false; | ||
| 1212 | 1220 | ||
| 1213 | for (auto* thread : process->GetThreadList()) { | 1221 | for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) { |
| 1214 | process_threads.emplace_back(thread); | 1222 | if (Scheduler(i).GetSchedulerCurrentThread()->GetOwnerProcess() == |
| 1223 | process.GetPointerUnsafe()) { | ||
| 1224 | // A thread has not finished running yet. | ||
| 1225 | // Continue waiting. | ||
| 1226 | must_wait = true; | ||
| 1215 | } | 1227 | } |
| 1216 | } | 1228 | } |
| 1217 | } | 1229 | } |
| 1218 | |||
| 1219 | // Wait for execution to stop. | ||
| 1220 | for (auto& thread : process_threads) { | ||
| 1221 | thread->WaitUntilSuspended(); | ||
| 1222 | } | ||
| 1223 | } | 1230 | } |
| 1224 | 1231 | ||
| 1225 | void KernelCore::ShutdownCores() { | 1232 | void KernelCore::ShutdownCores() { |