kernel: fix incorrect locking order in suspension
This commit is contained in:
		| @@ -763,19 +763,6 @@ void KThread::Continue() { | |||||||
|     KScheduler::OnThreadStateChanged(kernel, this, old_state); |     KScheduler::OnThreadStateChanged(kernel, this, old_state); | ||||||
| } | } | ||||||
|  |  | ||||||
| void KThread::WaitUntilSuspended() { |  | ||||||
|     // Make sure we have a suspend requested. |  | ||||||
|     ASSERT(IsSuspendRequested()); |  | ||||||
|  |  | ||||||
|     // Loop until the thread is not executing on any core. |  | ||||||
|     for (std::size_t i = 0; i < static_cast<std::size_t>(Core::Hardware::NUM_CPU_CORES); ++i) { |  | ||||||
|         KThread* core_thread{}; |  | ||||||
|         do { |  | ||||||
|             core_thread = kernel.Scheduler(i).GetSchedulerCurrentThread(); |  | ||||||
|         } while (core_thread == this); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| Result KThread::SetActivity(Svc::ThreadActivity activity) { | Result KThread::SetActivity(Svc::ThreadActivity activity) { | ||||||
|     // Lock ourselves. |     // Lock ourselves. | ||||||
|     KScopedLightLock lk(activity_pause_lock); |     KScopedLightLock lk(activity_pause_lock); | ||||||
|   | |||||||
| @@ -214,8 +214,6 @@ public: | |||||||
|  |  | ||||||
|     void Continue(); |     void Continue(); | ||||||
|  |  | ||||||
|     void WaitUntilSuspended(); |  | ||||||
|  |  | ||||||
|     constexpr void SetSyncedIndex(s32 index) { |     constexpr void SetSyncedIndex(s32 index) { | ||||||
|         synced_index = index; |         synced_index = index; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -1198,27 +1198,34 @@ void KernelCore::Suspend(bool suspended) { | |||||||
|     const bool should_suspend{exception_exited || suspended}; |     const bool should_suspend{exception_exited || suspended}; | ||||||
|     const auto activity = should_suspend ? ProcessActivity::Paused : ProcessActivity::Runnable; |     const auto activity = should_suspend ? ProcessActivity::Paused : ProcessActivity::Runnable; | ||||||
|  |  | ||||||
|     std::vector<KScopedAutoObject<KThread>> process_threads; |     //! This refers to the application process, not the current process. | ||||||
|     { |     KScopedAutoObject<KProcess> process = CurrentProcess(); | ||||||
|         KScopedSchedulerLock sl{*this}; |     if (process.IsNull()) { | ||||||
|  |         return; | ||||||
|         if (auto* process = CurrentProcess(); process != nullptr) { |  | ||||||
|             process->SetActivity(activity); |  | ||||||
|  |  | ||||||
|             if (!should_suspend) { |  | ||||||
|                 // Runnable now; no need to wait. |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             for (auto* thread : process->GetThreadList()) { |  | ||||||
|                 process_threads.emplace_back(thread); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Wait for execution to stop. |     // Set the new activity. | ||||||
|     for (auto& thread : process_threads) { |     process->SetActivity(activity); | ||||||
|         thread->WaitUntilSuspended(); |  | ||||||
|  |     // 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 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; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user