diff options
| author | 2023-01-23 14:56:06 -0500 | |
|---|---|---|
| committer | 2023-01-23 17:14:41 -0500 | |
| commit | 5086380a63bfbaa118ff48da14f505f842ac19cc (patch) | |
| tree | 8129ee6653bbb551ac77e45f86ee2ee959b58969 /src | |
| 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')
| -rw-r--r-- | src/core/hle/kernel/k_thread.cpp | 13 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_thread.h | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 39 |
3 files changed, 23 insertions, 31 deletions
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 21207fe99..7c7c2459c 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp | |||
| @@ -763,19 +763,6 @@ void KThread::Continue() { | |||
| 763 | KScheduler::OnThreadStateChanged(kernel, this, old_state); | 763 | KScheduler::OnThreadStateChanged(kernel, this, old_state); |
| 764 | } | 764 | } |
| 765 | 765 | ||
| 766 | void KThread::WaitUntilSuspended() { | ||
| 767 | // Make sure we have a suspend requested. | ||
| 768 | ASSERT(IsSuspendRequested()); | ||
| 769 | |||
| 770 | // Loop until the thread is not executing on any core. | ||
| 771 | for (std::size_t i = 0; i < static_cast<std::size_t>(Core::Hardware::NUM_CPU_CORES); ++i) { | ||
| 772 | KThread* core_thread{}; | ||
| 773 | do { | ||
| 774 | core_thread = kernel.Scheduler(i).GetSchedulerCurrentThread(); | ||
| 775 | } while (core_thread == this); | ||
| 776 | } | ||
| 777 | } | ||
| 778 | |||
| 779 | Result KThread::SetActivity(Svc::ThreadActivity activity) { | 766 | Result KThread::SetActivity(Svc::ThreadActivity activity) { |
| 780 | // Lock ourselves. | 767 | // Lock ourselves. |
| 781 | KScopedLightLock lk(activity_pause_lock); | 768 | KScopedLightLock lk(activity_pause_lock); |
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index 7cd94a340..083f4962d 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h | |||
| @@ -214,8 +214,6 @@ public: | |||
| 214 | 214 | ||
| 215 | void Continue(); | 215 | void Continue(); |
| 216 | 216 | ||
| 217 | void WaitUntilSuspended(); | ||
| 218 | |||
| 219 | constexpr void SetSyncedIndex(s32 index) { | 217 | constexpr void SetSyncedIndex(s32 index) { |
| 220 | synced_index = index; | 218 | synced_index = index; |
| 221 | } | 219 | } |
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() { |