diff --git a/src/core/hle/kernel/global_scheduler_context.cpp b/src/core/hle/kernel/global_scheduler_context.cpp index 65576b8c4b..adc709ab4e 100644 --- a/src/core/hle/kernel/global_scheduler_context.cpp +++ b/src/core/hle/kernel/global_scheduler_context.cpp @@ -49,4 +49,19 @@ bool GlobalSchedulerContext::IsLocked() const { return scheduler_lock.IsLockedByCurrentThread(); } +void GlobalSchedulerContext::RegisterDummyThreadForWakeup(KThread* thread) { + ASSERT(IsLocked()); + woken_dummy_thread_list.push_back(thread); +} + +void GlobalSchedulerContext::WakeupWaitingDummyThreads() { + ASSERT(IsLocked()); + + for (auto* thread : woken_dummy_thread_list) { + thread->IfDummyThreadEndWait(); + } + + woken_dummy_thread_list.clear(); +} + } // namespace Kernel diff --git a/src/core/hle/kernel/global_scheduler_context.h b/src/core/hle/kernel/global_scheduler_context.h index 67bb9852da..0be28d91b8 100644 --- a/src/core/hle/kernel/global_scheduler_context.h +++ b/src/core/hle/kernel/global_scheduler_context.h @@ -58,6 +58,9 @@ public: /// Returns true if the global scheduler lock is acquired bool IsLocked() const; + void RegisterDummyThreadForWakeup(KThread* thread); + void WakeupWaitingDummyThreads(); + [[nodiscard]] LockType& SchedulerLock() { return scheduler_lock; } @@ -76,6 +79,9 @@ private: KSchedulerPriorityQueue priority_queue; LockType scheduler_lock; + /// Lists dummy threads pending wakeup on lock release + std::vector woken_dummy_thread_list; + /// Lists all thread ids that aren't deleted/etc. std::vector thread_list; std::mutex global_list_guard; diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index c34ce7a178..9ddf23392c 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -314,6 +314,9 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) { idle_cores &= ~(1ULL << core_id); } + // HACK: any waiting dummy threads can wake up now. + kernel.GlobalSchedulerContext().WakeupWaitingDummyThreads(); + return cores_needing_scheduling; } @@ -536,6 +539,12 @@ void KScheduler::OnThreadStateChanged(KernelCore& kernel, KThread* thread, Threa GetPriorityQueue(kernel).PushBack(thread); IncrementScheduledCount(thread); SetSchedulerUpdateNeeded(kernel); + + if (thread->IsDummyThread()) { + // HACK: if this is a dummy thread, it should wake up when the scheduler + // lock is released. + kernel.GlobalSchedulerContext().RegisterDummyThreadForWakeup(thread); + } } } diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index b7bfcdce31..6cdd5b8e39 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -148,7 +148,9 @@ Result KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack physical_affinity_mask.SetAffinity(phys_core, true); // Set the thread state. - thread_state = (type == ThreadType::Main) ? ThreadState::Runnable : ThreadState::Initialized; + thread_state = (type == ThreadType::Main || type == ThreadType::Dummy) + ? ThreadState::Runnable + : ThreadState::Initialized; // Set TLS address. tls_address = 0; @@ -1231,9 +1233,6 @@ void KThread::EndWait(Result wait_result_) { } wait_queue->EndWait(this, wait_result_); - - // Special case for dummy threads to wakeup if necessary. - IfDummyThreadEndWait(); } }