From a4455c26126a61db846dad64ebe7558f7c20a131 Mon Sep 17 00:00:00 2001 From: pineappleEA Date: Sat, 22 Jan 2022 03:12:16 +0100 Subject: [PATCH] early-access version 2426 --- README.md | 2 +- src/core/hle/kernel/k_priority_queue.h | 36 +++++++++++++++++++++ src/core/hle/kernel/k_scheduler.cpp | 3 ++ src/core/hle/kernel/k_thread.cpp | 37 ++++++++++++++++++++++ src/core/hle/kernel/k_thread.h | 13 ++++++++ src/core/hle/service/apm/apm_interface.cpp | 14 +++++++- 6 files changed, 103 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e9a63fe67..847c092f6 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 2425. +This is the source code for early-access 2426. ## Legal Notice diff --git a/src/core/hle/kernel/k_priority_queue.h b/src/core/hle/kernel/k_priority_queue.h index f4d71ad7e..0b894c8cf 100755 --- a/src/core/hle/kernel/k_priority_queue.h +++ b/src/core/hle/kernel/k_priority_queue.h @@ -45,6 +45,7 @@ concept KPriorityQueueMember = !std::is_reference_v && requires(T & t) { { t.GetActiveCore() } -> Common::ConvertibleTo; { t.GetPriority() } -> Common::ConvertibleTo; + { t.IsDummyThread() } -> Common::ConvertibleTo; }; template @@ -349,24 +350,49 @@ public: // Mutators. constexpr void PushBack(Member* member) { + // This is for host (dummy) threads that we do not want to enter the priority queue. + if (member->IsDummyThread()) { + return; + } + this->PushBack(member->GetPriority(), member); } constexpr void Remove(Member* member) { + // This is for host (dummy) threads that we do not want to enter the priority queue. + if (member->IsDummyThread()) { + return; + } + this->Remove(member->GetPriority(), member); } constexpr void MoveToScheduledFront(Member* member) { + // This is for host (dummy) threads that we do not want to enter the priority queue. + if (member->IsDummyThread()) { + return; + } + this->scheduled_queue.MoveToFront(member->GetPriority(), member->GetActiveCore(), member); } constexpr KThread* MoveToScheduledBack(Member* member) { + // This is for host (dummy) threads that we do not want to enter the priority queue. + if (member->IsDummyThread()) { + return {}; + } + return this->scheduled_queue.MoveToBack(member->GetPriority(), member->GetActiveCore(), member); } // First class fancy operations. constexpr void ChangePriority(s32 prev_priority, bool is_running, Member* member) { + // This is for host (dummy) threads that we do not want to enter the priority queue. + if (member->IsDummyThread()) { + return; + } + ASSERT(IsValidPriority(prev_priority)); // Remove the member from the queues. @@ -383,6 +409,11 @@ public: constexpr void ChangeAffinityMask(s32 prev_core, const AffinityMaskType& prev_affinity, Member* member) { + // This is for host (dummy) threads that we do not want to enter the priority queue. + if (member->IsDummyThread()) { + return; + } + // Get the new information. const s32 priority = member->GetPriority(); const AffinityMaskType& new_affinity = member->GetAffinityMask(); @@ -412,6 +443,11 @@ public: } constexpr void ChangeCore(s32 prev_core, Member* member, bool to_front = false) { + // This is for host (dummy) threads that we do not want to enter the priority queue. + if (member->IsDummyThread()) { + return; + } + // Get the new information. const s32 new_core = member->GetActiveCore(); const s32 priority = member->GetPriority(); diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 1b2a01869..b32d4f285 100755 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -406,6 +406,9 @@ void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduli } else { RescheduleCores(kernel, cores_needing_scheduling); } + + // Special case to ensure dummy threads that are waiting block. + current_thread->IfDummyThreadTryWait(); } u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) { diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 4cbf12c11..f42abb8a1 100755 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -1075,12 +1075,46 @@ ResultCode KThread::Sleep(s64 timeout) { return ResultSuccess; } +void KThread::IfDummyThreadTryWait() { + if (!IsDummyThread()) { + return; + } + + if (GetState() != ThreadState::Waiting) { + return; + } + + // Block until we can grab the lock. + KScopedSpinLock lk{dummy_wait_lock}; +} + +void KThread::IfDummyThreadBeginWait() { + if (!IsDummyThread()) { + return; + } + + // Ensure the thread will block when IfDummyThreadTryWait is called. + dummy_wait_lock.Lock(); +} + +void KThread::IfDummyThreadEndWait() { + if (!IsDummyThread()) { + return; + } + + // Ensure the thread will no longer block. + dummy_wait_lock.Unlock(); +} + void KThread::BeginWait(KThreadQueue* queue) { // Set our state as waiting. SetState(ThreadState::Waiting); // Set our wait queue. wait_queue = queue; + + // Special case for dummy threads to ensure they block. + IfDummyThreadBeginWait(); } void KThread::NotifyAvailable(KSynchronizationObject* signaled_object, ResultCode wait_result_) { @@ -1106,6 +1140,9 @@ void KThread::EndWait(ResultCode wait_result_) { } wait_queue->EndWait(this, wait_result_); + + // Special case for dummy threads to wakeup if necessary. + IfDummyThreadEndWait(); } } diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index 77b53a198..d058db62c 100755 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -558,6 +558,10 @@ public: return thread_type; } + [[nodiscard]] bool IsDummyThread() const { + return GetThreadType() == ThreadType::Dummy; + } + void SetWaitObjectsForDebugging(const std::span& objects) { wait_objects_for_debugging.clear(); wait_objects_for_debugging.reserve(objects.size()); @@ -632,6 +636,14 @@ public: return condvar_key; } + // Dummy threads (used for HLE host threads) cannot wait based on the guest scheduler, and + // therefore will not block on guest kernel synchronization primitives. These methods handle + // blocking as needed. + + void IfDummyThreadTryWait(); + void IfDummyThreadBeginWait(); + void IfDummyThreadEndWait(); + private: static constexpr size_t PriorityInheritanceCountMax = 10; union SyncObjectBuffer { @@ -750,6 +762,7 @@ private: bool resource_limit_release_hint{}; StackParameters stack_parameters{}; KSpinLock context_guard{}; + KSpinLock dummy_wait_lock{}; // For emulation std::shared_ptr host_context{}; diff --git a/src/core/hle/service/apm/apm_interface.cpp b/src/core/hle/service/apm/apm_interface.cpp index e58bad083..6163e3294 100755 --- a/src/core/hle/service/apm/apm_interface.cpp +++ b/src/core/hle/service/apm/apm_interface.cpp @@ -17,7 +17,7 @@ public: static const FunctionInfo functions[] = { {0, &ISession::SetPerformanceConfiguration, "SetPerformanceConfiguration"}, {1, &ISession::GetPerformanceConfiguration, "GetPerformanceConfiguration"}, - {2, nullptr, "SetCpuOverclockEnabled"}, + {2, &ISession::SetCpuOverclockEnabled, "SetCpuOverclockEnabled"}, }; RegisterHandlers(functions); } @@ -47,6 +47,18 @@ private: rb.PushEnum(controller.GetCurrentPerformanceConfiguration(mode)); } + void SetCpuOverclockEnabled(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + const auto cpu_overclock_enabled = rp.Pop(); + + LOG_WARNING(Service_APM, "(STUBBED) called, cpu_overclock_enabled={}", + cpu_overclock_enabled); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + Controller& controller; };