Просмотр исходного кода

hle: kernel: Allocate a dummy KThread for each host thread, and use it for scheduling.

bunnei 5 лет назад
Родитель
Сommit
6e953f7f02

+ 3 - 9
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<KThread*>(thread_);
-}
-
 void KLightLock::Lock() {
     const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(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<KThread*>(_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<KThread*>(_owner & ~1ul);
         cur_thread->SetAddressKey(reinterpret_cast<uintptr_t>(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<KThread*>(_cur_thread);
 
     // Unlock.
     {

+ 3 - 3
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<u32>(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)

+ 2 - 2
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<KThread*> current_thread{};
 
-    std::shared_ptr<KThread> idle_thread;
+    KThread* idle_thread;
 
     std::shared_ptr<Common::Fiber> switch_fiber{};
 

+ 14 - 13
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

+ 1 - 5
src/core/hle/kernel/k_thread.cpp

@@ -1034,11 +1034,7 @@ ResultVal<std::shared_ptr<KThread>> 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) {

+ 20 - 7
src/core/hle/kernel/kernel.cpp

@@ -57,9 +57,10 @@ struct KernelCore::Impl {
     }
 
     void Initialize(KernelCore& kernel) {
+        global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
+
         RegisterHostThread();
 
-        global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
         service_thread_manager =
             std::make_unique<Common::ThreadWorker>(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<u32>(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<u64>(thread_id) << 1);
+            return GetHostDummyThread();
         }
-        return reinterpret_cast<uintptr_t>(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() {

+ 2 - 2
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;

+ 0 - 2
src/yuzu/main.cpp

@@ -1039,8 +1039,6 @@ bool GMainWindow::LoadROM(const QString& filename, std::size_t program_index) {
         std::make_unique<QtWebBrowser>(*this),         // Web Browser
     });
 
-    system.RegisterHostThread();
-
     const Core::System::ResultStatus result{
         system.Load(*render_window, filename.toStdString(), program_index)};