From 604f9582d642d0b016df32ac190fd1c7fe41e2b1 Mon Sep 17 00:00:00 2001 From: pineappleEA Date: Tue, 25 Oct 2022 15:36:49 +0200 Subject: [PATCH] early-access version 3049 --- README.md | 2 +- .../hle/kernel/global_scheduler_context.cpp | 15 ++++++-- .../hle/kernel/global_scheduler_context.h | 4 +- src/core/hle/kernel/k_scheduler.cpp | 17 ++++++++- src/core/hle/kernel/k_thread.cpp | 37 +++++++++---------- src/core/hle/kernel/k_thread.h | 8 ++-- 6 files changed, 52 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 8fcd47fac..874957c4f 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 3048. +This is the source code for early-access 3049. ## Legal Notice diff --git a/src/core/hle/kernel/global_scheduler_context.cpp b/src/core/hle/kernel/global_scheduler_context.cpp index adc709ab4..fd911a3a5 100755 --- a/src/core/hle/kernel/global_scheduler_context.cpp +++ b/src/core/hle/kernel/global_scheduler_context.cpp @@ -51,17 +51,24 @@ bool GlobalSchedulerContext::IsLocked() const { void GlobalSchedulerContext::RegisterDummyThreadForWakeup(KThread* thread) { ASSERT(IsLocked()); - woken_dummy_thread_list.push_back(thread); + + woken_dummy_threads.insert(thread); +} + +void GlobalSchedulerContext::UnregisterDummyThreadForWakeup(KThread* thread) { + ASSERT(IsLocked()); + + woken_dummy_threads.erase(thread); } void GlobalSchedulerContext::WakeupWaitingDummyThreads() { ASSERT(IsLocked()); - for (auto* thread : woken_dummy_thread_list) { - thread->IfDummyThreadEndWait(); + for (auto* thread : woken_dummy_threads) { + thread->DummyThreadEndWait(); } - woken_dummy_thread_list.clear(); + woken_dummy_threads.clear(); } } // namespace Kernel diff --git a/src/core/hle/kernel/global_scheduler_context.h b/src/core/hle/kernel/global_scheduler_context.h index 0be28d91b..220ed6192 100755 --- a/src/core/hle/kernel/global_scheduler_context.h +++ b/src/core/hle/kernel/global_scheduler_context.h @@ -4,6 +4,7 @@ #pragma once #include +#include #include #include "common/common_types.h" @@ -58,6 +59,7 @@ public: /// Returns true if the global scheduler lock is acquired bool IsLocked() const; + void UnregisterDummyThreadForWakeup(KThread* thread); void RegisterDummyThreadForWakeup(KThread* thread); void WakeupWaitingDummyThreads(); @@ -80,7 +82,7 @@ private: LockType scheduler_lock; /// Lists dummy threads pending wakeup on lock release - std::vector woken_dummy_thread_list; + std::set woken_dummy_threads; /// Lists all thread ids that aren't deleted/etc. std::vector thread_list; diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 9ddf23392..b1cabbca0 100755 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -81,8 +81,8 @@ void KScheduler::RescheduleCurrentHLEThread(KernelCore& kernel) { // HACK: we cannot schedule from this thread, it is not a core thread ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() == 1); - // Special case to ensure dummy threads that are waiting block - GetCurrentThread(kernel).IfDummyThreadTryWait(); + // Ensure dummy threads that are waiting block. + GetCurrentThread(kernel).DummyThreadBeginWait(); ASSERT(GetCurrentThread(kernel).GetState() != ThreadState::Waiting); GetCurrentThread(kernel).EnableDispatch(); @@ -317,6 +317,13 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) { // HACK: any waiting dummy threads can wake up now. kernel.GlobalSchedulerContext().WakeupWaitingDummyThreads(); + // HACK: if we are a dummy thread, and we need to go sleep, indicate + // that for when the lock is released. + KThread* const cur_thread = GetCurrentThreadPointer(kernel); + if (cur_thread->IsDummyThread() && cur_thread->GetState() != ThreadState::Runnable) { + cur_thread->RequestDummyThreadWait(); + } + return cores_needing_scheduling; } @@ -534,6 +541,12 @@ void KScheduler::OnThreadStateChanged(KernelCore& kernel, KThread* thread, Threa GetPriorityQueue(kernel).Remove(thread); IncrementScheduledCount(thread); SetSchedulerUpdateNeeded(kernel); + + if (thread->IsDummyThread()) { + // HACK: if this is a dummy thread, it should no longer wake up when the + // scheduler lock is released. + kernel.GlobalSchedulerContext().UnregisterDummyThreadForWakeup(thread); + } } else if (cur_state == ThreadState::Runnable) { // If we're now runnable, then we weren't previously, and we should add. GetPriorityQueue(kernel).PushBack(thread); diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 6cdd5b8e3..d57b42fdf 100755 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -1176,30 +1176,29 @@ Result KThread::Sleep(s64 timeout) { R_SUCCEED(); } -void KThread::IfDummyThreadTryWait() { - if (!IsDummyThread()) { - return; - } +void KThread::RequestDummyThreadWait() { + ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel)); + ASSERT(this->IsDummyThread()); - if (GetState() != ThreadState::Waiting) { - return; - } - - ASSERT(!kernel.IsPhantomModeForSingleCore()); - - // Block until we are no longer waiting. - std::unique_lock lk(dummy_wait_lock); - dummy_wait_cv.wait( - lk, [&] { return GetState() != ThreadState::Waiting || kernel.IsShuttingDown(); }); + // We will block when the scheduler lock is released. + dummy_thread_runnable.store(false); } -void KThread::IfDummyThreadEndWait() { - if (!IsDummyThread()) { - return; - } +void KThread::DummyThreadBeginWait() { + ASSERT(this->IsDummyThread()); + ASSERT(!kernel.IsPhantomModeForSingleCore()); + + // Block until runnable is no longer false. + dummy_thread_runnable.wait(false); +} + +void KThread::DummyThreadEndWait() { + ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel)); + ASSERT(this->IsDummyThread()); // Wake up the waiting thread. - dummy_wait_cv.notify_one(); + dummy_thread_runnable.store(true); + dummy_thread_runnable.notify_one(); } void KThread::BeginWait(KThreadQueue* queue) { diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index e2a27d603..30aa10c9a 100755 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -643,8 +643,9 @@ public: // therefore will not block on guest kernel synchronization primitives. These methods handle // blocking as needed. - void IfDummyThreadTryWait(); - void IfDummyThreadEndWait(); + void RequestDummyThreadWait(); + void DummyThreadBeginWait(); + void DummyThreadEndWait(); [[nodiscard]] uintptr_t GetArgument() const { return argument; @@ -777,8 +778,7 @@ private: bool is_single_core{}; ThreadType thread_type{}; StepState step_state{}; - std::mutex dummy_wait_lock; - std::condition_variable dummy_wait_cv; + std::atomic dummy_thread_runnable{true}; // For debugging std::vector wait_objects_for_debugging;