From 6e953f7f0294d945ba9d6f08350d5dccb0d76075 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 21 Jan 2021 13:00:16 -0800 Subject: [PATCH] hle: kernel: Allocate a dummy KThread for each host thread, and use it for scheduling. --- src/core/hle/kernel/k_light_lock.cpp | 12 +++--------- src/core/hle/kernel/k_scheduler.cpp | 6 +++--- src/core/hle/kernel/k_scheduler.h | 4 ++-- src/core/hle/kernel/k_scheduler_lock.h | 27 +++++++++++++------------- src/core/hle/kernel/k_thread.cpp | 6 +----- src/core/hle/kernel/kernel.cpp | 27 +++++++++++++++++++------- src/core/hle/kernel/kernel.h | 4 ++-- src/yuzu/main.cpp | 2 -- 8 files changed, 45 insertions(+), 43 deletions(-) diff --git a/src/core/hle/kernel/k_light_lock.cpp b/src/core/hle/kernel/k_light_lock.cpp index 1d54ba5df0..08fa65fd59 100644 --- a/src/core/hle/kernel/k_light_lock.cpp +++ b/src/core/hle/kernel/k_light_lock.cpp @@ -9,12 +9,6 @@ namespace Kernel { -static KThread* ToThread(uintptr_t thread_) { - ASSERT((thread_ & EmuThreadHandleReserved) == 0); - ASSERT((thread_ & 1) == 0); - return reinterpret_cast(thread_); -} - void KLightLock::Lock() { const uintptr_t cur_thread = reinterpret_cast(GetCurrentThreadPointer(kernel)); const uintptr_t cur_thread_tag = (cur_thread | 1); @@ -48,7 +42,7 @@ void KLightLock::Unlock() { } void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { - KThread* cur_thread = ToThread(_cur_thread); + KThread* cur_thread = reinterpret_cast(_cur_thread); // Pend the current thread waiting on the owner thread. { @@ -60,7 +54,7 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { } // Add the current thread as a waiter on the owner. - KThread* owner_thread = ToThread(_owner & ~1ul); + KThread* owner_thread = reinterpret_cast(_owner & ~1ul); cur_thread->SetAddressKey(reinterpret_cast(std::addressof(tag))); owner_thread->AddWaiter(cur_thread); @@ -88,7 +82,7 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) { } void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) { - KThread* owner_thread = ToThread(_cur_thread); + KThread* owner_thread = reinterpret_cast(_cur_thread); // Unlock. { diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index fbdc061df8..bb5f43b535 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -623,7 +623,7 @@ KThread* KScheduler::GetCurrentThread() const { if (auto result = current_thread.load(); result) { return result; } - return idle_thread.get(); + return idle_thread; } u64 KScheduler::GetLastContextSwitchTicks() const { @@ -708,7 +708,7 @@ void KScheduler::ScheduleImpl() { // We never want to schedule a null thread, so use the idle thread if we don't have a next. if (next_thread == nullptr) { - next_thread = idle_thread.get(); + next_thread = idle_thread; } // If we're not actually switching thread, there's nothing to do. @@ -803,7 +803,7 @@ void KScheduler::Initialize() { auto thread_res = KThread::Create(system, ThreadType::Main, name, 0, KThread::IdleThreadPriority, 0, static_cast(core_id), 0, nullptr, std::move(init_func), init_func_parameter); - idle_thread = thread_res.Unwrap(); + idle_thread = thread_res.Unwrap().get(); } KScopedSchedulerLock::KScopedSchedulerLock(KernelCore& kernel) diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h index e0d0525937..f595b9a5c9 100644 --- a/src/core/hle/kernel/k_scheduler.h +++ b/src/core/hle/kernel/k_scheduler.h @@ -54,7 +54,7 @@ public: /// Returns true if the scheduler is idle [[nodiscard]] bool IsIdle() const { - return GetCurrentThread() == idle_thread.get(); + return GetCurrentThread() == idle_thread; } /// Gets the timestamp for the last context switch in ticks. @@ -176,7 +176,7 @@ private: KThread* prev_thread{}; std::atomic current_thread{}; - std::shared_ptr idle_thread; + KThread* idle_thread; std::shared_ptr switch_fiber{}; diff --git a/src/core/hle/kernel/k_scheduler_lock.h b/src/core/hle/kernel/k_scheduler_lock.h index 5d48dcf381..3b38f8f3e9 100644 --- a/src/core/hle/kernel/k_scheduler_lock.h +++ b/src/core/hle/kernel/k_scheduler_lock.h @@ -10,6 +10,7 @@ #include "common/assert.h" #include "common/spin_lock.h" #include "core/hardware_properties.h" +#include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" namespace Kernel { @@ -22,42 +23,42 @@ public: explicit KAbstractSchedulerLock(KernelCore& kernel_) : kernel{kernel_} {} bool IsLockedByCurrentThread() const { - return this->owner_thread == kernel.GetCurrentEmuThreadID(); + return this->owner_thread == GetCurrentThreadPointer(kernel); } void Lock() { if (this->IsLockedByCurrentThread()) { // If we already own the lock, we can just increment the count. - ASSERT(this->lock_count > 0); - this->lock_count++; + ASSERT(lock_count > 0); + lock_count++; } else { // Otherwise, we want to disable scheduling and acquire the spinlock. SchedulerType::DisableScheduling(kernel); - this->spin_lock.lock(); + spin_lock.lock(); // For debug, ensure that our state is valid. - ASSERT(this->lock_count == 0); - ASSERT(this->owner_thread == EmuThreadHandleInvalid); + ASSERT(lock_count == 0); + ASSERT(owner_thread == nullptr); // Increment count, take ownership. - this->lock_count = 1; - this->owner_thread = kernel.GetCurrentEmuThreadID(); + lock_count = 1; + owner_thread = GetCurrentThreadPointer(kernel); } } void Unlock() { ASSERT(this->IsLockedByCurrentThread()); - ASSERT(this->lock_count > 0); + ASSERT(lock_count > 0); // Release an instance of the lock. - if ((--this->lock_count) == 0) { + if ((--lock_count) == 0) { // We're no longer going to hold the lock. Take note of what cores need scheduling. const u64 cores_needing_scheduling = SchedulerType::UpdateHighestPriorityThreads(kernel); // Note that we no longer hold the lock, and unlock the spinlock. - this->owner_thread = EmuThreadHandleInvalid; - this->spin_lock.unlock(); + owner_thread = nullptr; + spin_lock.unlock(); // Enable scheduling, and perform a rescheduling operation. SchedulerType::EnableScheduling(kernel, cores_needing_scheduling); @@ -68,7 +69,7 @@ private: KernelCore& kernel; Common::SpinLock spin_lock{}; s32 lock_count{}; - EmuThreadHandle owner_thread{EmuThreadHandleInvalid}; + KThread* owner_thread{}; }; } // namespace Kernel diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 62ce2fbd56..f57e98047c 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -1034,11 +1034,7 @@ ResultVal> KThread::Create(Core::System& system, Thread } KThread* GetCurrentThreadPointer(KernelCore& kernel) { - if (!kernel.CurrentScheduler()) { - // We are not called from a core thread - return {}; - } - return kernel.CurrentScheduler()->GetCurrentThread(); + return kernel.GetCurrentEmuThread(); } KThread& GetCurrentThread(KernelCore& kernel) { diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 6142496b61..093886b7c6 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -57,9 +57,10 @@ struct KernelCore::Impl { } void Initialize(KernelCore& kernel) { + global_scheduler_context = std::make_unique(kernel); + RegisterHostThread(); - global_scheduler_context = std::make_unique(kernel); service_thread_manager = std::make_unique(1, "yuzu:ServiceThreadManager"); is_phantom_mode_for_singlecore = false; @@ -206,6 +207,18 @@ struct KernelCore::Impl { return host_thread_id; } + // Gets the dummy KThread for the caller, allocating a new one if this is the first time + KThread* GetHostDummyThread() { + const thread_local auto thread = + KThread::Create( + system, ThreadType::Main, + std::string{"DummyThread:" + GetHostThreadId()}, 0, KThread::DefaultThreadPriority, + 0, static_cast(3), 0, nullptr, + []([[maybe_unused]] void* arg) { UNREACHABLE(); }, nullptr) + .Unwrap(); + return thread.get(); + } + /// Registers a CPU core thread by allocating a host thread ID for it void RegisterCoreThread(std::size_t core_id) { ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); @@ -218,6 +231,7 @@ struct KernelCore::Impl { /// Registers a new host thread by allocating a host thread ID for it void RegisterHostThread() { [[maybe_unused]] const auto this_id = GetHostThreadId(); + [[maybe_unused]] const auto dummy_thread = GetHostDummyThread(); } [[nodiscard]] u32 GetCurrentHostThreadID() { @@ -237,13 +251,12 @@ struct KernelCore::Impl { is_phantom_mode_for_singlecore = value; } - [[nodiscard]] EmuThreadHandle GetCurrentEmuThreadID() { + KThread* GetCurrentEmuThread() { const auto thread_id = GetCurrentHostThreadID(); if (thread_id >= Core::Hardware::NUM_CPU_CORES) { - // Reserved value for HLE threads - return EmuThreadHandleReserved + (static_cast(thread_id) << 1); + return GetHostDummyThread(); } - return reinterpret_cast(schedulers[thread_id].get()); + return schedulers[thread_id]->GetCurrentThread(); } void InitializeMemoryLayout() { @@ -548,8 +561,8 @@ u32 KernelCore::GetCurrentHostThreadID() const { return impl->GetCurrentHostThreadID(); } -EmuThreadHandle KernelCore::GetCurrentEmuThreadID() const { - return impl->GetCurrentEmuThreadID(); +KThread* KernelCore::GetCurrentEmuThread() const { + return impl->GetCurrentEmuThread(); } Memory::MemoryManager& KernelCore::MemoryManager() { diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index b92c017f60..e7c77727bf 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -165,8 +165,8 @@ public: /// Determines whether or not the given port is a valid named port. bool IsValidNamedPort(NamedPortTable::const_iterator port) const; - /// Gets the current host_thread/guest_thread handle. - EmuThreadHandle GetCurrentEmuThreadID() const; + /// Gets the current host_thread/guest_thread pointer. + KThread* GetCurrentEmuThread() const; /// Gets the current host_thread handle. u32 GetCurrentHostThreadID() const; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index e761411254..886e6e9d2b 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1039,8 +1039,6 @@ bool GMainWindow::LoadROM(const QString& filename, std::size_t program_index) { std::make_unique(*this), // Web Browser }); - system.RegisterHostThread(); - const Core::System::ResultStatus result{ system.Load(*render_window, filename.toStdString(), program_index)};