Fix Scheduler Core Migration Deadlock

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
This commit is contained in:
PixelyIon 2021-07-12 20:57:05 +05:30
parent b43541c1a4
commit a74eb8dbd6

View File

@ -147,8 +147,11 @@ namespace skyline::kernel {
auto wakeFunction{[&]() { auto wakeFunction{[&]() {
if (!thread->affinityMask.test(thread->coreId)) [[unlikely]] { 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); 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; 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)}; auto currentIt{std::find(core->queue.begin(), core->queue.end(), thread)}, nextIt{std::next(currentIt)};
if (currentIt == core->queue.end()) { if (currentIt == core->queue.end()) {
return; 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 // 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 (nextIt != core->queue.end() && (*nextIt)->priority < thread->priority) {
if (!thread->pendingYield) { if (!thread->pendingYield) {