From a74eb8dbd68cf7177c327222203fc7111a630f57 Mon Sep 17 00:00:00 2001 From: PixelyIon Date: Mon, 12 Jul 2021 20:57:05 +0530 Subject: [PATCH] Fix Scheduler Core Migration Deadlock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Encountered in 不如帰大乱 when `HOS-3` is awoken at the same time as `HOS-0` called `SvcSetThreadCoreMask` resulting in a deadlock where `HOS-0` owns `HOS-3`'s `coreMigrationMutex` while `HOS-3` owns the core mutex with the both of them attempting to lock the other mutex --- app/src/main/cpp/skyline/kernel/scheduler.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/cpp/skyline/kernel/scheduler.cpp b/app/src/main/cpp/skyline/kernel/scheduler.cpp index 255a838c..db1d71c5 100644 --- a/app/src/main/cpp/skyline/kernel/scheduler.cpp +++ b/app/src/main/cpp/skyline/kernel/scheduler.cpp @@ -147,8 +147,11 @@ namespace skyline::kernel { auto wakeFunction{[&]() { if (!thread->affinityMask.test(thread->coreId)) [[unlikely]] { + lock.unlock(); // If the core migration mutex is locked by a thread seeking the core mutex, it'll result in a deadlock std::lock_guard migrationLock(thread->coreMigrationMutex); - MigrateToCore(thread, core, &cores.at(thread->idealCore), lock); + lock.lock(); + if (!thread->affinityMask.test(thread->coreId)) // We need to retest in case the thread was migrated while the core was unlocked + MigrateToCore(thread, core, &cores.at(thread->idealCore), lock); } return !core->queue.empty() && core->queue.front() == thread; }}; @@ -260,7 +263,7 @@ namespace skyline::kernel { auto currentIt{std::find(core->queue.begin(), core->queue.end(), thread)}, nextIt{std::next(currentIt)}; if (currentIt == core->queue.end()) { return; - } else if (currentIt == core->queue.begin()) { + } else if (currentIt == core->queue.begin()) { // Alternatively, if it's currently running then we'd just want to yield if there's a higher priority thread to run instead if (nextIt != core->queue.end() && (*nextIt)->priority < thread->priority) { if (!thread->pendingYield) {