kernel: fix incorrect locking order in suspension

pull/8/head
Liam 2 years ago
parent 78df1ddce8
commit 5086380a63

@ -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,28 +1198,35 @@ 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) { // Set the new activity.
process->SetActivity(activity); process->SetActivity(activity);
if (!should_suspend) { // Wait for process execution to stop.
// Runnable now; no need to wait. bool must_wait{should_suspend};
return;
} // 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()) { for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) {
process_threads.emplace_back(thread); 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() { void KernelCore::ShutdownCores() {

Loading…
Cancel
Save