From c0d3aef28c0a0c68c18de30228f29e30f0e52533 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Wed, 30 Dec 2020 23:01:08 -0800
Subject: [PATCH 01/34] core: hle: kernel: Rename Thread to KThread.

---
 src/core/CMakeLists.txt                       |  4 +-
 src/core/core.cpp                             |  2 +-
 src/core/cpu_manager.cpp                      |  8 +-
 src/core/hle/kernel/client_session.cpp        |  4 +-
 src/core/hle/kernel/client_session.h          |  4 +-
 .../hle/kernel/global_scheduler_context.cpp   |  4 +-
 .../hle/kernel/global_scheduler_context.h     | 12 +--
 src/core/hle/kernel/handle_table.cpp          |  2 +-
 src/core/hle/kernel/hle_ipc.cpp               |  6 +-
 src/core/hle/kernel/hle_ipc.h                 | 14 ++--
 src/core/hle/kernel/k_address_arbiter.cpp     | 12 +--
 src/core/hle/kernel/k_condition_variable.cpp  | 34 ++++----
 src/core/hle/kernel/k_condition_variable.h    | 10 +--
 src/core/hle/kernel/k_priority_queue.h        |  4 +-
 src/core/hle/kernel/k_scheduler.cpp           | 70 ++++++++---------
 src/core/hle/kernel/k_scheduler.h             | 24 +++---
 .../k_scoped_scheduler_lock_and_sleep.h       |  6 +-
 .../hle/kernel/k_synchronization_object.cpp   | 10 +--
 .../hle/kernel/k_synchronization_object.h     |  6 +-
 .../hle/kernel/{thread.cpp => k_thread.cpp}   | 78 +++++++++----------
 src/core/hle/kernel/{thread.h => k_thread.h}  | 65 ++++++++--------
 src/core/hle/kernel/kernel.cpp                | 14 ++--
 src/core/hle/kernel/kernel.h                  |  6 +-
 src/core/hle/kernel/process.cpp               | 14 ++--
 src/core/hle/kernel/process.h                 | 10 +--
 src/core/hle/kernel/readable_event.cpp        |  2 +-
 src/core/hle/kernel/server_port.cpp           |  2 +-
 src/core/hle/kernel/server_session.cpp        |  6 +-
 src/core/hle/kernel/server_session.h          | 10 +--
 src/core/hle/kernel/svc.cpp                   | 30 +++----
 src/core/hle/kernel/time_manager.cpp          |  8 +-
 src/core/hle/kernel/time_manager.h            |  6 +-
 src/core/hle/kernel/writable_event.cpp        |  2 +-
 src/core/hle/service/nfp/nfp.cpp              |  2 +-
 src/core/hle/service/nvdrv/interface.cpp      |  2 +-
 src/core/hle/service/service.cpp              |  2 +-
 src/core/hle/service/sockets/bsd.cpp          |  2 +-
 src/core/hle/service/time/time.cpp            |  2 +-
 src/core/hle/service/time/time.h              |  2 +-
 src/core/hle/service/time/time_sharedmemory.h |  2 +-
 src/core/hle/service/vi/vi.cpp                |  2 +-
 src/core/loader/nro.cpp                       |  2 +-
 src/core/loader/nso.cpp                       |  2 +-
 src/yuzu/debugger/wait_tree.cpp               | 20 ++---
 src/yuzu/debugger/wait_tree.h                 | 14 ++--
 45 files changed, 271 insertions(+), 272 deletions(-)
 rename src/core/hle/kernel/{thread.cpp => k_thread.cpp} (85%)
 rename src/core/hle/kernel/{thread.h => k_thread.h} (91%)

diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 9c9b3195b..88a31e0f2 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -168,6 +168,8 @@ add_library(core STATIC
     hle/kernel/k_scoped_scheduler_lock_and_sleep.h
     hle/kernel/k_synchronization_object.cpp
     hle/kernel/k_synchronization_object.h
+    hle/kernel/k_thread.cpp
+    hle/kernel/k_thread.h
     hle/kernel/kernel.cpp
     hle/kernel/kernel.h
     hle/kernel/memory/address_space_info.cpp
@@ -216,8 +218,6 @@ add_library(core STATIC
     hle/kernel/svc_results.h
     hle/kernel/svc_types.h
     hle/kernel/svc_wrap.h
-    hle/kernel/thread.cpp
-    hle/kernel/thread.h
     hle/kernel/time_manager.cpp
     hle/kernel/time_manager.h
     hle/kernel/transfer_memory.cpp
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 86bdc7f6b..30f5e1128 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -28,10 +28,10 @@
 #include "core/hardware_interrupt_manager.h"
 #include "core/hle/kernel/client_port.h"
 #include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/physical_core.h"
 #include "core/hle/kernel/process.h"
-#include "core/hle/kernel/thread.h"
 #include "core/hle/service/am/applets/applets.h"
 #include "core/hle/service/apm/controller.h"
 #include "core/hle/service/filesystem/filesystem.h"
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index 373395047..122edb588 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -11,9 +11,9 @@
 #include "core/core_timing.h"
 #include "core/cpu_manager.h"
 #include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/physical_core.h"
-#include "core/hle/kernel/thread.h"
 #include "video_core/gpu.h"
 
 namespace Core {
@@ -147,7 +147,7 @@ void CpuManager::MultiCoreRunSuspendThread() {
     while (true) {
         auto core = kernel.GetCurrentHostThreadID();
         auto& scheduler = *kernel.CurrentScheduler();
-        Kernel::Thread* current_thread = scheduler.GetCurrentThread();
+        Kernel::KThread* current_thread = scheduler.GetCurrentThread();
         Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[core].host_context);
         ASSERT(scheduler.ContextSwitchPending());
         ASSERT(core == kernel.GetCurrentHostThreadID());
@@ -245,7 +245,7 @@ void CpuManager::SingleCoreRunSuspendThread() {
     while (true) {
         auto core = kernel.GetCurrentHostThreadID();
         auto& scheduler = *kernel.CurrentScheduler();
-        Kernel::Thread* current_thread = scheduler.GetCurrentThread();
+        Kernel::KThread* current_thread = scheduler.GetCurrentThread();
         Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[0].host_context);
         ASSERT(scheduler.ContextSwitchPending());
         ASSERT(core == kernel.GetCurrentHostThreadID());
@@ -256,7 +256,7 @@ void CpuManager::SingleCoreRunSuspendThread() {
 void CpuManager::PreemptSingleCore(bool from_running_enviroment) {
     {
         auto& scheduler = system.Kernel().Scheduler(current_core);
-        Kernel::Thread* current_thread = scheduler.GetCurrentThread();
+        Kernel::KThread* current_thread = scheduler.GetCurrentThread();
         if (idle_count >= 4 || from_running_enviroment) {
             if (!from_running_enviroment) {
                 system.CoreTiming().Idle();
diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp
index e8e52900d..a2be1a8f6 100644
--- a/src/core/hle/kernel/client_session.cpp
+++ b/src/core/hle/kernel/client_session.cpp
@@ -5,9 +5,9 @@
 #include "core/hle/kernel/client_session.h"
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/server_session.h"
 #include "core/hle/kernel/session.h"
-#include "core/hle/kernel/thread.h"
 #include "core/hle/result.h"
 
 namespace Kernel {
@@ -38,7 +38,7 @@ ResultVal<std::shared_ptr<ClientSession>> ClientSession::Create(KernelCore& kern
     return MakeResult(std::move(client_session));
 }
 
-ResultCode ClientSession::SendSyncRequest(std::shared_ptr<Thread> thread,
+ResultCode ClientSession::SendSyncRequest(std::shared_ptr<KThread> thread,
                                           Core::Memory::Memory& memory,
                                           Core::Timing::CoreTiming& core_timing) {
     // Keep ServerSession alive until we're done working with it.
diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h
index d5c9ebee8..a914c0990 100644
--- a/src/core/hle/kernel/client_session.h
+++ b/src/core/hle/kernel/client_session.h
@@ -24,7 +24,7 @@ namespace Kernel {
 
 class KernelCore;
 class Session;
-class Thread;
+class KThread;
 
 class ClientSession final : public KSynchronizationObject {
 public:
@@ -46,7 +46,7 @@ public:
         return HANDLE_TYPE;
     }
 
-    ResultCode SendSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory,
+    ResultCode SendSyncRequest(std::shared_ptr<KThread> thread, Core::Memory::Memory& memory,
                                Core::Timing::CoreTiming& core_timing);
 
     bool IsSignaled() const override;
diff --git a/src/core/hle/kernel/global_scheduler_context.cpp b/src/core/hle/kernel/global_scheduler_context.cpp
index a133e8ed0..c6838649f 100644
--- a/src/core/hle/kernel/global_scheduler_context.cpp
+++ b/src/core/hle/kernel/global_scheduler_context.cpp
@@ -17,12 +17,12 @@ GlobalSchedulerContext::GlobalSchedulerContext(KernelCore& kernel)
 
 GlobalSchedulerContext::~GlobalSchedulerContext() = default;
 
-void GlobalSchedulerContext::AddThread(std::shared_ptr<Thread> thread) {
+void GlobalSchedulerContext::AddThread(std::shared_ptr<KThread> thread) {
     std::scoped_lock lock{global_list_guard};
     thread_list.push_back(std::move(thread));
 }
 
-void GlobalSchedulerContext::RemoveThread(std::shared_ptr<Thread> thread) {
+void GlobalSchedulerContext::RemoveThread(std::shared_ptr<KThread> thread) {
     std::scoped_lock lock{global_list_guard};
     thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread),
                       thread_list.end());
diff --git a/src/core/hle/kernel/global_scheduler_context.h b/src/core/hle/kernel/global_scheduler_context.h
index 5c7b89290..a365ffdaf 100644
--- a/src/core/hle/kernel/global_scheduler_context.h
+++ b/src/core/hle/kernel/global_scheduler_context.h
@@ -12,7 +12,7 @@
 #include "core/hardware_properties.h"
 #include "core/hle/kernel/k_priority_queue.h"
 #include "core/hle/kernel/k_scheduler_lock.h"
-#include "core/hle/kernel/thread.h"
+#include "core/hle/kernel/k_thread.h"
 
 namespace Kernel {
 
@@ -20,7 +20,7 @@ class KernelCore;
 class SchedulerLock;
 
 using KSchedulerPriorityQueue =
-    KPriorityQueue<Thread, Core::Hardware::NUM_CPU_CORES, THREADPRIO_LOWEST, THREADPRIO_HIGHEST>;
+    KPriorityQueue<KThread, Core::Hardware::NUM_CPU_CORES, THREADPRIO_LOWEST, THREADPRIO_HIGHEST>;
 constexpr s32 HighestCoreMigrationAllowedPriority = 2;
 
 class GlobalSchedulerContext final {
@@ -33,13 +33,13 @@ public:
     ~GlobalSchedulerContext();
 
     /// Adds a new thread to the scheduler
-    void AddThread(std::shared_ptr<Thread> thread);
+    void AddThread(std::shared_ptr<KThread> thread);
 
     /// Removes a thread from the scheduler
-    void RemoveThread(std::shared_ptr<Thread> thread);
+    void RemoveThread(std::shared_ptr<KThread> thread);
 
     /// Returns a list of all threads managed by the scheduler
-    [[nodiscard]] const std::vector<std::shared_ptr<Thread>>& GetThreadList() const {
+    [[nodiscard]] const std::vector<std::shared_ptr<KThread>>& GetThreadList() const {
         return thread_list;
     }
 
@@ -74,7 +74,7 @@ private:
     LockType scheduler_lock;
 
     /// Lists all thread ids that aren't deleted/etc.
-    std::vector<std::shared_ptr<Thread>> thread_list;
+    std::vector<std::shared_ptr<KThread>> thread_list;
     Common::SpinLock global_list_guard{};
 };
 
diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp
index 40988b0fd..10a4e0510 100644
--- a/src/core/hle/kernel/handle_table.cpp
+++ b/src/core/hle/kernel/handle_table.cpp
@@ -9,9 +9,9 @@
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/handle_table.h"
 #include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/process.h"
-#include "core/hle/kernel/thread.h"
 
 namespace Kernel {
 namespace {
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index a419f9602..c7b10ca7a 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -19,12 +19,12 @@
 #include "core/hle/kernel/hle_ipc.h"
 #include "core/hle/kernel/k_scheduler.h"
 #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/readable_event.h"
 #include "core/hle/kernel/server_session.h"
-#include "core/hle/kernel/thread.h"
 #include "core/hle/kernel/time_manager.h"
 #include "core/hle/kernel/writable_event.h"
 #include "core/memory.h"
@@ -48,7 +48,7 @@ void SessionRequestHandler::ClientDisconnected(
 
 HLERequestContext::HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory,
                                      std::shared_ptr<ServerSession> server_session,
-                                     std::shared_ptr<Thread> thread)
+                                     std::shared_ptr<KThread> thread)
     : server_session(std::move(server_session)),
       thread(std::move(thread)), kernel{kernel}, memory{memory} {
     cmd_buf[0] = 0;
@@ -182,7 +182,7 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const HandleTabl
     return RESULT_SUCCESS;
 }
 
-ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) {
+ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& thread) {
     auto& owner_process = *thread.GetOwnerProcess();
     auto& handle_table = owner_process.GetHandleTable();
 
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 698f607e6..b8a746882 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -40,7 +40,7 @@ class HLERequestContext;
 class KernelCore;
 class Process;
 class ServerSession;
-class Thread;
+class KThread;
 class ReadableEvent;
 class WritableEvent;
 
@@ -110,7 +110,7 @@ class HLERequestContext {
 public:
     explicit HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory,
                                std::shared_ptr<ServerSession> session,
-                               std::shared_ptr<Thread> thread);
+                               std::shared_ptr<KThread> thread);
     ~HLERequestContext();
 
     /// Returns a pointer to the IPC command buffer for this request.
@@ -127,14 +127,14 @@ public:
     }
 
     using WakeupCallback = std::function<void(
-        std::shared_ptr<Thread> thread, HLERequestContext& context, ThreadWakeupReason reason)>;
+        std::shared_ptr<KThread> thread, HLERequestContext& context, ThreadWakeupReason reason)>;
 
     /// Populates this context with data from the requesting process/thread.
     ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table,
                                                  u32_le* src_cmdbuf);
 
     /// Writes data from this context back to the requesting process/thread.
-    ResultCode WriteToOutgoingCommandBuffer(Thread& thread);
+    ResultCode WriteToOutgoingCommandBuffer(KThread& thread);
 
     u32_le GetCommand() const {
         return command;
@@ -267,11 +267,11 @@ public:
 
     std::string Description() const;
 
-    Thread& GetThread() {
+    KThread& GetThread() {
         return *thread;
     }
 
-    const Thread& GetThread() const {
+    const KThread& GetThread() const {
         return *thread;
     }
 
@@ -286,7 +286,7 @@ private:
 
     std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
     std::shared_ptr<Kernel::ServerSession> server_session;
-    std::shared_ptr<Thread> thread;
+    std::shared_ptr<KThread> thread;
     // TODO(yuriks): Check common usage of this and optimize size accordingly
     boost::container::small_vector<std::shared_ptr<Object>, 8> move_objects;
     boost::container::small_vector<std::shared_ptr<Object>, 8> copy_objects;
diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp
index d9e702f13..282f02257 100644
--- a/src/core/hle/kernel/k_address_arbiter.cpp
+++ b/src/core/hle/kernel/k_address_arbiter.cpp
@@ -7,9 +7,9 @@
 #include "core/hle/kernel/k_address_arbiter.h"
 #include "core/hle/kernel/k_scheduler.h"
 #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/svc_results.h"
-#include "core/hle/kernel/thread.h"
 #include "core/hle/kernel/time_manager.h"
 #include "core/memory.h"
 
@@ -96,7 +96,7 @@ ResultCode KAddressArbiter::Signal(VAddr addr, s32 count) {
         auto it = thread_tree.nfind_light({addr, -1});
         while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
                (it->GetAddressArbiterKey() == addr)) {
-            Thread* target_thread = std::addressof(*it);
+            KThread* target_thread = std::addressof(*it);
             target_thread->SetSyncedObject(nullptr, RESULT_SUCCESS);
 
             ASSERT(target_thread->IsWaitingForAddressArbiter());
@@ -125,7 +125,7 @@ ResultCode KAddressArbiter::SignalAndIncrementIfEqual(VAddr addr, s32 value, s32
         auto it = thread_tree.nfind_light({addr, -1});
         while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
                (it->GetAddressArbiterKey() == addr)) {
-            Thread* target_thread = std::addressof(*it);
+            KThread* target_thread = std::addressof(*it);
             target_thread->SetSyncedObject(nullptr, RESULT_SUCCESS);
 
             ASSERT(target_thread->IsWaitingForAddressArbiter());
@@ -215,7 +215,7 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32
 
         while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
                (it->GetAddressArbiterKey() == addr)) {
-            Thread* target_thread = std::addressof(*it);
+            KThread* target_thread = std::addressof(*it);
             target_thread->SetSyncedObject(nullptr, RESULT_SUCCESS);
 
             ASSERT(target_thread->IsWaitingForAddressArbiter());
@@ -231,7 +231,7 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32
 
 ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement, s64 timeout) {
     // Prepare to wait.
-    Thread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread();
+    KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread();
     Handle timer = InvalidHandle;
 
     {
@@ -302,7 +302,7 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement
 
 ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) {
     // Prepare to wait.
-    Thread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread();
+    KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread();
     Handle timer = InvalidHandle;
 
     {
diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp
index 49a068310..2fa2d5289 100644
--- a/src/core/hle/kernel/k_condition_variable.cpp
+++ b/src/core/hle/kernel/k_condition_variable.cpp
@@ -10,11 +10,11 @@
 #include "core/hle/kernel/k_scheduler.h"
 #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
 #include "core/hle/kernel/k_synchronization_object.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/svc_common.h"
 #include "core/hle/kernel/svc_results.h"
-#include "core/hle/kernel/thread.h"
 #include "core/memory.h"
 
 namespace Kernel {
@@ -66,7 +66,7 @@ KConditionVariable::KConditionVariable(Core::System& system_)
 KConditionVariable::~KConditionVariable() = default;
 
 ResultCode KConditionVariable::SignalToAddress(VAddr addr) {
-    Thread* owner_thread = kernel.CurrentScheduler()->GetCurrentThread();
+    KThread* owner_thread = kernel.CurrentScheduler()->GetCurrentThread();
 
     // Signal the address.
     {
@@ -74,7 +74,7 @@ ResultCode KConditionVariable::SignalToAddress(VAddr addr) {
 
         // Remove waiter thread.
         s32 num_waiters{};
-        Thread* next_owner_thread =
+        KThread* next_owner_thread =
             owner_thread->RemoveWaiterByKey(std::addressof(num_waiters), addr);
 
         // Determine the next tag.
@@ -103,11 +103,11 @@ ResultCode KConditionVariable::SignalToAddress(VAddr addr) {
 }
 
 ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value) {
-    Thread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread();
+    KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread();
 
     // Wait for the address.
     {
-        std::shared_ptr<Thread> owner_thread;
+        std::shared_ptr<KThread> owner_thread;
         ASSERT(!owner_thread);
         {
             KScopedSchedulerLock sl(kernel);
@@ -126,7 +126,7 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val
                 R_UNLESS(test_tag == (handle | Svc::HandleWaitMask), RESULT_SUCCESS);
 
                 // Get the lock owner thread.
-                owner_thread = kernel.CurrentProcess()->GetHandleTable().Get<Thread>(handle);
+                owner_thread = kernel.CurrentProcess()->GetHandleTable().Get<KThread>(handle);
                 R_UNLESS(owner_thread, Svc::ResultInvalidHandle);
 
                 // Update the lock.
@@ -143,7 +143,7 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val
     // Remove the thread as a waiter from the lock owner.
     {
         KScopedSchedulerLock sl(kernel);
-        Thread* owner_thread = cur_thread->GetLockOwner();
+        KThread* owner_thread = cur_thread->GetLockOwner();
         if (owner_thread != nullptr) {
             owner_thread->RemoveWaiter(cur_thread);
         }
@@ -154,7 +154,7 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val
     return cur_thread->GetWaitResult(std::addressof(dummy));
 }
 
-Thread* KConditionVariable::SignalImpl(Thread* thread) {
+KThread* KConditionVariable::SignalImpl(KThread* thread) {
     // Check pre-conditions.
     ASSERT(kernel.GlobalSchedulerContext().IsLocked());
 
@@ -174,7 +174,7 @@ Thread* KConditionVariable::SignalImpl(Thread* thread) {
         }
     }
 
-    Thread* thread_to_close = nullptr;
+    KThread* thread_to_close = nullptr;
     if (can_access) {
         if (prev_tag == InvalidHandle) {
             // If nobody held the lock previously, we're all good.
@@ -182,7 +182,7 @@ Thread* KConditionVariable::SignalImpl(Thread* thread) {
             thread->Wakeup();
         } else {
             // Get the previous owner.
-            auto owner_thread = kernel.CurrentProcess()->GetHandleTable().Get<Thread>(
+            auto owner_thread = kernel.CurrentProcess()->GetHandleTable().Get<KThread>(
                 prev_tag & ~Svc::HandleWaitMask);
 
             if (owner_thread) {
@@ -210,8 +210,8 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {
 
     // TODO(bunnei): This should just be Thread once we implement KAutoObject instead of using
     // std::shared_ptr.
-    std::vector<std::shared_ptr<Thread>> thread_list;
-    std::array<Thread*, MaxThreads> thread_array;
+    std::vector<std::shared_ptr<KThread>> thread_list;
+    std::array<KThread*, MaxThreads> thread_array;
     s32 num_to_close{};
 
     // Perform signaling.
@@ -222,9 +222,9 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {
         auto it = thread_tree.nfind_light({cv_key, -1});
         while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
                (it->GetConditionVariableKey() == cv_key)) {
-            Thread* target_thread = std::addressof(*it);
+            KThread* target_thread = std::addressof(*it);
 
-            if (Thread* thread = SignalImpl(target_thread); thread != nullptr) {
+            if (KThread* thread = SignalImpl(target_thread); thread != nullptr) {
                 if (num_to_close < MaxThreads) {
                     thread_array[num_to_close++] = thread;
                 } else {
@@ -257,7 +257,7 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {
 
 ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) {
     // Prepare to wait.
-    Thread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread();
+    KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread();
     Handle timer = InvalidHandle;
 
     {
@@ -276,7 +276,7 @@ ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout)
         {
             // Remove waiter thread.
             s32 num_waiters{};
-            Thread* next_owner_thread =
+            KThread* next_owner_thread =
                 cur_thread->RemoveWaiterByKey(std::addressof(num_waiters), addr);
 
             // Update for the next owner thread.
@@ -331,7 +331,7 @@ ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout)
     {
         KScopedSchedulerLock sl(kernel);
 
-        if (Thread* owner = cur_thread->GetLockOwner(); owner != nullptr) {
+        if (KThread* owner = cur_thread->GetLockOwner(); owner != nullptr) {
             owner->RemoveWaiter(cur_thread);
         }
 
diff --git a/src/core/hle/kernel/k_condition_variable.h b/src/core/hle/kernel/k_condition_variable.h
index 98ed5b323..861dbd420 100644
--- a/src/core/hle/kernel/k_condition_variable.h
+++ b/src/core/hle/kernel/k_condition_variable.h
@@ -8,8 +8,8 @@
 #include "common/common_types.h"
 
 #include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/thread.h"
 #include "core/hle/result.h"
 
 namespace Core {
@@ -20,7 +20,7 @@ namespace Kernel {
 
 class KConditionVariable {
 public:
-    using ThreadTree = typename Thread::ConditionVariableThreadTreeType;
+    using ThreadTree = typename KThread::ConditionVariableThreadTreeType;
 
     explicit KConditionVariable(Core::System& system_);
     ~KConditionVariable();
@@ -34,7 +34,7 @@ public:
     [[nodiscard]] ResultCode Wait(VAddr addr, u64 key, u32 value, s64 timeout);
 
 private:
-    [[nodiscard]] Thread* SignalImpl(Thread* thread);
+    [[nodiscard]] KThread* SignalImpl(KThread* thread);
 
     ThreadTree thread_tree;
 
@@ -43,14 +43,14 @@ private:
 };
 
 inline void BeforeUpdatePriority(const KernelCore& kernel, KConditionVariable::ThreadTree* tree,
-                                 Thread* thread) {
+                                 KThread* thread) {
     ASSERT(kernel.GlobalSchedulerContext().IsLocked());
 
     tree->erase(tree->iterator_to(*thread));
 }
 
 inline void AfterUpdatePriority(const KernelCore& kernel, KConditionVariable::ThreadTree* tree,
-                                Thread* thread) {
+                                KThread* thread) {
     ASSERT(kernel.GlobalSchedulerContext().IsLocked());
 
     tree->insert(*thread);
diff --git a/src/core/hle/kernel/k_priority_queue.h b/src/core/hle/kernel/k_priority_queue.h
index 0dc929040..13d628b85 100644
--- a/src/core/hle/kernel/k_priority_queue.h
+++ b/src/core/hle/kernel/k_priority_queue.h
@@ -18,7 +18,7 @@
 
 namespace Kernel {
 
-class Thread;
+class KThread;
 
 template <typename T>
 concept KPriorityQueueAffinityMask = !std::is_reference_v<T> && requires(T & t) {
@@ -367,7 +367,7 @@ public:
         this->scheduled_queue.MoveToFront(member->GetPriority(), member->GetActiveCore(), member);
     }
 
-    constexpr Thread* MoveToScheduledBack(Member* member) {
+    constexpr KThread* MoveToScheduledBack(Member* member) {
         return this->scheduled_queue.MoveToBack(member->GetPriority(), member->GetActiveCore(),
                                                 member);
     }
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index 12b5619fb..0f7a541c8 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -17,15 +17,15 @@
 #include "core/cpu_manager.h"
 #include "core/hle/kernel/k_scheduler.h"
 #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/physical_core.h"
 #include "core/hle/kernel/process.h"
-#include "core/hle/kernel/thread.h"
 #include "core/hle/kernel/time_manager.h"
 
 namespace Kernel {
 
-static void IncrementScheduledCount(Kernel::Thread* thread) {
+static void IncrementScheduledCount(Kernel::KThread* thread) {
     if (auto process = thread->GetOwnerProcess(); process) {
         process->IncrementScheduledCount();
     }
@@ -56,9 +56,9 @@ void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedul
     }
 }
 
-u64 KScheduler::UpdateHighestPriorityThread(Thread* highest_thread) {
+u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) {
     std::scoped_lock lock{guard};
-    if (Thread* prev_highest_thread = this->state.highest_priority_thread;
+    if (KThread* prev_highest_thread = this->state.highest_priority_thread;
         prev_highest_thread != highest_thread) {
         if (prev_highest_thread != nullptr) {
             IncrementScheduledCount(prev_highest_thread);
@@ -90,13 +90,13 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) {
     ClearSchedulerUpdateNeeded(kernel);
 
     u64 cores_needing_scheduling = 0, idle_cores = 0;
-    Thread* top_threads[Core::Hardware::NUM_CPU_CORES];
+    KThread* top_threads[Core::Hardware::NUM_CPU_CORES];
     auto& priority_queue = GetPriorityQueue(kernel);
 
     /// We want to go over all cores, finding the highest priority thread and determining if
     /// scheduling is needed for that core.
     for (size_t core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
-        Thread* top_thread = priority_queue.GetScheduledFront(static_cast<s32>(core_id));
+        KThread* top_thread = priority_queue.GetScheduledFront(static_cast<s32>(core_id));
         if (top_thread != nullptr) {
             // If the thread has no waiters, we need to check if the process has a thread pinned.
             // TODO(bunnei): Implement thread pinning
@@ -112,7 +112,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) {
     // Idle cores are bad. We're going to try to migrate threads to each idle core in turn.
     while (idle_cores != 0) {
         const auto core_id = static_cast<u32>(std::countr_zero(idle_cores));
-        if (Thread* suggested = priority_queue.GetSuggestedFront(core_id); suggested != nullptr) {
+        if (KThread* suggested = priority_queue.GetSuggestedFront(core_id); suggested != nullptr) {
             s32 migration_candidates[Core::Hardware::NUM_CPU_CORES];
             size_t num_candidates = 0;
 
@@ -120,7 +120,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) {
             while (suggested != nullptr) {
                 // Check if the suggested thread is the top thread on its core.
                 const s32 suggested_core = suggested->GetActiveCore();
-                if (Thread* top_thread =
+                if (KThread* top_thread =
                         (suggested_core >= 0) ? top_threads[suggested_core] : nullptr;
                     top_thread != suggested) {
                     // Make sure we're not dealing with threads too high priority for migration.
@@ -152,7 +152,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) {
                     // Check if there's some other thread that can run on the candidate core.
                     const s32 candidate_core = migration_candidates[i];
                     suggested = top_threads[candidate_core];
-                    if (Thread* next_on_candidate_core =
+                    if (KThread* next_on_candidate_core =
                             priority_queue.GetScheduledNext(candidate_core, suggested);
                         next_on_candidate_core != nullptr) {
                         // The candidate core can run some other thread! We'll migrate its current
@@ -182,7 +182,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) {
     return cores_needing_scheduling;
 }
 
-void KScheduler::OnThreadStateChanged(KernelCore& kernel, Thread* thread, ThreadState old_state) {
+void KScheduler::OnThreadStateChanged(KernelCore& kernel, KThread* thread, ThreadState old_state) {
     ASSERT(kernel.GlobalSchedulerContext().IsLocked());
 
     // Check if the state has changed, because if it hasn't there's nothing to do.
@@ -205,7 +205,7 @@ void KScheduler::OnThreadStateChanged(KernelCore& kernel, Thread* thread, Thread
     }
 }
 
-void KScheduler::OnThreadPriorityChanged(KernelCore& kernel, Thread* thread, s32 old_priority) {
+void KScheduler::OnThreadPriorityChanged(KernelCore& kernel, KThread* thread, s32 old_priority) {
     ASSERT(kernel.GlobalSchedulerContext().IsLocked());
 
     // If the thread is runnable, we want to change its priority in the queue.
@@ -217,7 +217,7 @@ void KScheduler::OnThreadPriorityChanged(KernelCore& kernel, Thread* thread, s32
     }
 }
 
-void KScheduler::OnThreadAffinityMaskChanged(KernelCore& kernel, Thread* thread,
+void KScheduler::OnThreadAffinityMaskChanged(KernelCore& kernel, KThread* thread,
                                              const KAffinityMask& old_affinity, s32 old_core) {
     ASSERT(kernel.GlobalSchedulerContext().IsLocked());
 
@@ -237,8 +237,8 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) {
     auto& priority_queue = GetPriorityQueue(kernel);
 
     // Rotate the front of the queue to the end.
-    Thread* top_thread = priority_queue.GetScheduledFront(core_id, priority);
-    Thread* next_thread = nullptr;
+    KThread* top_thread = priority_queue.GetScheduledFront(core_id, priority);
+    KThread* next_thread = nullptr;
     if (top_thread != nullptr) {
         next_thread = priority_queue.MoveToScheduledBack(top_thread);
         if (next_thread != top_thread) {
@@ -249,11 +249,11 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) {
 
     // While we have a suggested thread, try to migrate it!
     {
-        Thread* suggested = priority_queue.GetSuggestedFront(core_id, priority);
+        KThread* suggested = priority_queue.GetSuggestedFront(core_id, priority);
         while (suggested != nullptr) {
             // Check if the suggested thread is the top thread on its core.
             const s32 suggested_core = suggested->GetActiveCore();
-            if (Thread* top_on_suggested_core =
+            if (KThread* top_on_suggested_core =
                     (suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core)
                                           : nullptr;
                 top_on_suggested_core != suggested) {
@@ -285,7 +285,7 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) {
     // Now that we might have migrated a thread with the same priority, check if we can do better.
 
     {
-        Thread* best_thread = priority_queue.GetScheduledFront(core_id);
+        KThread* best_thread = priority_queue.GetScheduledFront(core_id);
         if (best_thread == GetCurrentThread()) {
             best_thread = priority_queue.GetScheduledNext(core_id, best_thread);
         }
@@ -293,7 +293,7 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) {
         // If the best thread we can choose has a priority the same or worse than ours, try to
         // migrate a higher priority thread.
         if (best_thread != nullptr && best_thread->GetPriority() >= priority) {
-            Thread* suggested = priority_queue.GetSuggestedFront(core_id);
+            KThread* suggested = priority_queue.GetSuggestedFront(core_id);
             while (suggested != nullptr) {
                 // If the suggestion's priority is the same as ours, don't bother.
                 if (suggested->GetPriority() >= best_thread->GetPriority()) {
@@ -302,7 +302,7 @@ void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) {
 
                 // Check if the suggested thread is the top thread on its core.
                 const s32 suggested_core = suggested->GetActiveCore();
-                if (Thread* top_on_suggested_core =
+                if (KThread* top_on_suggested_core =
                         (suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core)
                                               : nullptr;
                     top_on_suggested_core != suggested) {
@@ -380,7 +380,7 @@ void KScheduler::YieldWithoutCoreMigration() {
     ASSERT(kernel.CurrentProcess() != nullptr);
 
     // Get the current thread and process.
-    Thread& cur_thread = *GetCurrentThread();
+    KThread& cur_thread = *GetCurrentThread();
     Process& cur_process = *kernel.CurrentProcess();
 
     // If the thread's yield count matches, there's nothing for us to do.
@@ -398,7 +398,7 @@ void KScheduler::YieldWithoutCoreMigration() {
         const auto cur_state = cur_thread.GetRawState();
         if (cur_state == ThreadState::Runnable) {
             // Put the current thread at the back of the queue.
-            Thread* next_thread = priority_queue.MoveToScheduledBack(std::addressof(cur_thread));
+            KThread* next_thread = priority_queue.MoveToScheduledBack(std::addressof(cur_thread));
             IncrementScheduledCount(std::addressof(cur_thread));
 
             // If the next thread is different, we have an update to perform.
@@ -421,7 +421,7 @@ void KScheduler::YieldWithCoreMigration() {
     ASSERT(kernel.CurrentProcess() != nullptr);
 
     // Get the current thread and process.
-    Thread& cur_thread = *GetCurrentThread();
+    KThread& cur_thread = *GetCurrentThread();
     Process& cur_process = *kernel.CurrentProcess();
 
     // If the thread's yield count matches, there's nothing for us to do.
@@ -442,17 +442,17 @@ void KScheduler::YieldWithCoreMigration() {
             const s32 core_id = cur_thread.GetActiveCore();
 
             // Put the current thread at the back of the queue.
-            Thread* next_thread = priority_queue.MoveToScheduledBack(std::addressof(cur_thread));
+            KThread* next_thread = priority_queue.MoveToScheduledBack(std::addressof(cur_thread));
             IncrementScheduledCount(std::addressof(cur_thread));
 
             // While we have a suggested thread, try to migrate it!
             bool recheck = false;
-            Thread* suggested = priority_queue.GetSuggestedFront(core_id);
+            KThread* suggested = priority_queue.GetSuggestedFront(core_id);
             while (suggested != nullptr) {
                 // Check if the suggested thread is the thread running on its core.
                 const s32 suggested_core = suggested->GetActiveCore();
 
-                if (Thread* running_on_suggested_core =
+                if (KThread* running_on_suggested_core =
                         (suggested_core >= 0)
                             ? kernel.Scheduler(suggested_core).state.highest_priority_thread
                             : nullptr;
@@ -511,7 +511,7 @@ void KScheduler::YieldToAnyThread() {
     ASSERT(kernel.CurrentProcess() != nullptr);
 
     // Get the current thread and process.
-    Thread& cur_thread = *GetCurrentThread();
+    KThread& cur_thread = *GetCurrentThread();
     Process& cur_process = *kernel.CurrentProcess();
 
     // If the thread's yield count matches, there's nothing for us to do.
@@ -539,11 +539,11 @@ void KScheduler::YieldToAnyThread() {
             // If there's nothing scheduled, we can try to perform a migration.
             if (priority_queue.GetScheduledFront(core_id) == nullptr) {
                 // While we have a suggested thread, try to migrate it!
-                Thread* suggested = priority_queue.GetSuggestedFront(core_id);
+                KThread* suggested = priority_queue.GetSuggestedFront(core_id);
                 while (suggested != nullptr) {
                     // Check if the suggested thread is the top thread on its core.
                     const s32 suggested_core = suggested->GetActiveCore();
-                    if (Thread* top_on_suggested_core =
+                    if (KThread* top_on_suggested_core =
                             (suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core)
                                                   : nullptr;
                         top_on_suggested_core != suggested) {
@@ -594,7 +594,7 @@ KScheduler::KScheduler(Core::System& system, std::size_t core_id)
 
 KScheduler::~KScheduler() = default;
 
-Thread* KScheduler::GetCurrentThread() const {
+KThread* KScheduler::GetCurrentThread() const {
     if (current_thread) {
         return current_thread;
     }
@@ -624,7 +624,7 @@ void KScheduler::OnThreadStart() {
     SwitchContextStep2();
 }
 
-void KScheduler::Unload(Thread* thread) {
+void KScheduler::Unload(KThread* thread) {
     if (thread) {
         thread->SetIsRunning(false);
         if (thread->IsContinuousOnSVC() && !thread->IsHLEThread()) {
@@ -643,7 +643,7 @@ void KScheduler::Unload(Thread* thread) {
     }
 }
 
-void KScheduler::Reload(Thread* thread) {
+void KScheduler::Reload(KThread* thread) {
     if (thread) {
         ASSERT_MSG(thread->GetState() == ThreadState::Runnable, "Thread must be runnable.");
 
@@ -674,7 +674,7 @@ void KScheduler::SwitchContextStep2() {
 }
 
 void KScheduler::ScheduleImpl() {
-    Thread* previous_thread = current_thread;
+    KThread* previous_thread = current_thread;
     current_thread = state.highest_priority_thread;
 
     this->state.needs_scheduling = false;
@@ -744,7 +744,7 @@ void KScheduler::SwitchToCurrent() {
     }
 }
 
-void KScheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) {
+void KScheduler::UpdateLastContextSwitchTime(KThread* thread, Process* process) {
     const u64 prev_switch_ticks = last_context_switch_time;
     const u64 most_recent_switch_ticks = system.CoreTiming().GetCPUTicks();
     const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks;
@@ -765,8 +765,8 @@ void KScheduler::Initialize() {
     std::function<void(void*)> init_func = Core::CpuManager::GetIdleThreadStartFunc();
     void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
     ThreadType type = static_cast<ThreadType>(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_IDLE);
-    auto thread_res = Thread::Create(system, type, name, 0, 64, 0, static_cast<u32>(core_id), 0,
-                                     nullptr, std::move(init_func), init_func_parameter);
+    auto thread_res = KThread::Create(system, type, name, 0, 64, 0, static_cast<u32>(core_id), 0,
+                                      nullptr, std::move(init_func), init_func_parameter);
     idle_thread = thread_res.Unwrap().get();
 
     {
diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h
index 783665123..157373934 100644
--- a/src/core/hle/kernel/k_scheduler.h
+++ b/src/core/hle/kernel/k_scheduler.h
@@ -29,7 +29,7 @@ namespace Kernel {
 class KernelCore;
 class Process;
 class SchedulerLock;
-class Thread;
+class KThread;
 
 class KScheduler final {
 public:
@@ -45,13 +45,13 @@ public:
 
     /// The next two are for SingleCore Only.
     /// Unload current thread before preempting core.
-    void Unload(Thread* thread);
+    void Unload(KThread* thread);
 
     /// Reload current thread after core preemption.
-    void Reload(Thread* thread);
+    void Reload(KThread* thread);
 
     /// Gets the current running thread
-    [[nodiscard]] Thread* GetCurrentThread() const;
+    [[nodiscard]] KThread* GetCurrentThread() const;
 
     /// Gets the timestamp for the last context switch in ticks.
     [[nodiscard]] u64 GetLastContextSwitchTicks() const;
@@ -72,7 +72,7 @@ public:
         return switch_fiber;
     }
 
-    [[nodiscard]] u64 UpdateHighestPriorityThread(Thread* highest_thread);
+    [[nodiscard]] u64 UpdateHighestPriorityThread(KThread* highest_thread);
 
     /**
      * Takes a thread and moves it to the back of the it's priority list.
@@ -100,13 +100,13 @@ public:
     void YieldToAnyThread();
 
     /// Notify the scheduler a thread's status has changed.
-    static void OnThreadStateChanged(KernelCore& kernel, Thread* thread, ThreadState old_state);
+    static void OnThreadStateChanged(KernelCore& kernel, KThread* thread, ThreadState old_state);
 
     /// Notify the scheduler a thread's priority has changed.
-    static void OnThreadPriorityChanged(KernelCore& kernel, Thread* thread, s32 old_priority);
+    static void OnThreadPriorityChanged(KernelCore& kernel, KThread* thread, s32 old_priority);
 
     /// Notify the scheduler a thread's core and/or affinity mask has changed.
-    static void OnThreadAffinityMaskChanged(KernelCore& kernel, Thread* thread,
+    static void OnThreadAffinityMaskChanged(KernelCore& kernel, KThread* thread,
                                             const KAffinityMask& old_affinity, s32 old_core);
 
     static bool CanSchedule(KernelCore& kernel);
@@ -163,13 +163,13 @@ private:
      * most recent tick count retrieved. No special arithmetic is
      * applied to it.
      */
-    void UpdateLastContextSwitchTime(Thread* thread, Process* process);
+    void UpdateLastContextSwitchTime(KThread* thread, Process* process);
 
     static void OnSwitch(void* this_scheduler);
     void SwitchToCurrent();
 
-    Thread* current_thread{};
-    Thread* idle_thread{};
+    KThread* current_thread{};
+    KThread* idle_thread{};
 
     std::shared_ptr<Common::Fiber> switch_fiber{};
 
@@ -178,7 +178,7 @@ private:
         bool interrupt_task_thread_runnable{};
         bool should_count_idle{};
         u64 idle_count{};
-        Thread* highest_priority_thread{};
+        KThread* highest_priority_thread{};
         void* idle_thread_stack{};
     };
 
diff --git a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h
index 2bb3817fa..fac39aeb7 100644
--- a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h
+++ b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h
@@ -9,15 +9,15 @@
 
 #include "common/common_types.h"
 #include "core/hle/kernel/handle_table.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/thread.h"
 #include "core/hle/kernel/time_manager.h"
 
 namespace Kernel {
 
 class KScopedSchedulerLockAndSleep {
 public:
-    explicit KScopedSchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, Thread* t,
+    explicit KScopedSchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, KThread* t,
                                           s64 timeout)
         : kernel(kernel), event_handle(event_handle), thread(t), timeout_tick(timeout) {
         event_handle = InvalidHandle;
@@ -43,7 +43,7 @@ public:
 private:
     KernelCore& kernel;
     Handle& event_handle;
-    Thread* thread{};
+    KThread* thread{};
     s64 timeout_tick{};
 };
 
diff --git a/src/core/hle/kernel/k_synchronization_object.cpp b/src/core/hle/kernel/k_synchronization_object.cpp
index 1c508cb55..61432fef8 100644
--- a/src/core/hle/kernel/k_synchronization_object.cpp
+++ b/src/core/hle/kernel/k_synchronization_object.cpp
@@ -7,9 +7,9 @@
 #include "core/hle/kernel/k_scheduler.h"
 #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
 #include "core/hle/kernel/k_synchronization_object.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/svc_results.h"
-#include "core/hle/kernel/thread.h"
 
 namespace Kernel {
 
@@ -20,7 +20,7 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index,
     std::vector<ThreadListNode> thread_nodes(num_objects);
 
     // Prepare for wait.
-    Thread* thread = kernel.CurrentScheduler()->GetCurrentThread();
+    KThread* thread = kernel.CurrentScheduler()->GetCurrentThread();
     Handle timer = InvalidHandle;
 
     {
@@ -148,7 +148,7 @@ void KSynchronizationObject::NotifyAvailable(ResultCode result) {
 
     // Iterate over each thread.
     for (auto* cur_node = thread_list_head; cur_node != nullptr; cur_node = cur_node->next) {
-        Thread* thread = cur_node->thread;
+        KThread* thread = cur_node->thread;
         if (thread->GetState() == ThreadState::Waiting) {
             thread->SetSyncedObject(this, result);
             thread->SetState(ThreadState::Runnable);
@@ -156,8 +156,8 @@ void KSynchronizationObject::NotifyAvailable(ResultCode result) {
     }
 }
 
-std::vector<Thread*> KSynchronizationObject::GetWaitingThreadsForDebugging() const {
-    std::vector<Thread*> threads;
+std::vector<KThread*> KSynchronizationObject::GetWaitingThreadsForDebugging() const {
+    std::vector<KThread*> threads;
 
     // If debugging, dump the list of waiters.
     {
diff --git a/src/core/hle/kernel/k_synchronization_object.h b/src/core/hle/kernel/k_synchronization_object.h
index 14d80ebf1..f65c71c28 100644
--- a/src/core/hle/kernel/k_synchronization_object.h
+++ b/src/core/hle/kernel/k_synchronization_object.h
@@ -13,14 +13,14 @@ namespace Kernel {
 
 class KernelCore;
 class Synchronization;
-class Thread;
+class KThread;
 
 /// Class that represents a Kernel object that a thread can be waiting on
 class KSynchronizationObject : public Object {
 public:
     struct ThreadListNode {
         ThreadListNode* next{};
-        Thread* thread{};
+        KThread* thread{};
     };
 
     [[nodiscard]] static ResultCode Wait(KernelCore& kernel, s32* out_index,
@@ -29,7 +29,7 @@ public:
 
     [[nodiscard]] virtual bool IsSignaled() const = 0;
 
-    [[nodiscard]] std::vector<Thread*> GetWaitingThreadsForDebugging() const;
+    [[nodiscard]] std::vector<KThread*> GetWaitingThreadsForDebugging() const;
 
 protected:
     explicit KSynchronizationObject(KernelCore& kernel);
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/k_thread.cpp
similarity index 85%
rename from src/core/hle/kernel/thread.cpp
rename to src/core/hle/kernel/k_thread.cpp
index d97323255..1ec29636c 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -20,11 +20,11 @@
 #include "core/hle/kernel/k_condition_variable.h"
 #include "core/hle/kernel/k_scheduler.h"
 #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/memory/memory_layout.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/process.h"
-#include "core/hle/kernel/thread.h"
 #include "core/hle/kernel/time_manager.h"
 #include "core/hle/result.h"
 #include "core/memory.h"
@@ -36,14 +36,14 @@
 
 namespace Kernel {
 
-bool Thread::IsSignaled() const {
+bool KThread::IsSignaled() const {
     return signaled;
 }
 
-Thread::Thread(KernelCore& kernel) : KSynchronizationObject{kernel} {}
-Thread::~Thread() = default;
+KThread::KThread(KernelCore& kernel) : KSynchronizationObject{kernel} {}
+KThread::~KThread() = default;
 
-void Thread::Stop() {
+void KThread::Stop() {
     {
         KScopedSchedulerLock lock(kernel);
         SetState(ThreadState::Terminated);
@@ -62,18 +62,18 @@ void Thread::Stop() {
     global_handle = 0;
 }
 
-void Thread::Wakeup() {
+void KThread::Wakeup() {
     KScopedSchedulerLock lock(kernel);
     SetState(ThreadState::Runnable);
 }
 
-ResultCode Thread::Start() {
+ResultCode KThread::Start() {
     KScopedSchedulerLock lock(kernel);
     SetState(ThreadState::Runnable);
     return RESULT_SUCCESS;
 }
 
-void Thread::CancelWait() {
+void KThread::CancelWait() {
     KScopedSchedulerLock lock(kernel);
     if (GetState() != ThreadState::Waiting || !is_cancellable) {
         is_sync_cancelled = true;
@@ -103,26 +103,26 @@ static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context,
     context.fpcr = 0;
 }
 
-std::shared_ptr<Common::Fiber>& Thread::GetHostContext() {
+std::shared_ptr<Common::Fiber>& KThread::GetHostContext() {
     return host_context;
 }
 
-ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadType type_flags,
-                                                  std::string name, VAddr entry_point, u32 priority,
-                                                  u64 arg, s32 processor_id, VAddr stack_top,
-                                                  Process* owner_process) {
+ResultVal<std::shared_ptr<KThread>> KThread::Create(Core::System& system, ThreadType type_flags,
+                                                    std::string name, VAddr entry_point,
+                                                    u32 priority, u64 arg, s32 processor_id,
+                                                    VAddr stack_top, Process* owner_process) {
     std::function<void(void*)> init_func = Core::CpuManager::GetGuestThreadStartFunc();
     void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
     return Create(system, type_flags, name, entry_point, priority, arg, processor_id, stack_top,
                   owner_process, std::move(init_func), init_func_parameter);
 }
 
-ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadType type_flags,
-                                                  std::string name, VAddr entry_point, u32 priority,
-                                                  u64 arg, s32 processor_id, VAddr stack_top,
-                                                  Process* owner_process,
-                                                  std::function<void(void*)>&& thread_start_func,
-                                                  void* thread_start_parameter) {
+ResultVal<std::shared_ptr<KThread>> KThread::Create(Core::System& system, ThreadType type_flags,
+                                                    std::string name, VAddr entry_point,
+                                                    u32 priority, u64 arg, s32 processor_id,
+                                                    VAddr stack_top, Process* owner_process,
+                                                    std::function<void(void*)>&& thread_start_func,
+                                                    void* thread_start_parameter) {
     auto& kernel = system.Kernel();
     // Check if priority is in ranged. Lowest priority -> highest priority id.
     if (priority > THREADPRIO_LOWEST && ((type_flags & THREADTYPE_IDLE) == 0)) {
@@ -143,7 +143,7 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy
         }
     }
 
-    std::shared_ptr<Thread> thread = std::make_shared<Thread>(kernel);
+    std::shared_ptr<KThread> thread = std::make_shared<KThread>(kernel);
 
     thread->thread_id = kernel.CreateNewThreadID();
     thread->thread_state = ThreadState::Initialized;
@@ -185,10 +185,10 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy
     thread->host_context =
         std::make_shared<Common::Fiber>(std::move(thread_start_func), thread_start_parameter);
 
-    return MakeResult<std::shared_ptr<Thread>>(std::move(thread));
+    return MakeResult<std::shared_ptr<KThread>>(std::move(thread));
 }
 
-void Thread::SetBasePriority(u32 priority) {
+void KThread::SetBasePriority(u32 priority) {
     ASSERT_MSG(priority <= THREADPRIO_LOWEST && priority >= THREADPRIO_HIGHEST,
                "Invalid priority value.");
 
@@ -201,18 +201,18 @@ void Thread::SetBasePriority(u32 priority) {
     RestorePriority(kernel, this);
 }
 
-void Thread::SetSynchronizationResults(KSynchronizationObject* object, ResultCode result) {
+void KThread::SetSynchronizationResults(KSynchronizationObject* object, ResultCode result) {
     signaling_object = object;
     signaling_result = result;
 }
 
-VAddr Thread::GetCommandBufferAddress() const {
+VAddr KThread::GetCommandBufferAddress() const {
     // Offset from the start of TLS at which the IPC command buffer begins.
     constexpr u64 command_header_offset = 0x80;
     return GetTLSAddress() + command_header_offset;
 }
 
-void Thread::SetState(ThreadState state) {
+void KThread::SetState(ThreadState state) {
     KScopedSchedulerLock sl(kernel);
 
     // Clear debugging state
@@ -227,7 +227,7 @@ void Thread::SetState(ThreadState state) {
     }
 }
 
-void Thread::AddWaiterImpl(Thread* thread) {
+void KThread::AddWaiterImpl(KThread* thread) {
     ASSERT(kernel.GlobalSchedulerContext().IsLocked());
 
     // Find the right spot to insert the waiter.
@@ -249,7 +249,7 @@ void Thread::AddWaiterImpl(Thread* thread) {
     thread->SetLockOwner(this);
 }
 
-void Thread::RemoveWaiterImpl(Thread* thread) {
+void KThread::RemoveWaiterImpl(KThread* thread) {
     ASSERT(kernel.GlobalSchedulerContext().IsLocked());
 
     // Keep track of how many kernel waiters we have.
@@ -262,7 +262,7 @@ void Thread::RemoveWaiterImpl(Thread* thread) {
     thread->SetLockOwner(nullptr);
 }
 
-void Thread::RestorePriority(KernelCore& kernel, Thread* thread) {
+void KThread::RestorePriority(KernelCore& kernel, KThread* thread) {
     ASSERT(kernel.GlobalSchedulerContext().IsLocked());
 
     while (true) {
@@ -295,7 +295,7 @@ void Thread::RestorePriority(KernelCore& kernel, Thread* thread) {
         KScheduler::OnThreadPriorityChanged(kernel, thread, old_priority);
 
         // Keep the lock owner up to date.
-        Thread* lock_owner = thread->GetLockOwner();
+        KThread* lock_owner = thread->GetLockOwner();
         if (lock_owner == nullptr) {
             return;
         }
@@ -307,25 +307,25 @@ void Thread::RestorePriority(KernelCore& kernel, Thread* thread) {
     }
 }
 
-void Thread::AddWaiter(Thread* thread) {
+void KThread::AddWaiter(KThread* thread) {
     AddWaiterImpl(thread);
     RestorePriority(kernel, this);
 }
 
-void Thread::RemoveWaiter(Thread* thread) {
+void KThread::RemoveWaiter(KThread* thread) {
     RemoveWaiterImpl(thread);
     RestorePriority(kernel, this);
 }
 
-Thread* Thread::RemoveWaiterByKey(s32* out_num_waiters, VAddr key) {
+KThread* KThread::RemoveWaiterByKey(s32* out_num_waiters, VAddr key) {
     ASSERT(kernel.GlobalSchedulerContext().IsLocked());
 
     s32 num_waiters{};
-    Thread* next_lock_owner{};
+    KThread* next_lock_owner{};
     auto it = waiter_list.begin();
     while (it != waiter_list.end()) {
         if (it->GetAddressKey() == key) {
-            Thread* thread = std::addressof(*it);
+            KThread* thread = std::addressof(*it);
 
             // Keep track of how many kernel waiters we have.
             if (Memory::IsKernelAddressKey(thread->GetAddressKey())) {
@@ -357,7 +357,7 @@ Thread* Thread::RemoveWaiterByKey(s32* out_num_waiters, VAddr key) {
     return next_lock_owner;
 }
 
-ResultCode Thread::SetActivity(ThreadActivity value) {
+ResultCode KThread::SetActivity(ThreadActivity value) {
     KScopedSchedulerLock lock(kernel);
 
     auto sched_status = GetState();
@@ -384,7 +384,7 @@ ResultCode Thread::SetActivity(ThreadActivity value) {
     return RESULT_SUCCESS;
 }
 
-ResultCode Thread::Sleep(s64 nanoseconds) {
+ResultCode KThread::Sleep(s64 nanoseconds) {
     Handle event_handle{};
     {
         KScopedSchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds);
@@ -399,7 +399,7 @@ ResultCode Thread::Sleep(s64 nanoseconds) {
     return RESULT_SUCCESS;
 }
 
-void Thread::AddSchedulingFlag(ThreadSchedFlags flag) {
+void KThread::AddSchedulingFlag(ThreadSchedFlags flag) {
     const auto old_state = GetRawState();
     pausing_state |= static_cast<u32>(flag);
     const auto base_scheduling = GetState();
@@ -407,7 +407,7 @@ void Thread::AddSchedulingFlag(ThreadSchedFlags flag) {
     KScheduler::OnThreadStateChanged(kernel, this, old_state);
 }
 
-void Thread::RemoveSchedulingFlag(ThreadSchedFlags flag) {
+void KThread::RemoveSchedulingFlag(ThreadSchedFlags flag) {
     const auto old_state = GetRawState();
     pausing_state &= ~static_cast<u32>(flag);
     const auto base_scheduling = GetState();
@@ -415,7 +415,7 @@ void Thread::RemoveSchedulingFlag(ThreadSchedFlags flag) {
     KScheduler::OnThreadStateChanged(kernel, this, old_state);
 }
 
-ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) {
+ResultCode KThread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) {
     KScopedSchedulerLock lock(kernel);
     const auto HighestSetCore = [](u64 mask, u32 max_cores) {
         for (s32 core = static_cast<s32>(max_cores - 1); core >= 0; core--) {
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/k_thread.h
similarity index 91%
rename from src/core/hle/kernel/thread.h
rename to src/core/hle/kernel/k_thread.h
index 6b66c9a0e..75257d2b4 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -124,15 +124,15 @@ enum class ThreadWaitReasonForDebugging : u32 {
     Suspended,       ///< Thread is waiting due to process suspension
 };
 
-class Thread final : public KSynchronizationObject, public boost::intrusive::list_base_hook<> {
+class KThread final : public KSynchronizationObject, public boost::intrusive::list_base_hook<> {
     friend class KScheduler;
     friend class Process;
 
 public:
-    explicit Thread(KernelCore& kernel);
-    ~Thread() override;
+    explicit KThread(KernelCore& kernel);
+    ~KThread() override;
 
-    using MutexWaitingThreads = std::vector<std::shared_ptr<Thread>>;
+    using MutexWaitingThreads = std::vector<std::shared_ptr<KThread>>;
 
     using ThreadContext32 = Core::ARM_Interface::ThreadContext32;
     using ThreadContext64 = Core::ARM_Interface::ThreadContext64;
@@ -149,10 +149,10 @@ public:
      * @param owner_process The parent process for the thread, if null, it's a kernel thread
      * @return A shared pointer to the newly created thread
      */
-    static ResultVal<std::shared_ptr<Thread>> Create(Core::System& system, ThreadType type_flags,
-                                                     std::string name, VAddr entry_point,
-                                                     u32 priority, u64 arg, s32 processor_id,
-                                                     VAddr stack_top, Process* owner_process);
+    static ResultVal<std::shared_ptr<KThread>> Create(Core::System& system, ThreadType type_flags,
+                                                      std::string name, VAddr entry_point,
+                                                      u32 priority, u64 arg, s32 processor_id,
+                                                      VAddr stack_top, Process* owner_process);
 
     /**
      * Creates and returns a new thread. The new thread is immediately scheduled
@@ -168,12 +168,10 @@ public:
      * @param thread_start_parameter The parameter which will passed to host context on init
      * @return A shared pointer to the newly created thread
      */
-    static ResultVal<std::shared_ptr<Thread>> Create(Core::System& system, ThreadType type_flags,
-                                                     std::string name, VAddr entry_point,
-                                                     u32 priority, u64 arg, s32 processor_id,
-                                                     VAddr stack_top, Process* owner_process,
-                                                     std::function<void(void*)>&& thread_start_func,
-                                                     void* thread_start_parameter);
+    static ResultVal<std::shared_ptr<KThread>> Create(
+        Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point,
+        u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process,
+        std::function<void(void*)>&& thread_start_func, void* thread_start_parameter);
 
     std::string GetName() const override {
         return name;
@@ -387,11 +385,11 @@ public:
         return wait_mutex_threads;
     }
 
-    Thread* GetLockOwner() const {
+    KThread* GetLockOwner() const {
         return lock_owner;
     }
 
-    void SetLockOwner(Thread* owner) {
+    void SetLockOwner(KThread* owner) {
         lock_owner = owner;
     }
 
@@ -485,22 +483,22 @@ public:
             next = nullptr;
         }
 
-        constexpr Thread* GetPrev() const {
+        constexpr KThread* GetPrev() const {
             return prev;
         }
-        constexpr Thread* GetNext() const {
+        constexpr KThread* GetNext() const {
             return next;
         }
-        constexpr void SetPrev(Thread* thread) {
+        constexpr void SetPrev(KThread* thread) {
             prev = thread;
         }
-        constexpr void SetNext(Thread* thread) {
+        constexpr void SetNext(KThread* thread) {
             next = thread;
         }
 
     private:
-        Thread* prev{};
-        Thread* next{};
+        KThread* prev{};
+        KThread* next{};
     };
 
     QueueEntry& GetPriorityQueueEntry(s32 core) {
@@ -553,11 +551,11 @@ public:
         return mutex_wait_address_for_debugging;
     }
 
-    void AddWaiter(Thread* thread);
+    void AddWaiter(KThread* thread);
 
-    void RemoveWaiter(Thread* thread);
+    void RemoveWaiter(KThread* thread);
 
-    [[nodiscard]] Thread* RemoveWaiterByKey(s32* out_num_waiters, VAddr key);
+    [[nodiscard]] KThread* RemoveWaiterByKey(s32* out_num_waiters, VAddr key);
 
     [[nodiscard]] VAddr GetAddressKey() const {
         return address_key;
@@ -603,9 +601,9 @@ private:
 
         template <typename T>
         requires(
-            std::same_as<T, Thread> ||
+            std::same_as<T, KThread> ||
             std::same_as<T, LightCompareType>) static constexpr int Compare(const T& lhs,
-                                                                            const Thread& rhs) {
+                                                                            const KThread& rhs) {
             const uintptr_t l_key = lhs.GetConditionVariableKey();
             const uintptr_t r_key = rhs.GetConditionVariableKey();
 
@@ -624,7 +622,8 @@ private:
     Common::IntrusiveRedBlackTreeNode condvar_arbiter_tree_node{};
 
     using ConditionVariableThreadTreeTraits =
-        Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&Thread::condvar_arbiter_tree_node>;
+        Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<
+            &KThread::condvar_arbiter_tree_node>;
     using ConditionVariableThreadTree =
         ConditionVariableThreadTreeTraits::TreeType<ConditionVariableComparator>;
 
@@ -679,9 +678,9 @@ public:
 private:
     void AddSchedulingFlag(ThreadSchedFlags flag);
     void RemoveSchedulingFlag(ThreadSchedFlags flag);
-    void AddWaiterImpl(Thread* thread);
-    void RemoveWaiterImpl(Thread* thread);
-    static void RestorePriority(KernelCore& kernel, Thread* thread);
+    void AddWaiterImpl(KThread* thread);
+    void RemoveWaiterImpl(KThread* thread);
+    static void RestorePriority(KernelCore& kernel, KThread* thread);
 
     Common::SpinLock context_guard{};
     ThreadContext32 context_32{};
@@ -736,7 +735,7 @@ private:
     MutexWaitingThreads wait_mutex_threads;
 
     /// Thread that owns the lock that this thread is waiting for.
-    Thread* lock_owner{};
+    KThread* lock_owner{};
 
     /// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
     Handle global_handle = 0;
@@ -772,7 +771,7 @@ private:
     u32 address_key_value{};
     s32 num_kernel_waiters{};
 
-    using WaiterList = boost::intrusive::list<Thread>;
+    using WaiterList = boost::intrusive::list<KThread>;
     WaiterList waiter_list{};
     WaiterList pinned_waiter_list{};
 
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index c0ff287a6..523dd63a5 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -29,6 +29,7 @@
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/handle_table.h"
 #include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/memory/memory_layout.h"
 #include "core/hle/kernel/memory/memory_manager.h"
@@ -38,7 +39,6 @@
 #include "core/hle/kernel/resource_limit.h"
 #include "core/hle/kernel/service_thread.h"
 #include "core/hle/kernel/shared_memory.h"
-#include "core/hle/kernel/thread.h"
 #include "core/hle/kernel/time_manager.h"
 #include "core/hle/lock.h"
 #include "core/hle/result.h"
@@ -171,8 +171,8 @@ struct KernelCore::Impl {
             const auto type =
                 static_cast<ThreadType>(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_SUSPEND);
             auto thread_res =
-                Thread::Create(system, type, std::move(name), 0, 0, 0, static_cast<u32>(i), 0,
-                               nullptr, std::move(init_func), init_func_parameter);
+                KThread::Create(system, type, std::move(name), 0, 0, 0, static_cast<u32>(i), 0,
+                                nullptr, std::move(init_func), init_func_parameter);
 
             suspend_threads[i] = std::move(thread_res).Unwrap();
         }
@@ -236,7 +236,7 @@ struct KernelCore::Impl {
             return result;
         }
         const Kernel::KScheduler& sched = cores[result.host_handle].Scheduler();
-        const Kernel::Thread* current = sched.GetCurrentThread();
+        const Kernel::KThread* current = sched.GetCurrentThread();
         if (current != nullptr && !current->IsPhantomMode()) {
             result.guest_handle = current->GetGlobalHandle();
         } else {
@@ -342,7 +342,7 @@ struct KernelCore::Impl {
     // the release of itself
     std::unique_ptr<Common::ThreadWorker> service_thread_manager;
 
-    std::array<std::shared_ptr<Thread>, Core::Hardware::NUM_CPU_CORES> suspend_threads{};
+    std::array<std::shared_ptr<KThread>, Core::Hardware::NUM_CPU_CORES> suspend_threads{};
     std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
     std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
 
@@ -380,8 +380,8 @@ std::shared_ptr<ResourceLimit> KernelCore::GetSystemResourceLimit() const {
     return impl->system_resource_limit;
 }
 
-std::shared_ptr<Thread> KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const {
-    return impl->global_handle_table.Get<Thread>(handle);
+std::shared_ptr<KThread> KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const {
+    return impl->global_handle_table.Get<KThread>(handle);
 }
 
 void KernelCore::AppendNewProcess(std::shared_ptr<Process> process) {
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 933d9a7d6..41c553582 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -43,7 +43,7 @@ class KScheduler;
 class SharedMemory;
 class ServiceThread;
 class Synchronization;
-class Thread;
+class KThread;
 class TimeManager;
 
 /// Represents a single instance of the kernel.
@@ -84,7 +84,7 @@ public:
     std::shared_ptr<ResourceLimit> GetSystemResourceLimit() const;
 
     /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table.
-    std::shared_ptr<Thread> RetrieveThreadFromGlobalHandleTable(Handle handle) const;
+    std::shared_ptr<KThread> RetrieveThreadFromGlobalHandleTable(Handle handle) const;
 
     /// Adds the given shared pointer to an internal list of active processes.
     void AppendNewProcess(std::shared_ptr<Process> process);
@@ -240,7 +240,7 @@ public:
 private:
     friend class Object;
     friend class Process;
-    friend class Thread;
+    friend class KThread;
 
     /// Creates a new object ID, incrementing the internal object ID counter.
     u32 CreateNewObjectID();
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 37b77fa6e..ccd371aba 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -16,13 +16,13 @@
 #include "core/hle/kernel/code_set.h"
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/memory/memory_block_manager.h"
 #include "core/hle/kernel/memory/page_table.h"
 #include "core/hle/kernel/memory/slab_heap.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/resource_limit.h"
-#include "core/hle/kernel/thread.h"
 #include "core/hle/lock.h"
 #include "core/memory.h"
 #include "core/settings.h"
@@ -39,10 +39,10 @@ namespace {
 void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) {
     const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart();
     ThreadType type = THREADTYPE_USER;
-    auto thread_res = Thread::Create(system, type, "main", entry_point, priority, 0,
-                                     owner_process.GetIdealCore(), stack_top, &owner_process);
+    auto thread_res = KThread::Create(system, type, "main", entry_point, priority, 0,
+                                      owner_process.GetIdealCore(), stack_top, &owner_process);
 
-    std::shared_ptr<Thread> thread = std::move(thread_res).Unwrap();
+    std::shared_ptr<KThread> thread = std::move(thread_res).Unwrap();
 
     // Register 1 must be a handle to the main thread
     const Handle thread_handle = owner_process.GetHandleTable().Create(thread).Unwrap();
@@ -162,11 +162,11 @@ u64 Process::GetTotalPhysicalMemoryUsedWithoutSystemResource() const {
     return GetTotalPhysicalMemoryUsed() - GetSystemResourceUsage();
 }
 
-void Process::RegisterThread(const Thread* thread) {
+void Process::RegisterThread(const KThread* thread) {
     thread_list.push_back(thread);
 }
 
-void Process::UnregisterThread(const Thread* thread) {
+void Process::UnregisterThread(const KThread* thread) {
     thread_list.remove(thread);
 }
 
@@ -267,7 +267,7 @@ void Process::Run(s32 main_thread_priority, u64 stack_size) {
 void Process::PrepareForTermination() {
     ChangeStatus(ProcessStatus::Exiting);
 
-    const auto stop_threads = [this](const std::vector<std::shared_ptr<Thread>>& thread_list) {
+    const auto stop_threads = [this](const std::vector<std::shared_ptr<KThread>>& thread_list) {
         for (auto& thread : thread_list) {
             if (thread->GetOwnerProcess() != this)
                 continue;
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 564e1f27d..db01d6c8a 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -30,7 +30,7 @@ namespace Kernel {
 
 class KernelCore;
 class ResourceLimit;
-class Thread;
+class KThread;
 class TLSPage;
 
 struct CodeSet;
@@ -252,17 +252,17 @@ public:
     u64 GetTotalPhysicalMemoryUsedWithoutSystemResource() const;
 
     /// Gets the list of all threads created with this process as their owner.
-    const std::list<const Thread*>& GetThreadList() const {
+    const std::list<const KThread*>& GetThreadList() const {
         return thread_list;
     }
 
     /// Registers a thread as being created under this process,
     /// adding it to this process' thread list.
-    void RegisterThread(const Thread* thread);
+    void RegisterThread(const KThread* thread);
 
     /// Unregisters a thread from this process, removing it
     /// from this process' thread list.
-    void UnregisterThread(const Thread* thread);
+    void UnregisterThread(const KThread* thread);
 
     /// Clears the signaled state of the process if and only if it's signaled.
     ///
@@ -380,7 +380,7 @@ private:
     std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy{};
 
     /// List of threads that are running with this process as their owner.
-    std::list<const Thread*> thread_list;
+    std::list<const KThread*> thread_list;
 
     /// Address of the top of the main thread's stack
     VAddr main_thread_stack_top{};
diff --git a/src/core/hle/kernel/readable_event.cpp b/src/core/hle/kernel/readable_event.cpp
index 99ed0857e..596d01479 100644
--- a/src/core/hle/kernel/readable_event.cpp
+++ b/src/core/hle/kernel/readable_event.cpp
@@ -7,10 +7,10 @@
 #include "common/logging/log.h"
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/readable_event.h"
-#include "core/hle/kernel/thread.h"
 
 namespace Kernel {
 
diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp
index 82857f93b..fe7a483c4 100644
--- a/src/core/hle/kernel/server_port.cpp
+++ b/src/core/hle/kernel/server_port.cpp
@@ -6,10 +6,10 @@
 #include "common/assert.h"
 #include "core/hle/kernel/client_port.h"
 #include "core/hle/kernel/errors.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/server_port.h"
 #include "core/hle/kernel/server_session.h"
-#include "core/hle/kernel/thread.h"
 
 namespace Kernel {
 
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 4f2bb7822..280c9b5f6 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -15,11 +15,11 @@
 #include "core/hle/kernel/handle_table.h"
 #include "core/hle/kernel/hle_ipc.h"
 #include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/server_session.h"
 #include "core/hle/kernel/session.h"
-#include "core/hle/kernel/thread.h"
 #include "core/memory.h"
 
 namespace Kernel {
@@ -116,7 +116,7 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con
     return RESULT_SUCCESS;
 }
 
-ResultCode ServerSession::QueueSyncRequest(std::shared_ptr<Thread> thread,
+ResultCode ServerSession::QueueSyncRequest(std::shared_ptr<KThread> thread,
                                            Core::Memory::Memory& memory) {
     u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(thread->GetTLSAddress()))};
     auto context =
@@ -161,7 +161,7 @@ ResultCode ServerSession::CompleteSyncRequest(HLERequestContext& context) {
     return result;
 }
 
-ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread,
+ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<KThread> thread,
                                             Core::Memory::Memory& memory,
                                             Core::Timing::CoreTiming& core_timing) {
     return QueueSyncRequest(std::move(thread), memory);
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index 9155cf7f5..d45cddec3 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -29,7 +29,7 @@ class HLERequestContext;
 class KernelCore;
 class Session;
 class SessionRequestHandler;
-class Thread;
+class KThread;
 
 /**
  * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS
@@ -95,7 +95,7 @@ public:
      *
      * @returns ResultCode from the operation.
      */
-    ResultCode HandleSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory,
+    ResultCode HandleSyncRequest(std::shared_ptr<KThread> thread, Core::Memory::Memory& memory,
                                  Core::Timing::CoreTiming& core_timing);
 
     /// Called when a client disconnection occurs.
@@ -128,7 +128,7 @@ public:
 
 private:
     /// Queues a sync request from the emulated application.
-    ResultCode QueueSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory);
+    ResultCode QueueSyncRequest(std::shared_ptr<KThread> thread, Core::Memory::Memory& memory);
 
     /// Completes a sync request from the emulated application.
     ResultCode CompleteSyncRequest(HLERequestContext& context);
@@ -149,12 +149,12 @@ private:
     /// List of threads that are pending a response after a sync request. This list is processed in
     /// a LIFO manner, thus, the last request will be dispatched first.
     /// TODO(Subv): Verify if this is indeed processed in LIFO using a hardware test.
-    std::vector<std::shared_ptr<Thread>> pending_requesting_threads;
+    std::vector<std::shared_ptr<KThread>> pending_requesting_threads;
 
     /// Thread whose request is currently being handled. A request is considered "handled" when a
     /// response is sent via svcReplyAndReceive.
     /// TODO(Subv): Find a better name for this.
-    std::shared_ptr<Thread> currently_handling;
+    std::shared_ptr<KThread> currently_handling;
 
     /// When set to True, converts the session to a domain at the end of the command
     bool convert_to_domain{};
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index cc8b661af..3609346d6 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -29,6 +29,7 @@
 #include "core/hle/kernel/k_scheduler.h"
 #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
 #include "core/hle/kernel/k_synchronization_object.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/memory/memory_block.h"
 #include "core/hle/kernel/memory/memory_layout.h"
@@ -42,7 +43,6 @@
 #include "core/hle/kernel/svc_results.h"
 #include "core/hle/kernel/svc_types.h"
 #include "core/hle/kernel/svc_wrap.h"
-#include "core/hle/kernel/thread.h"
 #include "core/hle/kernel/time_manager.h"
 #include "core/hle/kernel/transfer_memory.h"
 #include "core/hle/kernel/writable_event.h"
@@ -363,7 +363,7 @@ static ResultCode GetThreadId(Core::System& system, u64* thread_id, Handle threa
     LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
 
     const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
-    const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle);
+    const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
     if (!thread) {
         LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", thread_handle);
         return ERR_INVALID_HANDLE;
@@ -395,7 +395,7 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han
         return RESULT_SUCCESS;
     }
 
-    const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(handle);
+    const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle);
     if (thread) {
         const Process* const owner_process = thread->GetOwnerProcess();
         if (!owner_process) {
@@ -474,7 +474,7 @@ static ResultCode CancelSynchronization(Core::System& system, Handle thread_hand
     LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle);
 
     const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
-    std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle);
+    std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
     if (!thread) {
         LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
                   thread_handle);
@@ -872,7 +872,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
             return ERR_INVALID_COMBINATION;
         }
 
-        const auto thread = system.Kernel().CurrentProcess()->GetHandleTable().Get<Thread>(
+        const auto thread = system.Kernel().CurrentProcess()->GetHandleTable().Get<KThread>(
             static_cast<Handle>(handle));
         if (!thread) {
             LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}",
@@ -1033,7 +1033,7 @@ static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 act
     }
 
     const auto* current_process = system.Kernel().CurrentProcess();
-    const std::shared_ptr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
+    const std::shared_ptr<KThread> thread = current_process->GetHandleTable().Get<KThread>(handle);
     if (!thread) {
         LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
         return ERR_INVALID_HANDLE;
@@ -1066,7 +1066,7 @@ static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, H
     LOG_DEBUG(Kernel_SVC, "called, context=0x{:08X}, thread=0x{:X}", thread_context, handle);
 
     const auto* current_process = system.Kernel().CurrentProcess();
-    const std::shared_ptr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
+    const std::shared_ptr<KThread> thread = current_process->GetHandleTable().Get<KThread>(handle);
     if (!thread) {
         LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
         return ERR_INVALID_HANDLE;
@@ -1111,7 +1111,7 @@ static ResultCode GetThreadPriority(Core::System& system, u32* priority, Handle
     LOG_TRACE(Kernel_SVC, "called");
 
     const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
-    const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(handle);
+    const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle);
     if (!thread) {
         *priority = 0;
         LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
@@ -1140,7 +1140,7 @@ static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 pri
 
     const auto* const current_process = system.Kernel().CurrentProcess();
 
-    std::shared_ptr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
+    std::shared_ptr<KThread> thread = current_process->GetHandleTable().Get<KThread>(handle);
     if (!thread) {
         LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
         return ERR_INVALID_HANDLE;
@@ -1489,9 +1489,9 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
     ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(ResourceType::Threads, 1));
 
     ThreadType type = THREADTYPE_USER;
-    CASCADE_RESULT(std::shared_ptr<Thread> thread,
-                   Thread::Create(system, type, "", entry_point, priority, arg, processor_id,
-                                  stack_top, current_process));
+    CASCADE_RESULT(std::shared_ptr<KThread> thread,
+                   KThread::Create(system, type, "", entry_point, priority, arg, processor_id,
+                                   stack_top, current_process));
 
     const auto new_thread_handle = current_process->GetHandleTable().Create(thread);
     if (new_thread_handle.Failed()) {
@@ -1518,7 +1518,7 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) {
     LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
 
     const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
-    const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle);
+    const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
     if (!thread) {
         LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
                   thread_handle);
@@ -1844,7 +1844,7 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle,
     LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle);
 
     const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
-    const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle);
+    const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
     if (!thread) {
         LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
                   thread_handle);
@@ -1914,7 +1914,7 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle,
     }
 
     const auto& handle_table = current_process->GetHandleTable();
-    const std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle);
+    const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
     if (!thread) {
         LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
                   thread_handle);
diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp
index 832edd629..aaeef3033 100644
--- a/src/core/hle/kernel/time_manager.cpp
+++ b/src/core/hle/kernel/time_manager.cpp
@@ -8,8 +8,8 @@
 #include "core/core_timing_util.h"
 #include "core/hle/kernel/handle_table.h"
 #include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/thread.h"
 #include "core/hle/kernel/time_manager.h"
 
 namespace Kernel {
@@ -18,7 +18,7 @@ TimeManager::TimeManager(Core::System& system_) : system{system_} {
     time_manager_event_type = Core::Timing::CreateEvent(
         "Kernel::TimeManagerCallback",
         [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) {
-            std::shared_ptr<Thread> thread;
+            std::shared_ptr<KThread> thread;
             {
                 std::lock_guard lock{mutex};
                 const auto proper_handle = static_cast<Handle>(thread_handle);
@@ -35,7 +35,7 @@ TimeManager::TimeManager(Core::System& system_) : system{system_} {
         });
 }
 
-void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds) {
+void TimeManager::ScheduleTimeEvent(Handle& event_handle, KThread* timetask, s64 nanoseconds) {
     std::lock_guard lock{mutex};
     event_handle = timetask->GetGlobalHandle();
     if (nanoseconds > 0) {
@@ -58,7 +58,7 @@ void TimeManager::UnscheduleTimeEvent(Handle event_handle) {
     cancelled_events[event_handle] = true;
 }
 
-void TimeManager::CancelTimeEvent(Thread* time_task) {
+void TimeManager::CancelTimeEvent(KThread* time_task) {
     std::lock_guard lock{mutex};
     const Handle event_handle = time_task->GetGlobalHandle();
     UnscheduleTimeEvent(event_handle);
diff --git a/src/core/hle/kernel/time_manager.h b/src/core/hle/kernel/time_manager.h
index f39df39a0..7cc702bec 100644
--- a/src/core/hle/kernel/time_manager.h
+++ b/src/core/hle/kernel/time_manager.h
@@ -20,7 +20,7 @@ struct EventType;
 
 namespace Kernel {
 
-class Thread;
+class KThread;
 
 /**
  * The `TimeManager` takes care of scheduling time events on threads and executes their TimeUp
@@ -32,12 +32,12 @@ public:
 
     /// Schedule a time event on `timetask` thread that will expire in 'nanoseconds'
     /// returns a non-invalid handle in `event_handle` if correctly scheduled
-    void ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds);
+    void ScheduleTimeEvent(Handle& event_handle, KThread* timetask, s64 nanoseconds);
 
     /// Unschedule an existing time event
     void UnscheduleTimeEvent(Handle event_handle);
 
-    void CancelTimeEvent(Thread* time_task);
+    void CancelTimeEvent(KThread* time_task);
 
 private:
     Core::System& system;
diff --git a/src/core/hle/kernel/writable_event.cpp b/src/core/hle/kernel/writable_event.cpp
index fc2f7c424..dbe34472b 100644
--- a/src/core/hle/kernel/writable_event.cpp
+++ b/src/core/hle/kernel/writable_event.cpp
@@ -4,10 +4,10 @@
 
 #include <algorithm>
 #include "common/assert.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/readable_event.h"
-#include "core/hle/kernel/thread.h"
 #include "core/hle/kernel/writable_event.h"
 
 namespace Kernel {
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index 641bcadea..a515fdc60 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -8,9 +8,9 @@
 #include "common/logging/log.h"
 #include "core/core.h"
 #include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/readable_event.h"
-#include "core/hle/kernel/thread.h"
 #include "core/hle/kernel/writable_event.h"
 #include "core/hle/lock.h"
 #include "core/hle/service/nfp/nfp.h"
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp
index cc23b001c..1328b64d0 100644
--- a/src/core/hle/service/nvdrv/interface.cpp
+++ b/src/core/hle/service/nvdrv/interface.cpp
@@ -6,9 +6,9 @@
 #include "common/logging/log.h"
 #include "core/core.h"
 #include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/readable_event.h"
-#include "core/hle/kernel/thread.h"
 #include "core/hle/kernel/writable_event.h"
 #include "core/hle/service/nvdrv/interface.h"
 #include "core/hle/service/nvdrv/nvdata.h"
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index ff2a5b1db..1da56bc27 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -11,10 +11,10 @@
 #include "core/hle/ipc.h"
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/kernel/client_port.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/server_port.h"
-#include "core/hle/kernel/thread.h"
 #include "core/hle/service/acc/acc.h"
 #include "core/hle/service/am/am.h"
 #include "core/hle/service/aoc/aoc_u.h"
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp
index d85df6af1..22f540914 100644
--- a/src/core/hle/service/sockets/bsd.cpp
+++ b/src/core/hle/service/sockets/bsd.cpp
@@ -13,7 +13,7 @@
 #include "common/microprofile.h"
 #include "common/thread.h"
 #include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/thread.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/service/sockets/bsd.h"
 #include "core/hle/service/sockets/sockets_translate.h"
 #include "core/network/network.h"
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index abc753d5d..18629dd7e 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -121,7 +121,7 @@ private:
 };
 
 ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal(
-    Kernel::Thread* thread, Clock::SystemClockContext user_context,
+    Kernel::KThread* thread, Clock::SystemClockContext user_context,
     Clock::SystemClockContext network_context, u8 type, Clock::ClockSnapshot& clock_snapshot) {
 
     auto& time_manager{system.GetTimeManager()};
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h
index 975a8ae5b..4154c7ee9 100644
--- a/src/core/hle/service/time/time.h
+++ b/src/core/hle/service/time/time.h
@@ -39,7 +39,7 @@ public:
 
     private:
         ResultCode GetClockSnapshotFromSystemClockContextInternal(
-            Kernel::Thread* thread, Clock::SystemClockContext user_context,
+            Kernel::KThread* thread, Clock::SystemClockContext user_context,
             Clock::SystemClockContext network_context, u8 type,
             Clock::ClockSnapshot& cloc_snapshot);
 
diff --git a/src/core/hle/service/time/time_sharedmemory.h b/src/core/hle/service/time/time_sharedmemory.h
index 5976b2046..e0c3e63da 100644
--- a/src/core/hle/service/time/time_sharedmemory.h
+++ b/src/core/hle/service/time/time_sharedmemory.h
@@ -6,8 +6,8 @@
 
 #include "common/common_types.h"
 #include "common/uuid.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/shared_memory.h"
-#include "core/hle/kernel/thread.h"
 #include "core/hle/service/time/clock_types.h"
 
 namespace Service::Time {
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 968cd16b6..f3de2c428 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -18,8 +18,8 @@
 #include "common/swap.h"
 #include "core/core_timing.h"
 #include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/readable_event.h"
-#include "core/hle/kernel/thread.h"
 #include "core/hle/kernel/writable_event.h"
 #include "core/hle/service/nvdrv/nvdata.h"
 #include "core/hle/service/nvdrv/nvdrv.h"
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index ccf8cc153..4f55314c7 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -15,9 +15,9 @@
 #include "core/file_sys/romfs_factory.h"
 #include "core/file_sys/vfs_offset.h"
 #include "core/hle/kernel/code_set.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/memory/page_table.h"
 #include "core/hle/kernel/process.h"
-#include "core/hle/kernel/thread.h"
 #include "core/hle/service/filesystem/filesystem.h"
 #include "core/loader/nro.h"
 #include "core/loader/nso.h"
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 95b6f339a..50e6cd080 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -15,9 +15,9 @@
 #include "core/core.h"
 #include "core/file_sys/patch_manager.h"
 #include "core/hle/kernel/code_set.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/memory/page_table.h"
 #include "core/hle/kernel/process.h"
-#include "core/hle/kernel/thread.h"
 #include "core/loader/nso.h"
 #include "core/memory.h"
 #include "core/settings.h"
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp
index a93b5d3c2..55a3f7d60 100644
--- a/src/yuzu/debugger/wait_tree.cpp
+++ b/src/yuzu/debugger/wait_tree.cpp
@@ -15,10 +15,10 @@
 #include "core/hle/kernel/handle_table.h"
 #include "core/hle/kernel/k_scheduler.h"
 #include "core/hle/kernel/k_synchronization_object.h"
+#include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/readable_event.h"
 #include "core/hle/kernel/svc_common.h"
-#include "core/hle/kernel/thread.h"
 #include "core/memory.h"
 
 namespace {
@@ -90,7 +90,7 @@ std::size_t WaitTreeItem::Row() const {
 std::vector<std::unique_ptr<WaitTreeThread>> WaitTreeItem::MakeThreadItemList() {
     std::vector<std::unique_ptr<WaitTreeThread>> item_list;
     std::size_t row = 0;
-    auto add_threads = [&](const std::vector<std::shared_ptr<Kernel::Thread>>& threads) {
+    auto add_threads = [&](const std::vector<std::shared_ptr<Kernel::KThread>>& threads) {
         for (std::size_t i = 0; i < threads.size(); ++i) {
             if (!threads[i]->IsHLEThread()) {
                 item_list.push_back(std::make_unique<WaitTreeThread>(*threads[i]));
@@ -117,7 +117,7 @@ WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address, const Kernel::HandleTa
     : mutex_address(mutex_address) {
     mutex_value = Core::System::GetInstance().Memory().Read32(mutex_address);
     owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Svc::HandleWaitMask);
-    owner = handle_table.Get<Kernel::Thread>(owner_handle);
+    owner = handle_table.Get<Kernel::KThread>(owner_handle);
 }
 
 WaitTreeMutexInfo::~WaitTreeMutexInfo() = default;
@@ -139,7 +139,7 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeMutexInfo::GetChildren() cons
     return list;
 }
 
-WaitTreeCallstack::WaitTreeCallstack(const Kernel::Thread& thread) : thread(thread) {}
+WaitTreeCallstack::WaitTreeCallstack(const Kernel::KThread& thread) : thread(thread) {}
 WaitTreeCallstack::~WaitTreeCallstack() = default;
 
 QString WaitTreeCallstack::GetText() const {
@@ -194,7 +194,7 @@ std::unique_ptr<WaitTreeSynchronizationObject> WaitTreeSynchronizationObject::ma
     case Kernel::HandleType::ReadableEvent:
         return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::ReadableEvent&>(object));
     case Kernel::HandleType::Thread:
-        return std::make_unique<WaitTreeThread>(static_cast<const Kernel::Thread&>(object));
+        return std::make_unique<WaitTreeThread>(static_cast<const Kernel::KThread&>(object));
     default:
         return std::make_unique<WaitTreeSynchronizationObject>(object);
     }
@@ -231,12 +231,12 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeObjectList::GetChildren() con
     return list;
 }
 
-WaitTreeThread::WaitTreeThread(const Kernel::Thread& thread)
+WaitTreeThread::WaitTreeThread(const Kernel::KThread& thread)
     : WaitTreeSynchronizationObject(thread) {}
 WaitTreeThread::~WaitTreeThread() = default;
 
 QString WaitTreeThread::GetText() const {
-    const auto& thread = static_cast<const Kernel::Thread&>(object);
+    const auto& thread = static_cast<const Kernel::KThread&>(object);
     QString status;
     switch (thread.GetState()) {
     case Kernel::ThreadState::Runnable:
@@ -297,7 +297,7 @@ QString WaitTreeThread::GetText() const {
 QColor WaitTreeThread::GetColor() const {
     const std::size_t color_index = IsDarkTheme() ? 1 : 0;
 
-    const auto& thread = static_cast<const Kernel::Thread&>(object);
+    const auto& thread = static_cast<const Kernel::KThread&>(object);
     switch (thread.GetState()) {
     case Kernel::ThreadState::Runnable:
         if (!thread.IsPaused()) {
@@ -336,7 +336,7 @@ QColor WaitTreeThread::GetColor() const {
 std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
     std::vector<std::unique_ptr<WaitTreeItem>> list(WaitTreeSynchronizationObject::GetChildren());
 
-    const auto& thread = static_cast<const Kernel::Thread&>(object);
+    const auto& thread = static_cast<const Kernel::KThread&>(object);
 
     QString processor;
     switch (thread.GetProcessorID()) {
@@ -390,7 +390,7 @@ WaitTreeEvent::WaitTreeEvent(const Kernel::ReadableEvent& object)
     : WaitTreeSynchronizationObject(object) {}
 WaitTreeEvent::~WaitTreeEvent() = default;
 
-WaitTreeThreadList::WaitTreeThreadList(const std::vector<Kernel::Thread*>& list)
+WaitTreeThreadList::WaitTreeThreadList(const std::vector<Kernel::KThread*>& list)
     : thread_list(list) {}
 WaitTreeThreadList::~WaitTreeThreadList() = default;
 
diff --git a/src/yuzu/debugger/wait_tree.h b/src/yuzu/debugger/wait_tree.h
index cf96911ea..b202c5567 100644
--- a/src/yuzu/debugger/wait_tree.h
+++ b/src/yuzu/debugger/wait_tree.h
@@ -19,8 +19,8 @@ class EmuThread;
 namespace Kernel {
 class HandleTable;
 class KSynchronizationObject;
+class KThread;
 class ReadableEvent;
-class Thread;
 } // namespace Kernel
 
 class WaitTreeThread;
@@ -83,20 +83,20 @@ private:
     VAddr mutex_address;
     u32 mutex_value;
     Kernel::Handle owner_handle;
-    std::shared_ptr<Kernel::Thread> owner;
+    std::shared_ptr<Kernel::KThread> owner;
 };
 
 class WaitTreeCallstack : public WaitTreeExpandableItem {
     Q_OBJECT
 public:
-    explicit WaitTreeCallstack(const Kernel::Thread& thread);
+    explicit WaitTreeCallstack(const Kernel::KThread& thread);
     ~WaitTreeCallstack() override;
 
     QString GetText() const override;
     std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
 
 private:
-    const Kernel::Thread& thread;
+    const Kernel::KThread& thread;
 };
 
 class WaitTreeSynchronizationObject : public WaitTreeExpandableItem {
@@ -131,7 +131,7 @@ private:
 class WaitTreeThread : public WaitTreeSynchronizationObject {
     Q_OBJECT
 public:
-    explicit WaitTreeThread(const Kernel::Thread& thread);
+    explicit WaitTreeThread(const Kernel::KThread& thread);
     ~WaitTreeThread() override;
 
     QString GetText() const override;
@@ -149,14 +149,14 @@ public:
 class WaitTreeThreadList : public WaitTreeExpandableItem {
     Q_OBJECT
 public:
-    explicit WaitTreeThreadList(const std::vector<Kernel::Thread*>& list);
+    explicit WaitTreeThreadList(const std::vector<Kernel::KThread*>& list);
     ~WaitTreeThreadList() override;
 
     QString GetText() const override;
     std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
 
 private:
-    const std::vector<Kernel::Thread*>& thread_list;
+    const std::vector<Kernel::KThread*>& thread_list;
 };
 
 class WaitTreeModel : public QAbstractItemModel {

From 9a4e148f9e27671f58f0d32afb2c9a85adc136c5 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Wed, 30 Dec 2020 23:38:49 -0800
Subject: [PATCH 02/34] arm: arm_dynarmic: Skip calls when JIT is invalid.

- This can happen if called from an idle or suspension thread.
---
 src/core/arm/dynarmic/arm_dynarmic_32.cpp | 12 ++++++++++++
 src/core/arm/dynarmic/arm_dynarmic_64.cpp | 12 ++++++++++++
 2 files changed, 24 insertions(+)

diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index 6c4c8e9e4..7d7e191ea 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -251,10 +251,16 @@ void ARM_Dynarmic_32::SetTPIDR_EL0(u64 value) {
 }
 
 void ARM_Dynarmic_32::ChangeProcessorID(std::size_t new_core_id) {
+    if (!jit) {
+        return;
+    }
     jit->ChangeProcessorID(new_core_id);
 }
 
 void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
+    if (!jit) {
+        return;
+    }
     Dynarmic::A32::Context context;
     jit->SaveContext(context);
     ctx.cpu_registers = context.Regs();
@@ -264,6 +270,9 @@ void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
 }
 
 void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) {
+    if (!jit) {
+        return;
+    }
     Dynarmic::A32::Context context;
     context.Regs() = ctx.cpu_registers;
     context.ExtRegs() = ctx.extension_registers;
@@ -273,6 +282,9 @@ void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) {
 }
 
 void ARM_Dynarmic_32::PrepareReschedule() {
+    if (!jit) {
+        return;
+    }
     jit->HaltExecution();
 }
 
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index 4c5ebca22..f755a39cf 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -290,10 +290,16 @@ void ARM_Dynarmic_64::SetTPIDR_EL0(u64 value) {
 }
 
 void ARM_Dynarmic_64::ChangeProcessorID(std::size_t new_core_id) {
+    if (!jit) {
+        return;
+    }
     jit->ChangeProcessorID(new_core_id);
 }
 
 void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) {
+    if (!jit) {
+        return;
+    }
     ctx.cpu_registers = jit->GetRegisters();
     ctx.sp = jit->GetSP();
     ctx.pc = jit->GetPC();
@@ -305,6 +311,9 @@ void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) {
 }
 
 void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) {
+    if (!jit) {
+        return;
+    }
     jit->SetRegisters(ctx.cpu_registers);
     jit->SetSP(ctx.sp);
     jit->SetPC(ctx.pc);
@@ -316,6 +325,9 @@ void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) {
 }
 
 void ARM_Dynarmic_64::PrepareReschedule() {
+    if (!jit) {
+        return;
+    }
     jit->HaltExecution();
 }
 

From eea346ba8eed49111d34e2fb1eee8a1ad53c4614 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Thu, 31 Dec 2020 00:46:09 -0800
Subject: [PATCH 03/34] hle: kernel: KThread: Remove thread types that do not
 exist.

---
 src/core/cpu_manager.cpp            |  2 +-
 src/core/hle/kernel/k_scheduler.cpp | 27 +++++++++++++--------------
 src/core/hle/kernel/k_thread.cpp    | 21 +++++++++------------
 src/core/hle/kernel/k_thread.h      | 15 ++-------------
 src/core/hle/kernel/kernel.cpp      |  8 +++-----
 src/yuzu/debugger/wait_tree.cpp     | 10 ++--------
 6 files changed, 30 insertions(+), 53 deletions(-)

diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index 122edb588..018cd2e25 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -279,7 +279,7 @@ void CpuManager::PreemptSingleCore(bool from_running_enviroment) {
         auto& scheduler = system.Kernel().Scheduler(current_core);
         scheduler.Reload(scheduler.GetCurrentThread());
         auto* currrent_thread2 = scheduler.GetCurrentThread();
-        if (!currrent_thread2->IsIdleThread()) {
+        if (!currrent_thread2->IsKernelThread()) {
             idle_count = 0;
         }
     }
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index 0f7a541c8..edc5df733 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -627,11 +627,11 @@ void KScheduler::OnThreadStart() {
 void KScheduler::Unload(KThread* thread) {
     if (thread) {
         thread->SetIsRunning(false);
-        if (thread->IsContinuousOnSVC() && !thread->IsHLEThread()) {
+        if (thread->IsContinuousOnSVC()) {
             system.ArmInterface(core_id).ExceptionalExit();
             thread->SetContinuousOnSVC(false);
         }
-        if (!thread->IsHLEThread() && !thread->HasExited()) {
+        if (!thread->HasExited()) {
             Core::ARM_Interface& cpu_core = system.ArmInterface(core_id);
             cpu_core.SaveContext(thread->GetContext32());
             cpu_core.SaveContext(thread->GetContext64());
@@ -655,14 +655,13 @@ void KScheduler::Reload(KThread* thread) {
         if (thread_owner_process != nullptr) {
             system.Kernel().MakeCurrentProcess(thread_owner_process);
         }
-        if (!thread->IsHLEThread()) {
-            Core::ARM_Interface& cpu_core = system.ArmInterface(core_id);
-            cpu_core.LoadContext(thread->GetContext32());
-            cpu_core.LoadContext(thread->GetContext64());
-            cpu_core.SetTlsAddress(thread->GetTLSAddress());
-            cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0());
-            cpu_core.ClearExclusiveState();
-        }
+
+        Core::ARM_Interface& cpu_core = system.ArmInterface(core_id);
+        cpu_core.LoadContext(thread->GetContext32());
+        cpu_core.LoadContext(thread->GetContext64());
+        cpu_core.SetTlsAddress(thread->GetTLSAddress());
+        cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0());
+        cpu_core.ClearExclusiveState();
     }
 }
 
@@ -722,7 +721,7 @@ void KScheduler::SwitchToCurrent() {
             return state.needs_scheduling.load(std::memory_order_relaxed);
         };
         do {
-            if (current_thread != nullptr && !current_thread->IsHLEThread()) {
+            if (current_thread != nullptr) {
                 current_thread->context_guard.lock();
                 if (current_thread->GetRawState() != ThreadState::Runnable) {
                     current_thread->context_guard.unlock();
@@ -764,9 +763,9 @@ void KScheduler::Initialize() {
     std::string name = "Idle Thread Id:" + std::to_string(core_id);
     std::function<void(void*)> init_func = Core::CpuManager::GetIdleThreadStartFunc();
     void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
-    ThreadType type = static_cast<ThreadType>(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_IDLE);
-    auto thread_res = KThread::Create(system, type, name, 0, 64, 0, static_cast<u32>(core_id), 0,
-                                      nullptr, std::move(init_func), init_func_parameter);
+    auto thread_res = KThread::Create(system, THREADTYPE_KERNEL, name, 0, THREADPRIO_LOWEST, 0,
+                                      static_cast<u32>(core_id), 0, nullptr, std::move(init_func),
+                                      init_func_parameter);
     idle_thread = thread_res.Unwrap().get();
 
     {
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index 1ec29636c..0f349dad2 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -125,7 +125,7 @@ ResultVal<std::shared_ptr<KThread>> KThread::Create(Core::System& system, Thread
                                                     void* thread_start_parameter) {
     auto& kernel = system.Kernel();
     // Check if priority is in ranged. Lowest priority -> highest priority id.
-    if (priority > THREADPRIO_LOWEST && ((type_flags & THREADTYPE_IDLE) == 0)) {
+    if (priority > THREADPRIO_LOWEST) {
         LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority);
         return ERR_INVALID_THREAD_PRIORITY;
     }
@@ -164,10 +164,10 @@ ResultVal<std::shared_ptr<KThread>> KThread::Create(Core::System& system, Thread
     thread->owner_process = owner_process;
     thread->type = type_flags;
     thread->signaled = false;
-    if ((type_flags & THREADTYPE_IDLE) == 0) {
-        auto& scheduler = kernel.GlobalSchedulerContext();
-        scheduler.AddThread(thread);
-    }
+
+    auto& scheduler = kernel.GlobalSchedulerContext();
+    scheduler.AddThread(thread);
+
     if (owner_process) {
         thread->tls_address = thread->owner_process->CreateTLSRegion();
         thread->owner_process->RegisterThread(thread.get());
@@ -175,13 +175,10 @@ ResultVal<std::shared_ptr<KThread>> KThread::Create(Core::System& system, Thread
         thread->tls_address = 0;
     }
 
-    // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
-    // to initialize the context
-    if ((type_flags & THREADTYPE_HLE) == 0) {
-        ResetThreadContext32(thread->context_32, static_cast<u32>(stack_top),
-                             static_cast<u32>(entry_point), static_cast<u32>(arg));
-        ResetThreadContext64(thread->context_64, stack_top, entry_point, arg);
-    }
+    ResetThreadContext32(thread->context_32, static_cast<u32>(stack_top),
+                         static_cast<u32>(entry_point), static_cast<u32>(arg));
+    ResetThreadContext64(thread->context_64, stack_top, entry_point, arg);
+
     thread->host_context =
         std::make_shared<Common::Fiber>(std::move(thread_start_func), thread_start_parameter);
 
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index 75257d2b4..d9fe2e363 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -51,9 +51,6 @@ enum ThreadPriority : u32 {
 enum ThreadType : u32 {
     THREADTYPE_USER = 0x1,
     THREADTYPE_KERNEL = 0x2,
-    THREADTYPE_HLE = 0x4,
-    THREADTYPE_IDLE = 0x8,
-    THREADTYPE_SUSPEND = 0x10,
 };
 
 enum ThreadProcessorId : s32 {
@@ -309,16 +306,8 @@ public:
         return context_64;
     }
 
-    bool IsHLEThread() const {
-        return (type & THREADTYPE_HLE) != 0;
-    }
-
-    bool IsSuspendThread() const {
-        return (type & THREADTYPE_SUSPEND) != 0;
-    }
-
-    bool IsIdleThread() const {
-        return (type & THREADTYPE_IDLE) != 0;
+    bool IsKernelThread() const {
+        return (type & THREADTYPE_KERNEL) != 0;
     }
 
     bool WasRunning() const {
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 523dd63a5..6ae0bdeed 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -168,11 +168,9 @@ struct KernelCore::Impl {
             std::string name = "Suspend Thread Id:" + std::to_string(i);
             std::function<void(void*)> init_func = Core::CpuManager::GetSuspendThreadStartFunc();
             void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
-            const auto type =
-                static_cast<ThreadType>(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_SUSPEND);
-            auto thread_res =
-                KThread::Create(system, type, std::move(name), 0, 0, 0, static_cast<u32>(i), 0,
-                                nullptr, std::move(init_func), init_func_parameter);
+            auto thread_res = KThread::Create(system, THREADTYPE_KERNEL, std::move(name), 0, 0, 0,
+                                              static_cast<u32>(i), 0, nullptr, std::move(init_func),
+                                              init_func_parameter);
 
             suspend_threads[i] = std::move(thread_res).Unwrap();
         }
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp
index 55a3f7d60..0f03f4d90 100644
--- a/src/yuzu/debugger/wait_tree.cpp
+++ b/src/yuzu/debugger/wait_tree.cpp
@@ -92,10 +92,8 @@ std::vector<std::unique_ptr<WaitTreeThread>> WaitTreeItem::MakeThreadItemList()
     std::size_t row = 0;
     auto add_threads = [&](const std::vector<std::shared_ptr<Kernel::KThread>>& threads) {
         for (std::size_t i = 0; i < threads.size(); ++i) {
-            if (!threads[i]->IsHLEThread()) {
-                item_list.push_back(std::make_unique<WaitTreeThread>(*threads[i]));
-                item_list.back()->row = row;
-            }
+            item_list.push_back(std::make_unique<WaitTreeThread>(*threads[i]));
+            item_list.back()->row = row;
             ++row;
         }
     };
@@ -149,10 +147,6 @@ QString WaitTreeCallstack::GetText() const {
 std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() const {
     std::vector<std::unique_ptr<WaitTreeItem>> list;
 
-    if (thread.IsHLEThread()) {
-        return list;
-    }
-
     if (thread.GetOwnerProcess() == nullptr || !thread.GetOwnerProcess()->Is64BitProcess()) {
         return list;
     }

From 47829850131f04075950b733cb93a3688e8afb5b Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Thu, 31 Dec 2020 02:13:02 -0800
Subject: [PATCH 04/34] hle: kernel: Move single core "phantom mode" out of
 KThread.

- This is a workaround that does not belong in a kernel primitive.
---
 src/core/cpu_manager.cpp       | 13 +++++++------
 src/core/hle/kernel/k_thread.h |  9 ---------
 src/core/hle/kernel/kernel.cpp | 21 ++++++++++++++++++++-
 src/core/hle/kernel/kernel.h   |  4 ++++
 4 files changed, 31 insertions(+), 16 deletions(-)

diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index 018cd2e25..719258250 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -217,9 +217,9 @@ void CpuManager::SingleCoreRunGuestLoop() {
             physical_core = &kernel.CurrentPhysicalCore();
         }
         system.ExitDynarmicProfile();
-        thread->SetPhantomMode(true);
+        kernel.SetIsPhantomModeForSingleCore(true);
         system.CoreTiming().Advance();
-        thread->SetPhantomMode(false);
+        kernel.SetIsPhantomModeForSingleCore(false);
         physical_core->ArmInterface().ClearExclusiveState();
         PreemptSingleCore();
         auto& scheduler = kernel.Scheduler(current_core);
@@ -255,22 +255,23 @@ void CpuManager::SingleCoreRunSuspendThread() {
 
 void CpuManager::PreemptSingleCore(bool from_running_enviroment) {
     {
-        auto& scheduler = system.Kernel().Scheduler(current_core);
+        auto& kernel = system.Kernel();
+        auto& scheduler = kernel.Scheduler(current_core);
         Kernel::KThread* current_thread = scheduler.GetCurrentThread();
         if (idle_count >= 4 || from_running_enviroment) {
             if (!from_running_enviroment) {
                 system.CoreTiming().Idle();
                 idle_count = 0;
             }
-            current_thread->SetPhantomMode(true);
+            kernel.SetIsPhantomModeForSingleCore(true);
             system.CoreTiming().Advance();
-            current_thread->SetPhantomMode(false);
+            kernel.SetIsPhantomModeForSingleCore(false);
         }
         current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES);
         system.CoreTiming().ResetTicks();
         scheduler.Unload(scheduler.GetCurrentThread());
 
-        auto& next_scheduler = system.Kernel().Scheduler(current_core);
+        auto& next_scheduler = kernel.Scheduler(current_core);
         Common::Fiber::YieldTo(current_thread->GetHostContext(), next_scheduler.ControlContext());
     }
 
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index d9fe2e363..7dec9449e 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -451,14 +451,6 @@ public:
         is_continuous_on_svc = is_continuous;
     }
 
-    bool IsPhantomMode() const {
-        return is_phantom_mode;
-    }
-
-    void SetPhantomMode(bool phantom) {
-        is_phantom_mode = phantom;
-    }
-
     bool HasExited() const {
         return has_exited;
     }
@@ -747,7 +739,6 @@ private:
     bool is_continuous_on_svc = false;
 
     bool will_be_terminated = false;
-    bool is_phantom_mode = false;
     bool has_exited = false;
 
     bool was_running = false;
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 6ae0bdeed..80a78e643 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -62,6 +62,7 @@ struct KernelCore::Impl {
         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;
 
         InitializePhysicalCores();
         InitializeSystemResourceLimit(kernel);
@@ -227,6 +228,15 @@ struct KernelCore::Impl {
         return this_id;
     }
 
+    bool IsPhantomModeForSingleCore() const {
+        return is_phantom_mode_for_singlecore;
+    }
+
+    void SetIsPhantomModeForSingleCore(bool value) {
+        ASSERT(!is_multicore);
+        is_phantom_mode_for_singlecore = value;
+    }
+
     [[nodiscard]] Core::EmuThreadHandle GetCurrentEmuThreadID() {
         Core::EmuThreadHandle result = Core::EmuThreadHandle::InvalidHandle();
         result.host_handle = GetCurrentHostThreadID();
@@ -235,7 +245,7 @@ struct KernelCore::Impl {
         }
         const Kernel::KScheduler& sched = cores[result.host_handle].Scheduler();
         const Kernel::KThread* current = sched.GetCurrentThread();
-        if (current != nullptr && !current->IsPhantomMode()) {
+        if (current != nullptr && !IsPhantomModeForSingleCore()) {
             result.guest_handle = current->GetGlobalHandle();
         } else {
             result.guest_handle = InvalidHandle;
@@ -345,6 +355,7 @@ struct KernelCore::Impl {
     std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
 
     bool is_multicore{};
+    bool is_phantom_mode_for_singlecore{};
     u32 single_core_thread_id{};
 
     std::array<u64, Core::Hardware::NUM_CPU_CORES> svc_ticks{};
@@ -643,4 +654,12 @@ void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> servi
     });
 }
 
+bool KernelCore::IsPhantomModeForSingleCore() const {
+    return impl->IsPhantomModeForSingleCore();
+}
+
+void KernelCore::SetIsPhantomModeForSingleCore(bool value) {
+    impl->SetIsPhantomModeForSingleCore(value);
+}
+
 } // namespace Kernel
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 41c553582..fc58f3ecb 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -237,6 +237,10 @@ public:
      */
     void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread);
 
+    /// Workaround for single-core mode when preempting threads while idle.
+    bool IsPhantomModeForSingleCore() const;
+    void SetIsPhantomModeForSingleCore(bool value);
+
 private:
     friend class Object;
     friend class Process;

From 0530292b9768637aa6e2875e931c1066af4aa80e Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Fri, 1 Jan 2021 01:04:30 -0800
Subject: [PATCH 05/34] hle: kernel: KThread: Fix ThreadType definition.

---
 src/core/hle/kernel/k_scheduler.cpp |  2 +-
 src/core/hle/kernel/k_thread.h      | 11 +++++++----
 src/core/hle/kernel/kernel.cpp      |  2 +-
 src/core/hle/kernel/process.cpp     |  3 +--
 src/core/hle/kernel/svc.cpp         |  5 ++---
 5 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index edc5df733..0f34a8a69 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -763,7 +763,7 @@ void KScheduler::Initialize() {
     std::string name = "Idle Thread Id:" + std::to_string(core_id);
     std::function<void(void*)> init_func = Core::CpuManager::GetIdleThreadStartFunc();
     void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
-    auto thread_res = KThread::Create(system, THREADTYPE_KERNEL, name, 0, THREADPRIO_LOWEST, 0,
+    auto thread_res = KThread::Create(system, ThreadType::Kernel, name, 0, THREADPRIO_LOWEST, 0,
                                       static_cast<u32>(core_id), 0, nullptr, std::move(init_func),
                                       init_func_parameter);
     idle_thread = thread_res.Unwrap().get();
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index 7dec9449e..bef480dd7 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -48,10 +48,13 @@ enum ThreadPriority : u32 {
     THREADPRIO_COUNT = 64,             ///< Total number of possible thread priorities.
 };
 
-enum ThreadType : u32 {
-    THREADTYPE_USER = 0x1,
-    THREADTYPE_KERNEL = 0x2,
+enum class ThreadType : u32 {
+    Main = 0,
+    Kernel = 1,
+    HighPriority = 2,
+    User = 3,
 };
+DECLARE_ENUM_FLAG_OPERATORS(ThreadType);
 
 enum ThreadProcessorId : s32 {
     /// Indicates that no particular processor core is preferred.
@@ -307,7 +310,7 @@ public:
     }
 
     bool IsKernelThread() const {
-        return (type & THREADTYPE_KERNEL) != 0;
+        return type == ThreadType::Kernel;
     }
 
     bool WasRunning() const {
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 80a78e643..97a5dc2e0 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -169,7 +169,7 @@ struct KernelCore::Impl {
             std::string name = "Suspend Thread Id:" + std::to_string(i);
             std::function<void(void*)> init_func = Core::CpuManager::GetSuspendThreadStartFunc();
             void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
-            auto thread_res = KThread::Create(system, THREADTYPE_KERNEL, std::move(name), 0, 0, 0,
+            auto thread_res = KThread::Create(system, ThreadType::Kernel, std::move(name), 0, 0, 0,
                                               static_cast<u32>(i), 0, nullptr, std::move(init_func),
                                               init_func_parameter);
 
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index ccd371aba..e47da2b7f 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -38,8 +38,7 @@ namespace {
  */
 void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) {
     const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart();
-    ThreadType type = THREADTYPE_USER;
-    auto thread_res = KThread::Create(system, type, "main", entry_point, priority, 0,
+    auto thread_res = KThread::Create(system, ThreadType::User, "main", entry_point, priority, 0,
                                       owner_process.GetIdealCore(), stack_top, &owner_process);
 
     std::shared_ptr<KThread> thread = std::move(thread_res).Unwrap();
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 3609346d6..711b9d520 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1488,10 +1488,9 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
 
     ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(ResourceType::Threads, 1));
 
-    ThreadType type = THREADTYPE_USER;
     CASCADE_RESULT(std::shared_ptr<KThread> thread,
-                   KThread::Create(system, type, "", entry_point, priority, arg, processor_id,
-                                   stack_top, current_process));
+                   KThread::Create(system, ThreadType::User, "", entry_point, priority, arg,
+                                   processor_id, stack_top, current_process));
 
     const auto new_thread_handle = current_process->GetHandleTable().Create(thread);
     if (new_thread_handle.Failed()) {

From 1e55498110800623c63e3ef03bfbff6b6de1c522 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Fri, 1 Jan 2021 02:06:06 -0800
Subject: [PATCH 06/34] hle: kernel: KThread: Reorganize thread priority
 defaults.

---
 src/core/hle/kernel/global_scheduler_context.h |  9 +++++++--
 src/core/hle/kernel/k_scheduler.cpp            |  6 +++---
 src/core/hle/kernel/k_thread.cpp               | 13 ++++++-------
 src/core/hle/kernel/k_thread.h                 | 12 +++---------
 src/core/hle/kernel/svc.cpp                    | 10 ++++------
 src/core/hle/kernel/svc_results.h              |  1 +
 src/core/hle/kernel/svc_types.h                |  3 +++
 src/core/loader/nro.cpp                        |  4 ++--
 src/core/loader/nso.cpp                        |  4 ++--
 9 files changed, 31 insertions(+), 31 deletions(-)

diff --git a/src/core/hle/kernel/global_scheduler_context.h b/src/core/hle/kernel/global_scheduler_context.h
index a365ffdaf..11592843e 100644
--- a/src/core/hle/kernel/global_scheduler_context.h
+++ b/src/core/hle/kernel/global_scheduler_context.h
@@ -13,6 +13,7 @@
 #include "core/hle/kernel/k_priority_queue.h"
 #include "core/hle/kernel/k_scheduler_lock.h"
 #include "core/hle/kernel/k_thread.h"
+#include "core/hle/kernel/svc_types.h"
 
 namespace Kernel {
 
@@ -20,8 +21,12 @@ class KernelCore;
 class SchedulerLock;
 
 using KSchedulerPriorityQueue =
-    KPriorityQueue<KThread, Core::Hardware::NUM_CPU_CORES, THREADPRIO_LOWEST, THREADPRIO_HIGHEST>;
-constexpr s32 HighestCoreMigrationAllowedPriority = 2;
+    KPriorityQueue<KThread, Core::Hardware::NUM_CPU_CORES, Svc::LowestThreadPriority,
+                   Svc::HighestThreadPriority>;
+
+static constexpr s32 HighestCoreMigrationAllowedPriority = 2;
+static_assert(Svc::LowestThreadPriority >= HighestCoreMigrationAllowedPriority);
+static_assert(Svc::HighestThreadPriority <= HighestCoreMigrationAllowedPriority);
 
 class GlobalSchedulerContext final {
     friend class KScheduler;
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index 0f34a8a69..0e6300760 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -763,9 +763,9 @@ void KScheduler::Initialize() {
     std::string name = "Idle Thread Id:" + std::to_string(core_id);
     std::function<void(void*)> init_func = Core::CpuManager::GetIdleThreadStartFunc();
     void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
-    auto thread_res = KThread::Create(system, ThreadType::Kernel, name, 0, THREADPRIO_LOWEST, 0,
-                                      static_cast<u32>(core_id), 0, nullptr, std::move(init_func),
-                                      init_func_parameter);
+    auto thread_res = KThread::Create(system, ThreadType::Kernel, name, 0,
+                                      Svc::LowestThreadPriority, 0, static_cast<u32>(core_id), 0,
+                                      nullptr, std::move(init_func), init_func_parameter);
     idle_thread = thread_res.Unwrap().get();
 
     {
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index 0f349dad2..518c5d5df 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -8,6 +8,7 @@
 #include <vector>
 
 #include "common/assert.h"
+#include "common/common_funcs.h"
 #include "common/common_types.h"
 #include "common/fiber.h"
 #include "common/logging/log.h"
@@ -25,6 +26,7 @@
 #include "core/hle/kernel/memory/memory_layout.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/process.h"
+#include "core/hle/kernel/svc_results.h"
 #include "core/hle/kernel/time_manager.h"
 #include "core/hle/result.h"
 #include "core/memory.h"
@@ -124,11 +126,9 @@ ResultVal<std::shared_ptr<KThread>> KThread::Create(Core::System& system, Thread
                                                     std::function<void(void*)>&& thread_start_func,
                                                     void* thread_start_parameter) {
     auto& kernel = system.Kernel();
-    // Check if priority is in ranged. Lowest priority -> highest priority id.
-    if (priority > THREADPRIO_LOWEST) {
-        LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority);
-        return ERR_INVALID_THREAD_PRIORITY;
-    }
+
+    R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority,
+             Svc::ResultInvalidPriority);
 
     if (processor_id > THREADPROCESSORID_MAX) {
         LOG_ERROR(Kernel_SVC, "Invalid processor id: {}", processor_id);
@@ -186,8 +186,7 @@ ResultVal<std::shared_ptr<KThread>> KThread::Create(Core::System& system, Thread
 }
 
 void KThread::SetBasePriority(u32 priority) {
-    ASSERT_MSG(priority <= THREADPRIO_LOWEST && priority >= THREADPRIO_HIGHEST,
-               "Invalid priority value.");
+    ASSERT(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority);
 
     KScopedSchedulerLock lock(kernel);
 
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index bef480dd7..83a6d36ae 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -39,15 +39,6 @@ class KernelCore;
 class Process;
 class KScheduler;
 
-enum ThreadPriority : u32 {
-    THREADPRIO_HIGHEST = 0,            ///< Highest thread priority
-    THREADPRIO_MAX_CORE_MIGRATION = 2, ///< Highest priority for a core migration
-    THREADPRIO_USERLAND_MAX = 24,      ///< Highest thread priority for userland apps
-    THREADPRIO_DEFAULT = 44,           ///< Default thread priority for userland apps
-    THREADPRIO_LOWEST = 63,            ///< Lowest thread priority
-    THREADPRIO_COUNT = 64,             ///< Total number of possible thread priorities.
-};
-
 enum class ThreadType : u32 {
     Main = 0,
     Kernel = 1,
@@ -129,6 +120,9 @@ class KThread final : public KSynchronizationObject, public boost::intrusive::li
     friend class Process;
 
 public:
+    static constexpr s32 DefaultThreadPriority = 44;
+    static constexpr s32 IdleThreadPriority = 64;
+
     explicit KThread(KernelCore& kernel);
     ~KThread() override;
 
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 711b9d520..70a8ef34b 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1130,11 +1130,9 @@ static ResultCode GetThreadPriority32(Core::System& system, u32* priority, Handl
 static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 priority) {
     LOG_TRACE(Kernel_SVC, "called");
 
-    if (priority > THREADPRIO_LOWEST) {
-        LOG_ERROR(
-            Kernel_SVC,
-            "An invalid priority was specified, expected {} but got {} for thread_handle={:08X}",
-            THREADPRIO_LOWEST, priority, handle);
+    if (priority > Svc::LowestThreadPriority) {
+        LOG_ERROR(Kernel_SVC, "An invalid priority was specified {} for thread_handle={:08X}",
+                  priority, handle);
         return ERR_INVALID_THREAD_PRIORITY;
     }
 
@@ -1472,7 +1470,7 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
         return ERR_INVALID_PROCESSOR_ID;
     }
 
-    if (priority > THREADPRIO_LOWEST) {
+    if (priority > Svc::LowestThreadPriority) {
         LOG_ERROR(Kernel_SVC,
                   "Invalid thread priority specified ({}). Must be within the range 0-64",
                   priority);
diff --git a/src/core/hle/kernel/svc_results.h b/src/core/hle/kernel/svc_results.h
index 78282f021..74adabc11 100644
--- a/src/core/hle/kernel/svc_results.h
+++ b/src/core/hle/kernel/svc_results.h
@@ -11,6 +11,7 @@ namespace Kernel::Svc {
 constexpr ResultCode ResultTerminationRequested{ErrorModule::Kernel, 59};
 constexpr ResultCode ResultInvalidAddress{ErrorModule::Kernel, 102};
 constexpr ResultCode ResultInvalidCurrentMemory{ErrorModule::Kernel, 106};
+constexpr ResultCode ResultInvalidPriority{ErrorModule::Kernel, 112};
 constexpr ResultCode ResultInvalidHandle{ErrorModule::Kernel, 114};
 constexpr ResultCode ResultTimedOut{ErrorModule::Kernel, 117};
 constexpr ResultCode ResultCancelled{ErrorModule::Kernel, 118};
diff --git a/src/core/hle/kernel/svc_types.h b/src/core/hle/kernel/svc_types.h
index d623f7a50..09b858f2a 100644
--- a/src/core/hle/kernel/svc_types.h
+++ b/src/core/hle/kernel/svc_types.h
@@ -77,4 +77,7 @@ enum class ArbitrationType : u32 {
     WaitIfEqual = 2,
 };
 
+constexpr inline s32 LowestThreadPriority = 63;
+constexpr inline s32 HighestThreadPriority = 0;
+
 } // namespace Kernel::Svc
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 4f55314c7..f976d0a9c 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -219,8 +219,8 @@ AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::Process& process, Core::Sy
     }
 
     is_loaded = true;
-    return {ResultStatus::Success,
-            LoadParameters{Kernel::THREADPRIO_DEFAULT, Core::Memory::DEFAULT_STACK_SIZE}};
+    return {ResultStatus::Success, LoadParameters{Kernel::KThread::DefaultThreadPriority,
+                                                  Core::Memory::DEFAULT_STACK_SIZE}};
 }
 
 ResultStatus AppLoader_NRO::ReadIcon(std::vector<u8>& buffer) {
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 50e6cd080..ea347ea83 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -179,8 +179,8 @@ AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::Process& process, Core::Sy
     LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address);
 
     is_loaded = true;
-    return {ResultStatus::Success,
-            LoadParameters{Kernel::THREADPRIO_DEFAULT, Core::Memory::DEFAULT_STACK_SIZE}};
+    return {ResultStatus::Success, LoadParameters{Kernel::KThread::DefaultThreadPriority,
+                                                  Core::Memory::DEFAULT_STACK_SIZE}};
 }
 
 ResultStatus AppLoader_NSO::ReadNSOModules(Modules& modules) {

From 4dbf3f4880cac69db21cc8f18582814dc986c854 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Sun, 3 Jan 2021 01:49:18 -0800
Subject: [PATCH 07/34] hle: kernel: KThread: Clean up thread priorities.

---
 .../hle/kernel/global_scheduler_context.h     |  2 +-
 src/core/hle/kernel/k_scheduler.cpp           |  2 +-
 src/core/hle/kernel/k_thread.cpp              | 10 +--
 src/core/hle/kernel/k_thread.h                | 22 ------
 src/core/hle/kernel/process.cpp               |  2 +-
 src/core/hle/kernel/process.h                 |  7 +-
 src/core/hle/kernel/svc.cpp                   | 70 ++++++++-----------
 src/core/hle/kernel/svc_results.h             |  1 +
 src/core/hle/kernel/svc_types.h               |  4 ++
 src/yuzu/debugger/wait_tree.cpp               | 11 +--
 10 files changed, 46 insertions(+), 85 deletions(-)

diff --git a/src/core/hle/kernel/global_scheduler_context.h b/src/core/hle/kernel/global_scheduler_context.h
index 11592843e..0f7b9a61c 100644
--- a/src/core/hle/kernel/global_scheduler_context.h
+++ b/src/core/hle/kernel/global_scheduler_context.h
@@ -21,7 +21,7 @@ class KernelCore;
 class SchedulerLock;
 
 using KSchedulerPriorityQueue =
-    KPriorityQueue<KThread, Core::Hardware::NUM_CPU_CORES, Svc::LowestThreadPriority,
+    KPriorityQueue<KThread, Core::Hardware::NUM_CPU_CORES, Svc::LowestThreadPriority + 1,
                    Svc::HighestThreadPriority>;
 
 static constexpr s32 HighestCoreMigrationAllowedPriority = 2;
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index 0e6300760..233022023 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -764,7 +764,7 @@ void KScheduler::Initialize() {
     std::function<void(void*)> init_func = Core::CpuManager::GetIdleThreadStartFunc();
     void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
     auto thread_res = KThread::Create(system, ThreadType::Kernel, name, 0,
-                                      Svc::LowestThreadPriority, 0, static_cast<u32>(core_id), 0,
+                                      KThread::IdleThreadPriority, 0, static_cast<u32>(core_id), 0,
                                       nullptr, std::move(init_func), init_func_parameter);
     idle_thread = thread_res.Unwrap().get();
 
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index 518c5d5df..e5be849bb 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -127,14 +127,6 @@ ResultVal<std::shared_ptr<KThread>> KThread::Create(Core::System& system, Thread
                                                     void* thread_start_parameter) {
     auto& kernel = system.Kernel();
 
-    R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority,
-             Svc::ResultInvalidPriority);
-
-    if (processor_id > THREADPROCESSORID_MAX) {
-        LOG_ERROR(Kernel_SVC, "Invalid processor id: {}", processor_id);
-        return ERR_INVALID_PROCESSOR_ID;
-    }
-
     if (owner_process) {
         if (!system.Memory().IsValidVirtualAddress(*owner_process, entry_point)) {
             LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point);
@@ -423,7 +415,7 @@ ResultCode KThread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask)
     };
 
     const bool use_override = affinity_override_count != 0;
-    if (new_core == THREADPROCESSORID_DONT_UPDATE) {
+    if (new_core == Svc::IdealCoreNoUpdate) {
         new_core = use_override ? ideal_core_override : ideal_core;
         if ((new_affinity_mask & (1ULL << new_core)) == 0) {
             LOG_ERROR(Kernel, "New affinity mask is incorrect! new_core={}, new_affinity_mask={}",
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index 83a6d36ae..ef2313f87 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -47,28 +47,6 @@ enum class ThreadType : u32 {
 };
 DECLARE_ENUM_FLAG_OPERATORS(ThreadType);
 
-enum ThreadProcessorId : s32 {
-    /// Indicates that no particular processor core is preferred.
-    THREADPROCESSORID_DONT_CARE = -1,
-
-    /// Run thread on the ideal core specified by the process.
-    THREADPROCESSORID_IDEAL = -2,
-
-    /// Indicates that the preferred processor ID shouldn't be updated in
-    /// a core mask setting operation.
-    THREADPROCESSORID_DONT_UPDATE = -3,
-
-    THREADPROCESSORID_0 = 0,   ///< Run thread on core 0
-    THREADPROCESSORID_1 = 1,   ///< Run thread on core 1
-    THREADPROCESSORID_2 = 2,   ///< Run thread on core 2
-    THREADPROCESSORID_3 = 3,   ///< Run thread on core 3
-    THREADPROCESSORID_MAX = 4, ///< Processor ID must be less than this
-
-    /// Allowed CPU mask
-    THREADPROCESSORID_DEFAULT_MASK = (1 << THREADPROCESSORID_0) | (1 << THREADPROCESSORID_1) |
-                                     (1 << THREADPROCESSORID_2) | (1 << THREADPROCESSORID_3)
-};
-
 enum class ThreadState : u16 {
     Initialized = 0,
     Waiting = 1,
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index e47da2b7f..819e275ff 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -39,7 +39,7 @@ namespace {
 void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) {
     const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart();
     auto thread_res = KThread::Create(system, ThreadType::User, "main", entry_point, priority, 0,
-                                      owner_process.GetIdealCore(), stack_top, &owner_process);
+                                      owner_process.GetIdealCoreId(), stack_top, &owner_process);
 
     std::shared_ptr<KThread> thread = std::move(thread_res).Unwrap();
 
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index db01d6c8a..5a2cfdb36 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -173,10 +173,15 @@ public:
     std::shared_ptr<ResourceLimit> GetResourceLimit() const;
 
     /// Gets the ideal CPU core ID for this process
-    u8 GetIdealCore() const {
+    u8 GetIdealCoreId() const {
         return ideal_core;
     }
 
+    /// Checks if the specified thread priority is valid.
+    bool CheckThreadPriority(s32 prio) const {
+        return ((1ULL << prio) & GetPriorityMask()) != 0;
+    }
+
     /// Gets the bitmask of allowed cores that this process' threads can run on.
     u64 GetCoreMask() const {
         return capabilities.GetCoreMask();
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 70a8ef34b..2512bfd98 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1443,54 +1443,40 @@ static void ExitProcess32(Core::System& system) {
     ExitProcess(system);
 }
 
+static constexpr bool IsValidCoreId(int32_t core_id) {
+    return (0 <= core_id && core_id < static_cast<int32_t>(Core::Hardware::NUM_CPU_CORES));
+}
+
 /// Creates a new thread
 static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr entry_point, u64 arg,
-                               VAddr stack_top, u32 priority, s32 processor_id) {
+                               VAddr stack_bottom, u32 priority, s32 core_id) {
     LOG_DEBUG(Kernel_SVC,
-              "called entrypoint=0x{:08X}, arg=0x{:08X}, stacktop=0x{:08X}, "
-              "threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}",
-              entry_point, arg, stack_top, priority, processor_id, *out_handle);
-
-    auto* const current_process = system.Kernel().CurrentProcess();
-
-    if (processor_id == THREADPROCESSORID_IDEAL) {
-        // Set the target CPU to the one specified by the process.
-        processor_id = current_process->GetIdealCore();
-        ASSERT(processor_id != THREADPROCESSORID_IDEAL);
-    }
-
-    if (processor_id < THREADPROCESSORID_0 || processor_id > THREADPROCESSORID_3) {
-        LOG_ERROR(Kernel_SVC, "Invalid thread processor ID: {}", processor_id);
-        return ERR_INVALID_PROCESSOR_ID;
-    }
-
-    const u64 core_mask = current_process->GetCoreMask();
-    if ((core_mask | (1ULL << processor_id)) != core_mask) {
-        LOG_ERROR(Kernel_SVC, "Invalid thread core specified ({})", processor_id);
-        return ERR_INVALID_PROCESSOR_ID;
-    }
-
-    if (priority > Svc::LowestThreadPriority) {
-        LOG_ERROR(Kernel_SVC,
-                  "Invalid thread priority specified ({}). Must be within the range 0-64",
-                  priority);
-        return ERR_INVALID_THREAD_PRIORITY;
-    }
-
-    if (((1ULL << priority) & current_process->GetPriorityMask()) == 0) {
-        LOG_ERROR(Kernel_SVC, "Invalid thread priority specified ({})", priority);
-        return ERR_INVALID_THREAD_PRIORITY;
-    }
+              "called entry_point=0x{:08X}, arg=0x{:08X}, stack_bottom=0x{:08X}, "
+              "priority=0x{:08X}, core_id=0x{:08X}",
+              entry_point, arg, stack_bottom, priority, core_id);
 
+    // Adjust core id, if it's the default magic.
     auto& kernel = system.Kernel();
+    auto& process = *kernel.CurrentProcess();
+    if (core_id == Svc::IdealCoreUseProcessValue) {
+        core_id = process.GetIdealCoreId();
+    }
+
+    // Validate arguments.
+    R_UNLESS(IsValidCoreId(core_id), Svc::ResultInvalidCoreId);
+    R_UNLESS(((1ULL << core_id) & process.GetCoreMask()) != 0, Svc::ResultInvalidCoreId);
+
+    R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority,
+             Svc::ResultInvalidPriority);
+    R_UNLESS(process.CheckThreadPriority(priority), Svc::ResultInvalidPriority);
 
     ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(ResourceType::Threads, 1));
 
     CASCADE_RESULT(std::shared_ptr<KThread> thread,
                    KThread::Create(system, ThreadType::User, "", entry_point, priority, arg,
-                                   processor_id, stack_top, current_process));
+                                   core_id, stack_bottom, &process));
 
-    const auto new_thread_handle = current_process->GetHandleTable().Create(thread);
+    const auto new_thread_handle = process.GetHandleTable().Create(thread);
     if (new_thread_handle.Failed()) {
         LOG_ERROR(Kernel_SVC, "Failed to create handle with error=0x{:X}",
                   new_thread_handle.Code().raw);
@@ -1872,10 +1858,10 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle,
 
     const auto* const current_process = system.Kernel().CurrentProcess();
 
-    if (core == static_cast<u32>(THREADPROCESSORID_IDEAL)) {
-        const u8 ideal_cpu_core = current_process->GetIdealCore();
+    if (core == static_cast<u32>(Svc::IdealCoreUseProcessValue)) {
+        const u8 ideal_cpu_core = current_process->GetIdealCoreId();
 
-        ASSERT(ideal_cpu_core != static_cast<u8>(THREADPROCESSORID_IDEAL));
+        ASSERT(ideal_cpu_core != static_cast<u8>(Svc::IdealCoreUseProcessValue));
 
         // Set the target CPU to the ideal core specified by the process.
         core = ideal_cpu_core;
@@ -1903,8 +1889,8 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle,
                           affinity_mask);
                 return ERR_INVALID_COMBINATION;
             }
-        } else if (core != static_cast<u32>(THREADPROCESSORID_DONT_CARE) &&
-                   core != static_cast<u32>(THREADPROCESSORID_DONT_UPDATE)) {
+        } else if (core != static_cast<u32>(Svc::IdealCoreDontCare) &&
+                   core != static_cast<u32>(Svc::IdealCoreNoUpdate)) {
             LOG_ERROR(Kernel_SVC, "Invalid processor ID specified (core={}).", core);
             return ERR_INVALID_PROCESSOR_ID;
         }
diff --git a/src/core/hle/kernel/svc_results.h b/src/core/hle/kernel/svc_results.h
index 74adabc11..67bdf5424 100644
--- a/src/core/hle/kernel/svc_results.h
+++ b/src/core/hle/kernel/svc_results.h
@@ -12,6 +12,7 @@ constexpr ResultCode ResultTerminationRequested{ErrorModule::Kernel, 59};
 constexpr ResultCode ResultInvalidAddress{ErrorModule::Kernel, 102};
 constexpr ResultCode ResultInvalidCurrentMemory{ErrorModule::Kernel, 106};
 constexpr ResultCode ResultInvalidPriority{ErrorModule::Kernel, 112};
+constexpr ResultCode ResultInvalidCoreId{ErrorModule::Kernel, 113};
 constexpr ResultCode ResultInvalidHandle{ErrorModule::Kernel, 114};
 constexpr ResultCode ResultTimedOut{ErrorModule::Kernel, 117};
 constexpr ResultCode ResultCancelled{ErrorModule::Kernel, 118};
diff --git a/src/core/hle/kernel/svc_types.h b/src/core/hle/kernel/svc_types.h
index 09b858f2a..8909dbfab 100644
--- a/src/core/hle/kernel/svc_types.h
+++ b/src/core/hle/kernel/svc_types.h
@@ -77,6 +77,10 @@ enum class ArbitrationType : u32 {
     WaitIfEqual = 2,
 };
 
+constexpr inline s32 IdealCoreDontCare = -1;
+constexpr inline s32 IdealCoreUseProcessValue = -2;
+constexpr inline s32 IdealCoreNoUpdate = -3;
+
 constexpr inline s32 LowestThreadPriority = 63;
 constexpr inline s32 HighestThreadPriority = 0;
 
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp
index 0f03f4d90..d6354b01d 100644
--- a/src/yuzu/debugger/wait_tree.cpp
+++ b/src/yuzu/debugger/wait_tree.cpp
@@ -19,6 +19,7 @@
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/readable_event.h"
 #include "core/hle/kernel/svc_common.h"
+#include "core/hle/kernel/svc_types.h"
 #include "core/memory.h"
 
 namespace {
@@ -334,17 +335,11 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
 
     QString processor;
     switch (thread.GetProcessorID()) {
-    case Kernel::ThreadProcessorId::THREADPROCESSORID_IDEAL:
+    case Kernel::Svc::IdealCoreUseProcessValue:
         processor = tr("ideal");
         break;
-    case Kernel::ThreadProcessorId::THREADPROCESSORID_0:
-    case Kernel::ThreadProcessorId::THREADPROCESSORID_1:
-    case Kernel::ThreadProcessorId::THREADPROCESSORID_2:
-    case Kernel::ThreadProcessorId::THREADPROCESSORID_3:
-        processor = tr("core %1").arg(thread.GetProcessorID());
-        break;
     default:
-        processor = tr("Unknown processor %1").arg(thread.GetProcessorID());
+        processor = tr("core %1").arg(thread.GetProcessorID());
         break;
     }
 

From 2fb77adb9f3fca7c4243ffe20df14c45d928fa96 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Fri, 15 Jan 2021 21:52:18 -0800
Subject: [PATCH 08/34] common: common_funcs: Add a few more useful macros for
 kernel code.

---
 src/common/common_funcs.h | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index 75f3027fb..49c36765d 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -101,6 +101,17 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
         }                                                                                          \
     }
 
+#define R_SUCCEEDED(res) (res.IsSuccess())
+
+/// Evaluates an expression that returns a result, and returns the result if it would fail.
+#define R_TRY(res_expr)                                                                            \
+    {                                                                                              \
+        const auto _tmp_r_try_rc = (res_expr);                                                     \
+        if (_tmp_r_try_rc.IsError()) {                                                             \
+            return _tmp_r_try_rc;                                                                  \
+        }                                                                                          \
+    }
+
 namespace Common {
 
 [[nodiscard]] constexpr u32 MakeMagic(char a, char b, char c, char d) {

From 97129bc742cd8972c87c9f087914729419d5b6c8 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Fri, 15 Jan 2021 21:53:56 -0800
Subject: [PATCH 09/34] core: hle: kernel: Implement KThreadQueue.

---
 src/core/CMakeLists.txt              |  1 +
 src/core/hle/kernel/k_thread_queue.h | 81 ++++++++++++++++++++++++++++
 2 files changed, 82 insertions(+)
 create mode 100644 src/core/hle/kernel/k_thread_queue.h

diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 88a31e0f2..843bce150 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -170,6 +170,7 @@ add_library(core STATIC
     hle/kernel/k_synchronization_object.h
     hle/kernel/k_thread.cpp
     hle/kernel/k_thread.h
+    hle/kernel/k_thread_queue.h
     hle/kernel/kernel.cpp
     hle/kernel/kernel.h
     hle/kernel/memory/address_space_info.cpp
diff --git a/src/core/hle/kernel/k_thread_queue.h b/src/core/hle/kernel/k_thread_queue.h
new file mode 100644
index 000000000..c52eba249
--- /dev/null
+++ b/src/core/hle/kernel/k_thread_queue.h
@@ -0,0 +1,81 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/kernel/k_thread.h"
+
+namespace Kernel {
+
+class KThreadQueue {
+public:
+    explicit KThreadQueue(KernelCore& kernel) : kernel{kernel} {}
+
+    bool IsEmpty() const {
+        return wait_list.empty();
+    }
+
+    KThread::WaiterList::iterator begin() {
+        return wait_list.begin();
+    }
+    KThread::WaiterList::iterator end() {
+        return wait_list.end();
+    }
+
+    bool SleepThread(KThread* t) {
+        KScopedSchedulerLock sl{kernel};
+
+        // If the thread needs terminating, don't enqueue it.
+        if (t->IsTerminationRequested()) {
+            return false;
+        }
+
+        // Set the thread's queue and mark it as waiting.
+        t->SetSleepingQueue(this);
+        t->SetState(ThreadState::Waiting);
+
+        // Add the thread to the queue.
+        wait_list.push_back(*t);
+
+        return true;
+    }
+
+    void WakeupThread(KThread* t) {
+        KScopedSchedulerLock sl{kernel};
+
+        // Remove the thread from the queue.
+        wait_list.erase(wait_list.iterator_to(*t));
+
+        // Mark the thread as no longer sleeping.
+        t->SetState(ThreadState::Runnable);
+        t->SetSleepingQueue(nullptr);
+    }
+
+    KThread* WakeupFrontThread() {
+        KScopedSchedulerLock sl{kernel};
+
+        if (wait_list.empty()) {
+            return nullptr;
+        } else {
+            // Remove the thread from the queue.
+            auto it = wait_list.begin();
+            KThread* thread = std::addressof(*it);
+            wait_list.erase(it);
+
+            ASSERT(thread->GetState() == ThreadState::Waiting);
+
+            // Mark the thread as no longer sleeping.
+            thread->SetState(ThreadState::Runnable);
+            thread->SetSleepingQueue(nullptr);
+
+            return thread;
+        }
+    }
+
+private:
+    KernelCore& kernel;
+    KThread::WaiterList wait_list{};
+};
+
+} // namespace Kernel

From 5a4fc4a5299a3835a57ae8a35c6de51459df70c0 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Fri, 15 Jan 2021 21:58:44 -0800
Subject: [PATCH 10/34] core: hle: kernel: Implement KLightLock.

---
 src/core/CMakeLists.txt              |   2 +
 src/core/hle/kernel/k_light_lock.cpp | 130 +++++++++++++++++++++++++++
 src/core/hle/kernel/k_light_lock.h   |  41 +++++++++
 3 files changed, 173 insertions(+)
 create mode 100644 src/core/hle/kernel/k_light_lock.cpp
 create mode 100644 src/core/hle/kernel/k_light_lock.h

diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 843bce150..397cc028f 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -160,6 +160,8 @@ add_library(core STATIC
     hle/kernel/k_affinity_mask.h
     hle/kernel/k_condition_variable.cpp
     hle/kernel/k_condition_variable.h
+    hle/kernel/k_light_lock.cpp
+    hle/kernel/k_light_lock.h
     hle/kernel/k_priority_queue.h
     hle/kernel/k_scheduler.cpp
     hle/kernel/k_scheduler.h
diff --git a/src/core/hle/kernel/k_light_lock.cpp b/src/core/hle/kernel/k_light_lock.cpp
new file mode 100644
index 000000000..08fa65fd5
--- /dev/null
+++ b/src/core/hle/kernel/k_light_lock.cpp
@@ -0,0 +1,130 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/kernel/k_light_lock.h"
+#include "core/hle/kernel/k_scheduler.h"
+#include "core/hle/kernel/k_thread.h"
+#include "core/hle/kernel/kernel.h"
+
+namespace Kernel {
+
+void KLightLock::Lock() {
+    const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel));
+    const uintptr_t cur_thread_tag = (cur_thread | 1);
+
+    while (true) {
+        uintptr_t old_tag = tag.load(std::memory_order_relaxed);
+
+        while (!tag.compare_exchange_weak(old_tag, (old_tag == 0) ? cur_thread : old_tag | 1,
+                                          std::memory_order_acquire)) {
+            if ((old_tag | 1) == cur_thread_tag) {
+                return;
+            }
+        }
+
+        if ((old_tag == 0) || ((old_tag | 1) == cur_thread_tag)) {
+            break;
+        }
+
+        LockSlowPath(old_tag | 1, cur_thread);
+    }
+}
+
+void KLightLock::Unlock() {
+    const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel));
+    uintptr_t expected = cur_thread;
+    do {
+        if (expected != cur_thread) {
+            return UnlockSlowPath(cur_thread);
+        }
+    } while (!tag.compare_exchange_weak(expected, 0, std::memory_order_release));
+}
+
+void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {
+    KThread* cur_thread = reinterpret_cast<KThread*>(_cur_thread);
+
+    // Pend the current thread waiting on the owner thread.
+    {
+        KScopedSchedulerLock sl{kernel};
+
+        // Ensure we actually have locking to do.
+        if (tag.load(std::memory_order_relaxed) != _owner) {
+            return;
+        }
+
+        // Add the current thread as a waiter on the owner.
+        KThread* owner_thread = reinterpret_cast<KThread*>(_owner & ~1ul);
+        cur_thread->SetAddressKey(reinterpret_cast<uintptr_t>(std::addressof(tag)));
+        owner_thread->AddWaiter(cur_thread);
+
+        // Set thread states.
+        if (cur_thread->GetState() == ThreadState::Runnable) {
+            cur_thread->SetState(ThreadState::Waiting);
+        } else {
+            KScheduler::SetSchedulerUpdateNeeded(kernel);
+        }
+
+        if (owner_thread->IsSuspended()) {
+            owner_thread->ContinueIfHasKernelWaiters();
+            KScheduler::SetSchedulerUpdateNeeded(kernel);
+        }
+    }
+
+    // We're no longer waiting on the lock owner.
+    {
+        KScopedSchedulerLock sl{kernel};
+        KThread* owner_thread = cur_thread->GetLockOwner();
+        if (owner_thread) {
+            owner_thread->RemoveWaiter(cur_thread);
+        }
+    }
+}
+
+void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) {
+    KThread* owner_thread = reinterpret_cast<KThread*>(_cur_thread);
+
+    // Unlock.
+    {
+        KScopedSchedulerLock sl{kernel};
+
+        // Get the next owner.
+        s32 num_waiters = 0;
+        KThread* next_owner = owner_thread->RemoveWaiterByKey(
+            std::addressof(num_waiters), reinterpret_cast<uintptr_t>(std::addressof(tag)));
+
+        // Pass the lock to the next owner.
+        uintptr_t next_tag = 0;
+        if (next_owner) {
+            next_tag = reinterpret_cast<uintptr_t>(next_owner);
+            if (num_waiters > 1) {
+                next_tag |= 0x1;
+            }
+
+            if (next_owner->GetState() == ThreadState::Waiting) {
+                next_owner->SetState(ThreadState::Runnable);
+            } else {
+                KScheduler::SetSchedulerUpdateNeeded(kernel);
+            }
+
+            if (next_owner->IsSuspended()) {
+                next_owner->ContinueIfHasKernelWaiters();
+            }
+        }
+
+        // We may have unsuspended in the process of acquiring the lock, so we'll re-suspend now if
+        // so.
+        if (owner_thread->IsSuspended()) {
+            owner_thread->TrySuspend();
+        }
+
+        // Write the new tag value.
+        tag.store(next_tag);
+    }
+}
+
+bool KLightLock::IsLockedByCurrentThread() const {
+    return (tag | 0x1ul) == (reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel)) | 0x1ul);
+}
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_light_lock.h b/src/core/hle/kernel/k_light_lock.h
new file mode 100644
index 000000000..f4c45f76a
--- /dev/null
+++ b/src/core/hle/kernel/k_light_lock.h
@@ -0,0 +1,41 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <atomic>
+
+#include "common/common_types.h"
+#include "core/hle/kernel/k_scoped_lock.h"
+
+namespace Kernel {
+
+class KernelCore;
+
+class KLightLock {
+public:
+    explicit KLightLock(KernelCore& kernel_) : kernel{kernel_} {}
+
+    void Lock();
+
+    void Unlock();
+
+    void LockSlowPath(uintptr_t owner, uintptr_t cur_thread);
+
+    void UnlockSlowPath(uintptr_t cur_thread);
+
+    bool IsLocked() const {
+        return tag != 0;
+    }
+
+    bool IsLockedByCurrentThread() const;
+
+private:
+    std::atomic<uintptr_t> tag{};
+    KernelCore& kernel;
+};
+
+using KScopedLightLock = KScopedLock<KLightLock>;
+
+} // namespace Kernel

From 33b493028029c81385d8b8a4864b62da2ed523d5 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Fri, 15 Jan 2021 22:02:33 -0800
Subject: [PATCH 11/34] core: hle: kernel: svc_results: Populate with several
 missing error codes.

---
 src/core/hle/kernel/svc_results.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/core/hle/kernel/svc_results.h b/src/core/hle/kernel/svc_results.h
index 67bdf5424..7b897fbce 100644
--- a/src/core/hle/kernel/svc_results.h
+++ b/src/core/hle/kernel/svc_results.h
@@ -8,15 +8,18 @@
 
 namespace Kernel::Svc {
 
+constexpr ResultCode ResultNoSynchronizationObject{ErrorModule::Kernel, 57};
 constexpr ResultCode ResultTerminationRequested{ErrorModule::Kernel, 59};
 constexpr ResultCode ResultInvalidAddress{ErrorModule::Kernel, 102};
 constexpr ResultCode ResultInvalidCurrentMemory{ErrorModule::Kernel, 106};
 constexpr ResultCode ResultInvalidPriority{ErrorModule::Kernel, 112};
 constexpr ResultCode ResultInvalidCoreId{ErrorModule::Kernel, 113};
 constexpr ResultCode ResultInvalidHandle{ErrorModule::Kernel, 114};
+constexpr ResultCode ResultInvalidCombination{ErrorModule::Kernel, 116};
 constexpr ResultCode ResultTimedOut{ErrorModule::Kernel, 117};
 constexpr ResultCode ResultCancelled{ErrorModule::Kernel, 118};
 constexpr ResultCode ResultInvalidEnumValue{ErrorModule::Kernel, 120};
+constexpr ResultCode ResultBusy{ErrorModule::Kernel, 122};
 constexpr ResultCode ResultInvalidState{ErrorModule::Kernel, 125};
 
 } // namespace Kernel::Svc

From ff186b2498e5f3119e0d03a859754722e1948c62 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Sat, 16 Jan 2021 00:25:29 -0800
Subject: [PATCH 12/34] core: hle: kernel: object: Implement Finalize() virtual
 method.

---
 src/core/hle/kernel/client_port.h                | 2 ++
 src/core/hle/kernel/client_session.h             | 2 ++
 src/core/hle/kernel/handle_table.cpp             | 4 ++++
 src/core/hle/kernel/k_synchronization_object.cpp | 2 +-
 src/core/hle/kernel/object.h                     | 2 ++
 src/core/hle/kernel/process.h                    | 2 ++
 src/core/hle/kernel/readable_event.h             | 2 ++
 src/core/hle/kernel/resource_limit.h             | 2 ++
 src/core/hle/kernel/server_port.h                | 2 ++
 src/core/hle/kernel/server_session.h             | 2 ++
 src/core/hle/kernel/session.h                    | 2 ++
 src/core/hle/kernel/shared_memory.h              | 2 ++
 src/core/hle/kernel/transfer_memory.h            | 2 ++
 src/core/hle/kernel/writable_event.cpp           | 4 ----
 src/core/hle/kernel/writable_event.h             | 3 ++-
 15 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h
index 9762bbf0d..77559ebf9 100644
--- a/src/core/hle/kernel/client_port.h
+++ b/src/core/hle/kernel/client_port.h
@@ -51,6 +51,8 @@ public:
      */
     void ConnectionClosed();
 
+    void Finalize() override {}
+
 private:
     std::shared_ptr<ServerPort> server_port; ///< ServerPort associated with this client port.
     u32 max_sessions = 0;    ///< Maximum number of simultaneous sessions the port can have
diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h
index a914c0990..85aafeaf4 100644
--- a/src/core/hle/kernel/client_session.h
+++ b/src/core/hle/kernel/client_session.h
@@ -51,6 +51,8 @@ public:
 
     bool IsSignaled() const override;
 
+    void Finalize() override {}
+
 private:
     static ResultVal<std::shared_ptr<ClientSession>> Create(KernelCore& kernel,
                                                             std::shared_ptr<Session> parent,
diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp
index 10a4e0510..1a2fa9cd8 100644
--- a/src/core/hle/kernel/handle_table.cpp
+++ b/src/core/hle/kernel/handle_table.cpp
@@ -89,6 +89,10 @@ ResultCode HandleTable::Close(Handle handle) {
 
     const u16 slot = GetSlot(handle);
 
+    if (objects[slot].use_count() == 1) {
+        objects[slot]->Finalize();
+    }
+
     objects[slot] = nullptr;
 
     generations[slot] = next_free_slot;
diff --git a/src/core/hle/kernel/k_synchronization_object.cpp b/src/core/hle/kernel/k_synchronization_object.cpp
index 61432fef8..18e7026f5 100644
--- a/src/core/hle/kernel/k_synchronization_object.cpp
+++ b/src/core/hle/kernel/k_synchronization_object.cpp
@@ -136,7 +136,7 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index,
 
 KSynchronizationObject::KSynchronizationObject(KernelCore& kernel) : Object{kernel} {}
 
-KSynchronizationObject ::~KSynchronizationObject() = default;
+KSynchronizationObject::~KSynchronizationObject() = default;
 
 void KSynchronizationObject::NotifyAvailable(ResultCode result) {
     KScopedSchedulerLock lock(kernel);
diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h
index 27124ef67..be7fcb5fb 100644
--- a/src/core/hle/kernel/object.h
+++ b/src/core/hle/kernel/object.h
@@ -61,6 +61,8 @@ public:
      */
     bool IsWaitable() const;
 
+    virtual void Finalize() = 0;
+
 protected:
     /// The kernel instance this object was created under.
     KernelCore& kernel;
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 5a2cfdb36..917babfb4 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -308,6 +308,8 @@ public:
 
     bool IsSignaled() const override;
 
+    void Finalize() override {}
+
     ///////////////////////////////////////////////////////////////////////////////////////////////
     // Thread-local storage management
 
diff --git a/src/core/hle/kernel/readable_event.h b/src/core/hle/kernel/readable_event.h
index 34e477274..2195710c2 100644
--- a/src/core/hle/kernel/readable_event.h
+++ b/src/core/hle/kernel/readable_event.h
@@ -47,6 +47,8 @@ public:
 
     bool IsSignaled() const override;
 
+    void Finalize() override {}
+
 private:
     explicit ReadableEvent(KernelCore& kernel);
 
diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h
index 936cc4d0f..464d4f2a6 100644
--- a/src/core/hle/kernel/resource_limit.h
+++ b/src/core/hle/kernel/resource_limit.h
@@ -85,6 +85,8 @@ public:
      */
     ResultCode SetLimitValue(ResourceType resource, s64 value);
 
+    void Finalize() override {}
+
 private:
     // TODO(Subv): Increment resource limit current values in their respective Kernel::T::Create
     // functions
diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h
index 6470df993..29b4f2509 100644
--- a/src/core/hle/kernel/server_port.h
+++ b/src/core/hle/kernel/server_port.h
@@ -81,6 +81,8 @@ public:
 
     bool IsSignaled() const override;
 
+    void Finalize() override {}
+
 private:
     /// ServerSessions waiting to be accepted by the port
     std::vector<std::shared_ptr<ServerSession>> pending_sessions;
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index d45cddec3..c42d5ee59 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -126,6 +126,8 @@ public:
 
     bool IsSignaled() const override;
 
+    void Finalize() override {}
+
 private:
     /// Queues a sync request from the emulated application.
     ResultCode QueueSyncRequest(std::shared_ptr<KThread> thread, Core::Memory::Memory& memory);
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h
index f6dd2c1d2..fa3c5651a 100644
--- a/src/core/hle/kernel/session.h
+++ b/src/core/hle/kernel/session.h
@@ -39,6 +39,8 @@ public:
 
     bool IsSignaled() const override;
 
+    void Finalize() override {}
+
     std::shared_ptr<ClientSession> Client() {
         if (auto result{client.lock()}) {
             return result;
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 0ef87235c..623bd8b11 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -71,6 +71,8 @@ public:
         return device_memory.GetPointer(physical_address + offset);
     }
 
+    void Finalize() override {}
+
 private:
     Core::DeviceMemory& device_memory;
     Process* owner_process{};
diff --git a/src/core/hle/kernel/transfer_memory.h b/src/core/hle/kernel/transfer_memory.h
index 05e9f7464..777799d12 100644
--- a/src/core/hle/kernel/transfer_memory.h
+++ b/src/core/hle/kernel/transfer_memory.h
@@ -72,6 +72,8 @@ public:
     /// is closed.
     ResultCode Reset();
 
+    void Finalize() override {}
+
 private:
     /// The base address for the memory managed by this instance.
     VAddr base_address{};
diff --git a/src/core/hle/kernel/writable_event.cpp b/src/core/hle/kernel/writable_event.cpp
index dbe34472b..142212ee4 100644
--- a/src/core/hle/kernel/writable_event.cpp
+++ b/src/core/hle/kernel/writable_event.cpp
@@ -38,8 +38,4 @@ void WritableEvent::Clear() {
     readable->Clear();
 }
 
-bool WritableEvent::IsSignaled() const {
-    return readable->IsSignaled();
-}
-
 } // namespace Kernel
diff --git a/src/core/hle/kernel/writable_event.h b/src/core/hle/kernel/writable_event.h
index 6189cf65c..467eb2c21 100644
--- a/src/core/hle/kernel/writable_event.h
+++ b/src/core/hle/kernel/writable_event.h
@@ -46,7 +46,8 @@ public:
 
     void Signal();
     void Clear();
-    bool IsSignaled() const;
+
+    void Finalize() override {}
 
 private:
     explicit WritableEvent(KernelCore& kernel);

From bb966d3e336ce1eee86daca5db00b29a63708d4c Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Tue, 19 Jan 2021 20:53:11 -0800
Subject: [PATCH 13/34] common: common_funcs: Add useful kernel macro
 R_SUCCEED_IF.

---
 src/common/common_funcs.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index 49c36765d..842d62ca7 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -112,6 +112,9 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
         }                                                                                          \
     }
 
+/// Evaluates a boolean expression, and succeeds if that expression is true.
+#define R_SUCCEED_IF(expr) R_UNLESS(!(expr), RESULT_SUCCESS)
+
 namespace Common {
 
 [[nodiscard]] constexpr u32 MakeMagic(char a, char b, char c, char d) {

From c0f5830323ca5d5bdc2e5e494fcaeaf27fffeb6b Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Tue, 19 Jan 2021 21:05:24 -0800
Subject: [PATCH 14/34] hle: kernel: TimeManager: Simplify to not rely on
 previous EmuThreadHandle implementation.

---
 src/core/hle/kernel/k_address_arbiter.cpp     | 16 ++------
 src/core/hle/kernel/k_condition_variable.cpp  |  8 +---
 .../k_scoped_scheduler_lock_and_sleep.h       | 14 +++----
 .../hle/kernel/k_synchronization_object.cpp   |  8 +---
 src/core/hle/kernel/time_manager.cpp          | 40 +++++--------------
 src/core/hle/kernel/time_manager.h            |  8 +---
 6 files changed, 25 insertions(+), 69 deletions(-)

diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp
index 282f02257..1685d25bb 100644
--- a/src/core/hle/kernel/k_address_arbiter.cpp
+++ b/src/core/hle/kernel/k_address_arbiter.cpp
@@ -232,10 +232,9 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32
 ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement, s64 timeout) {
     // Prepare to wait.
     KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread();
-    Handle timer = InvalidHandle;
 
     {
-        KScopedSchedulerLockAndSleep slp(kernel, timer, cur_thread, timeout);
+        KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout};
 
         // Check that the thread isn't terminating.
         if (cur_thread->IsTerminationRequested()) {
@@ -280,10 +279,7 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement
     }
 
     // Cancel the timer wait.
-    if (timer != InvalidHandle) {
-        auto& time_manager = kernel.TimeManager();
-        time_manager.UnscheduleTimeEvent(timer);
-    }
+    kernel.TimeManager().UnscheduleTimeEvent(cur_thread);
 
     // Remove from the address arbiter.
     {
@@ -303,10 +299,9 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement
 ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) {
     // Prepare to wait.
     KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread();
-    Handle timer = InvalidHandle;
 
     {
-        KScopedSchedulerLockAndSleep slp(kernel, timer, cur_thread, timeout);
+        KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout};
 
         // Check that the thread isn't terminating.
         if (cur_thread->IsTerminationRequested()) {
@@ -344,10 +339,7 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) {
     }
 
     // Cancel the timer wait.
-    if (timer != InvalidHandle) {
-        auto& time_manager = kernel.TimeManager();
-        time_manager.UnscheduleTimeEvent(timer);
-    }
+    kernel.TimeManager().UnscheduleTimeEvent(cur_thread);
 
     // Remove from the address arbiter.
     {
diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp
index 2fa2d5289..f0ad8b390 100644
--- a/src/core/hle/kernel/k_condition_variable.cpp
+++ b/src/core/hle/kernel/k_condition_variable.cpp
@@ -258,10 +258,9 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {
 ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) {
     // Prepare to wait.
     KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread();
-    Handle timer = InvalidHandle;
 
     {
-        KScopedSchedulerLockAndSleep slp(kernel, timer, cur_thread, timeout);
+        KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout};
 
         // Set the synced object.
         cur_thread->SetSyncedObject(nullptr, Svc::ResultTimedOut);
@@ -322,10 +321,7 @@ ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout)
     }
 
     // Cancel the timer wait.
-    if (timer != InvalidHandle) {
-        auto& time_manager = kernel.TimeManager();
-        time_manager.UnscheduleTimeEvent(timer);
-    }
+    kernel.TimeManager().UnscheduleTimeEvent(cur_thread);
 
     // Remove from the condition variable.
     {
diff --git a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h
index fac39aeb7..f8189e107 100644
--- a/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h
+++ b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h
@@ -17,19 +17,16 @@ namespace Kernel {
 
 class KScopedSchedulerLockAndSleep {
 public:
-    explicit KScopedSchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, KThread* t,
-                                          s64 timeout)
-        : kernel(kernel), event_handle(event_handle), thread(t), timeout_tick(timeout) {
-        event_handle = InvalidHandle;
-
+    explicit KScopedSchedulerLockAndSleep(KernelCore& kernel, KThread* t, s64 timeout)
+        : kernel(kernel), thread(t), timeout_tick(timeout) {
         // Lock the scheduler.
         kernel.GlobalSchedulerContext().scheduler_lock.Lock();
     }
 
     ~KScopedSchedulerLockAndSleep() {
         // Register the sleep.
-        if (this->timeout_tick > 0) {
-            kernel.TimeManager().ScheduleTimeEvent(event_handle, this->thread, this->timeout_tick);
+        if (timeout_tick > 0) {
+            kernel.TimeManager().ScheduleTimeEvent(thread, timeout_tick);
         }
 
         // Unlock the scheduler.
@@ -37,12 +34,11 @@ public:
     }
 
     void CancelSleep() {
-        this->timeout_tick = 0;
+        timeout_tick = 0;
     }
 
 private:
     KernelCore& kernel;
-    Handle& event_handle;
     KThread* thread{};
     s64 timeout_tick{};
 };
diff --git a/src/core/hle/kernel/k_synchronization_object.cpp b/src/core/hle/kernel/k_synchronization_object.cpp
index 18e7026f5..a3b34f82f 100644
--- a/src/core/hle/kernel/k_synchronization_object.cpp
+++ b/src/core/hle/kernel/k_synchronization_object.cpp
@@ -21,11 +21,10 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index,
 
     // Prepare for wait.
     KThread* thread = kernel.CurrentScheduler()->GetCurrentThread();
-    Handle timer = InvalidHandle;
 
     {
         // Setup the scheduling lock and sleep.
-        KScopedSchedulerLockAndSleep slp(kernel, timer, thread, timeout);
+        KScopedSchedulerLockAndSleep slp{kernel, thread, timeout};
 
         // Check if any of the objects are already signaled.
         for (auto i = 0; i < num_objects; ++i) {
@@ -90,10 +89,7 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index,
     thread->SetWaitObjectsForDebugging({});
 
     // Cancel the timer as needed.
-    if (timer != InvalidHandle) {
-        auto& time_manager = kernel.TimeManager();
-        time_manager.UnscheduleTimeEvent(timer);
-    }
+    kernel.TimeManager().UnscheduleTimeEvent(thread);
 
     // Get the wait result.
     ResultCode wait_result{RESULT_SUCCESS};
diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp
index aaeef3033..fd0630019 100644
--- a/src/core/hle/kernel/time_manager.cpp
+++ b/src/core/hle/kernel/time_manager.cpp
@@ -21,47 +21,27 @@ TimeManager::TimeManager(Core::System& system_) : system{system_} {
             std::shared_ptr<KThread> thread;
             {
                 std::lock_guard lock{mutex};
-                const auto proper_handle = static_cast<Handle>(thread_handle);
-                if (cancelled_events[proper_handle]) {
-                    return;
-                }
-                thread = system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle);
-            }
-
-            if (thread) {
-                // Thread can be null if process has exited
-                thread->Wakeup();
+                thread = SharedFrom<KThread>(reinterpret_cast<KThread*>(thread_handle));
             }
+            thread->Wakeup();
         });
 }
 
-void TimeManager::ScheduleTimeEvent(Handle& event_handle, KThread* timetask, s64 nanoseconds) {
+void TimeManager::ScheduleTimeEvent(KThread* thread, s64 nanoseconds) {
     std::lock_guard lock{mutex};
-    event_handle = timetask->GetGlobalHandle();
     if (nanoseconds > 0) {
-        ASSERT(timetask);
-        ASSERT(timetask->GetState() != ThreadState::Runnable);
+        ASSERT(thread);
+        ASSERT(thread->GetState() != ThreadState::Runnable);
         system.CoreTiming().ScheduleEvent(std::chrono::nanoseconds{nanoseconds},
-                                          time_manager_event_type, event_handle);
-    } else {
-        event_handle = InvalidHandle;
+                                          time_manager_event_type,
+                                          reinterpret_cast<uintptr_t>(thread));
     }
-    cancelled_events[event_handle] = false;
 }
 
-void TimeManager::UnscheduleTimeEvent(Handle event_handle) {
+void TimeManager::UnscheduleTimeEvent(KThread* thread) {
     std::lock_guard lock{mutex};
-    if (event_handle == InvalidHandle) {
-        return;
-    }
-    system.CoreTiming().UnscheduleEvent(time_manager_event_type, event_handle);
-    cancelled_events[event_handle] = true;
-}
-
-void TimeManager::CancelTimeEvent(KThread* time_task) {
-    std::lock_guard lock{mutex};
-    const Handle event_handle = time_task->GetGlobalHandle();
-    UnscheduleTimeEvent(event_handle);
+    system.CoreTiming().UnscheduleEvent(time_manager_event_type,
+                                        reinterpret_cast<uintptr_t>(thread));
 }
 
 } // namespace Kernel
diff --git a/src/core/hle/kernel/time_manager.h b/src/core/hle/kernel/time_manager.h
index 7cc702bec..0d7f05f30 100644
--- a/src/core/hle/kernel/time_manager.h
+++ b/src/core/hle/kernel/time_manager.h
@@ -31,18 +31,14 @@ public:
     explicit TimeManager(Core::System& system);
 
     /// Schedule a time event on `timetask` thread that will expire in 'nanoseconds'
-    /// returns a non-invalid handle in `event_handle` if correctly scheduled
-    void ScheduleTimeEvent(Handle& event_handle, KThread* timetask, s64 nanoseconds);
+    void ScheduleTimeEvent(KThread* time_task, s64 nanoseconds);
 
     /// Unschedule an existing time event
-    void UnscheduleTimeEvent(Handle event_handle);
-
-    void CancelTimeEvent(KThread* time_task);
+    void UnscheduleTimeEvent(KThread* thread);
 
 private:
     Core::System& system;
     std::shared_ptr<Core::Timing::EventType> time_manager_event_type;
-    std::unordered_map<Handle, bool> cancelled_events;
     std::mutex mutex;
 };
 

From 1f99f5473c7a03c791ea20256c7fc2f1caba8adc Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Tue, 19 Jan 2021 21:07:07 -0800
Subject: [PATCH 15/34] kernel: k_light_lock: Simplify EmuThreadHandle
 implementation.

---
 src/core/hardware_properties.h         | 36 ++++++--------------------
 src/core/hle/kernel/k_light_lock.cpp   | 12 ++++++---
 src/core/hle/kernel/k_scheduler_lock.h |  9 +++----
 src/core/hle/kernel/kernel.cpp         | 21 +++++----------
 src/core/hle/kernel/kernel.h           |  6 ++++-
 5 files changed, 33 insertions(+), 51 deletions(-)

diff --git a/src/core/hardware_properties.h b/src/core/hardware_properties.h
index 456b41e1b..176a72c67 100644
--- a/src/core/hardware_properties.h
+++ b/src/core/hardware_properties.h
@@ -4,8 +4,10 @@
 
 #pragma once
 
+#include <array>
 #include <tuple>
 
+#include "common/bit_util.h"
 #include "common/common_types.h"
 
 namespace Core {
@@ -18,34 +20,12 @@ constexpr u64 BASE_CLOCK_RATE = 1019215872; // Switch cpu frequency is 1020MHz u
 constexpr u64 CNTFREQ = 19200000;           // Switch's hardware clock speed
 constexpr u32 NUM_CPU_CORES = 4;            // Number of CPU Cores
 
-} // namespace Hardware
-
-constexpr u32 INVALID_HOST_THREAD_ID = 0xFFFFFFFF;
-
-struct EmuThreadHandle {
-    u32 host_handle;
-    u32 guest_handle;
-
-    u64 GetRaw() const {
-        return (static_cast<u64>(host_handle) << 32) | guest_handle;
-    }
-
-    bool operator==(const EmuThreadHandle& rhs) const {
-        return std::tie(host_handle, guest_handle) == std::tie(rhs.host_handle, rhs.guest_handle);
-    }
-
-    bool operator!=(const EmuThreadHandle& rhs) const {
-        return !operator==(rhs);
-    }
-
-    static constexpr EmuThreadHandle InvalidHandle() {
-        constexpr u32 invalid_handle = 0xFFFFFFFF;
-        return {invalid_handle, invalid_handle};
-    }
-
-    bool IsInvalid() const {
-        return (*this) == InvalidHandle();
-    }
+// Virtual to Physical core map.
+constexpr std::array<s32, Common::BitSize<u64>()> VirtualToPhysicalCoreMap{
+    0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
 };
 
+} // namespace Hardware
+
 } // namespace Core
diff --git a/src/core/hle/kernel/k_light_lock.cpp b/src/core/hle/kernel/k_light_lock.cpp
index 08fa65fd5..1d54ba5df 100644
--- a/src/core/hle/kernel/k_light_lock.cpp
+++ b/src/core/hle/kernel/k_light_lock.cpp
@@ -9,6 +9,12 @@
 
 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);
@@ -42,7 +48,7 @@ void KLightLock::Unlock() {
 }
 
 void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {
-    KThread* cur_thread = reinterpret_cast<KThread*>(_cur_thread);
+    KThread* cur_thread = ToThread(_cur_thread);
 
     // Pend the current thread waiting on the owner thread.
     {
@@ -54,7 +60,7 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {
         }
 
         // Add the current thread as a waiter on the owner.
-        KThread* owner_thread = reinterpret_cast<KThread*>(_owner & ~1ul);
+        KThread* owner_thread = ToThread(_owner & ~1ul);
         cur_thread->SetAddressKey(reinterpret_cast<uintptr_t>(std::addressof(tag)));
         owner_thread->AddWaiter(cur_thread);
 
@@ -82,7 +88,7 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {
 }
 
 void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) {
-    KThread* owner_thread = reinterpret_cast<KThread*>(_cur_thread);
+    KThread* owner_thread = ToThread(_cur_thread);
 
     // Unlock.
     {
diff --git a/src/core/hle/kernel/k_scheduler_lock.h b/src/core/hle/kernel/k_scheduler_lock.h
index 9b40bd22c..5d48dcf38 100644
--- a/src/core/hle/kernel/k_scheduler_lock.h
+++ b/src/core/hle/kernel/k_scheduler_lock.h
@@ -37,7 +37,7 @@ public:
 
             // For debug, ensure that our state is valid.
             ASSERT(this->lock_count == 0);
-            ASSERT(this->owner_thread == Core::EmuThreadHandle::InvalidHandle());
+            ASSERT(this->owner_thread == EmuThreadHandleInvalid);
 
             // Increment count, take ownership.
             this->lock_count = 1;
@@ -54,14 +54,13 @@ public:
             // We're no longer going to hold the lock. Take note of what cores need scheduling.
             const u64 cores_needing_scheduling =
                 SchedulerType::UpdateHighestPriorityThreads(kernel);
-            Core::EmuThreadHandle leaving_thread = owner_thread;
 
             // Note that we no longer hold the lock, and unlock the spinlock.
-            this->owner_thread = Core::EmuThreadHandle::InvalidHandle();
+            this->owner_thread = EmuThreadHandleInvalid;
             this->spin_lock.unlock();
 
             // Enable scheduling, and perform a rescheduling operation.
-            SchedulerType::EnableScheduling(kernel, cores_needing_scheduling, leaving_thread);
+            SchedulerType::EnableScheduling(kernel, cores_needing_scheduling);
         }
     }
 
@@ -69,7 +68,7 @@ private:
     KernelCore& kernel;
     Common::SpinLock spin_lock{};
     s32 lock_count{};
-    Core::EmuThreadHandle owner_thread{Core::EmuThreadHandle::InvalidHandle()};
+    EmuThreadHandle owner_thread{EmuThreadHandleInvalid};
 };
 
 } // namespace Kernel
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 97a5dc2e0..39d5122f5 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -237,20 +237,13 @@ struct KernelCore::Impl {
         is_phantom_mode_for_singlecore = value;
     }
 
-    [[nodiscard]] Core::EmuThreadHandle GetCurrentEmuThreadID() {
-        Core::EmuThreadHandle result = Core::EmuThreadHandle::InvalidHandle();
-        result.host_handle = GetCurrentHostThreadID();
-        if (result.host_handle >= Core::Hardware::NUM_CPU_CORES) {
-            return result;
+    [[nodiscard]] EmuThreadHandle GetCurrentEmuThreadID() {
+        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);
         }
-        const Kernel::KScheduler& sched = cores[result.host_handle].Scheduler();
-        const Kernel::KThread* current = sched.GetCurrentThread();
-        if (current != nullptr && !IsPhantomModeForSingleCore()) {
-            result.guest_handle = current->GetGlobalHandle();
-        } else {
-            result.guest_handle = InvalidHandle;
-        }
-        return result;
+        return reinterpret_cast<uintptr_t>(schedulers[thread_id].get());
     }
 
     void InitializeMemoryLayout() {
@@ -555,7 +548,7 @@ u32 KernelCore::GetCurrentHostThreadID() const {
     return impl->GetCurrentHostThreadID();
 }
 
-Core::EmuThreadHandle KernelCore::GetCurrentEmuThreadID() const {
+EmuThreadHandle KernelCore::GetCurrentEmuThreadID() const {
     return impl->GetCurrentEmuThreadID();
 }
 
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index fc58f3ecb..b92c017f6 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -46,6 +46,10 @@ class Synchronization;
 class KThread;
 class TimeManager;
 
+using EmuThreadHandle = uintptr_t;
+constexpr EmuThreadHandle EmuThreadHandleInvalid{};
+constexpr EmuThreadHandle EmuThreadHandleReserved{1ULL << 63};
+
 /// Represents a single instance of the kernel.
 class KernelCore {
 private:
@@ -162,7 +166,7 @@ public:
     bool IsValidNamedPort(NamedPortTable::const_iterator port) const;
 
     /// Gets the current host_thread/guest_thread handle.
-    Core::EmuThreadHandle GetCurrentEmuThreadID() const;
+    EmuThreadHandle GetCurrentEmuThreadID() const;
 
     /// Gets the current host_thread handle.
     u32 GetCurrentHostThreadID() const;

From 1772ebeb1e45240fd731e461a4c74eab8ec37c84 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Tue, 19 Jan 2021 21:08:35 -0800
Subject: [PATCH 16/34] kernel: KSchedulerPriorityQueue: Lowest priority should
 be LowestThreadPriority.

---
 src/core/hle/kernel/global_scheduler_context.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/core/hle/kernel/global_scheduler_context.h b/src/core/hle/kernel/global_scheduler_context.h
index 0f7b9a61c..11592843e 100644
--- a/src/core/hle/kernel/global_scheduler_context.h
+++ b/src/core/hle/kernel/global_scheduler_context.h
@@ -21,7 +21,7 @@ class KernelCore;
 class SchedulerLock;
 
 using KSchedulerPriorityQueue =
-    KPriorityQueue<KThread, Core::Hardware::NUM_CPU_CORES, Svc::LowestThreadPriority + 1,
+    KPriorityQueue<KThread, Core::Hardware::NUM_CPU_CORES, Svc::LowestThreadPriority,
                    Svc::HighestThreadPriority>;
 
 static constexpr s32 HighestCoreMigrationAllowedPriority = 2;

From 14703384582dbd7ba53970e1b60eae37235dce8a Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Tue, 19 Jan 2021 21:11:23 -0800
Subject: [PATCH 17/34] kernel: svc_types: Add ThreadActivity.

---
 src/core/hle/kernel/svc_types.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/core/hle/kernel/svc_types.h b/src/core/hle/kernel/svc_types.h
index 8909dbfab..ded55af9a 100644
--- a/src/core/hle/kernel/svc_types.h
+++ b/src/core/hle/kernel/svc_types.h
@@ -77,6 +77,11 @@ enum class ArbitrationType : u32 {
     WaitIfEqual = 2,
 };
 
+enum class ThreadActivity : u32 {
+    Runnable = 0,
+    Paused = 1,
+};
+
 constexpr inline s32 IdealCoreDontCare = -1;
 constexpr inline s32 IdealCoreUseProcessValue = -2;
 constexpr inline s32 IdealCoreNoUpdate = -3;

From cdd14b03e5c8e29bc6cd11bbde0ef726d2f166ce Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Wed, 20 Jan 2021 13:42:27 -0800
Subject: [PATCH 18/34] hle: kernel: Recode implementation of KThread to be
 more accurate.

---
 src/core/cpu_manager.cpp               |    3 +-
 src/core/hle/kernel/hle_ipc.h          |    3 -
 src/core/hle/kernel/k_scheduler.cpp    |  144 ++--
 src/core/hle/kernel/k_scheduler.h      |   24 +-
 src/core/hle/kernel/k_thread.cpp       | 1025 +++++++++++++++++++-----
 src/core/hle/kernel/k_thread.h         |  596 +++++++-------
 src/core/hle/kernel/kernel.cpp         |   10 +-
 src/core/hle/kernel/process.cpp        |   74 +-
 src/core/hle/kernel/process.h          |   63 ++
 src/core/hle/kernel/server_session.cpp |    2 +-
 src/core/hle/kernel/svc.cpp            |  359 ++++-----
 src/core/hle/kernel/svc_types.h        |    6 +
 src/core/hle/kernel/svc_wrap.h         |   56 +-
 src/yuzu/debugger/wait_tree.cpp        |   24 +-
 14 files changed, 1583 insertions(+), 806 deletions(-)

diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index 719258250..9bbb82b97 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -279,8 +279,7 @@ void CpuManager::PreemptSingleCore(bool from_running_enviroment) {
     {
         auto& scheduler = system.Kernel().Scheduler(current_core);
         scheduler.Reload(scheduler.GetCurrentThread());
-        auto* currrent_thread2 = scheduler.GetCurrentThread();
-        if (!currrent_thread2->IsKernelThread()) {
+        if (!scheduler.IsIdle()) {
             idle_count = 0;
         }
     }
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index b8a746882..9f764c79a 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -126,9 +126,6 @@ public:
         return server_session;
     }
 
-    using WakeupCallback = std::function<void(
-        std::shared_ptr<KThread> thread, HLERequestContext& context, ThreadWakeupReason reason)>;
-
     /// Populates this context with data from the requesting process/thread.
     ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table,
                                                  u32_le* src_cmdbuf);
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index 233022023..5bdbd9a9b 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -31,11 +31,15 @@ static void IncrementScheduledCount(Kernel::KThread* thread) {
     }
 }
 
-void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule,
-                                 Core::EmuThreadHandle global_thread) {
-    const u32 current_core = global_thread.host_handle;
-    bool must_context_switch = global_thread.guest_handle != InvalidHandle &&
-                               (current_core < Core::Hardware::NUM_CPU_CORES);
+void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule) {
+    auto scheduler = kernel.CurrentScheduler();
+
+    u32 current_core{0xF};
+    bool must_context_switch{};
+    if (scheduler) {
+        current_core = scheduler->core_id;
+        must_context_switch = true;
+    }
 
     while (cores_pending_reschedule != 0) {
         const auto core = static_cast<u32>(std::countr_zero(cores_pending_reschedule));
@@ -58,26 +62,25 @@ void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedul
 
 u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) {
     std::scoped_lock lock{guard};
-    if (KThread* prev_highest_thread = this->state.highest_priority_thread;
+    if (KThread* prev_highest_thread = state.highest_priority_thread;
         prev_highest_thread != highest_thread) {
         if (prev_highest_thread != nullptr) {
             IncrementScheduledCount(prev_highest_thread);
             prev_highest_thread->SetLastScheduledTick(system.CoreTiming().GetCPUTicks());
         }
-        if (this->state.should_count_idle) {
+        if (state.should_count_idle) {
             if (highest_thread != nullptr) {
-                // if (Process* process = highest_thread->GetOwnerProcess(); process != nullptr) {
-                //    process->SetRunningThread(this->core_id, highest_thread,
-                //                              this->state.idle_count);
-                //}
+                if (Process* process = highest_thread->GetOwnerProcess(); process != nullptr) {
+                    process->SetRunningThread(core_id, highest_thread, state.idle_count);
+                }
             } else {
-                this->state.idle_count++;
+                state.idle_count++;
             }
         }
 
-        this->state.highest_priority_thread = highest_thread;
-        this->state.needs_scheduling = true;
-        return (1ULL << this->core_id);
+        state.highest_priority_thread = highest_thread;
+        state.needs_scheduling = true;
+        return (1ULL << core_id);
     } else {
         return 0;
     }
@@ -99,7 +102,20 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) {
         KThread* top_thread = priority_queue.GetScheduledFront(static_cast<s32>(core_id));
         if (top_thread != nullptr) {
             // If the thread has no waiters, we need to check if the process has a thread pinned.
-            // TODO(bunnei): Implement thread pinning
+            if (top_thread->GetNumKernelWaiters() == 0) {
+                if (Process* parent = top_thread->GetOwnerProcess(); parent != nullptr) {
+                    if (KThread* pinned = parent->GetPinnedThread(static_cast<s32>(core_id));
+                        pinned != nullptr && pinned != top_thread) {
+                        // We prefer our parent's pinned thread if possible. However, we also don't
+                        // want to schedule un-runnable threads.
+                        if (pinned->GetRawState() == ThreadState::Runnable) {
+                            top_thread = pinned;
+                        } else {
+                            top_thread = nullptr;
+                        }
+                    }
+                }
+            }
         } else {
             idle_cores |= (1ULL << core_id);
         }
@@ -182,6 +198,19 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) {
     return cores_needing_scheduling;
 }
 
+void KScheduler::ClearPreviousThread(KernelCore& kernel, KThread* thread) {
+    ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+    for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; ++i) {
+        // Get an atomic reference to the core scheduler's previous thread.
+        std::atomic_ref<KThread*> prev_thread(kernel.Scheduler(static_cast<s32>(i)).prev_thread);
+        static_assert(std::atomic_ref<KThread*>::is_always_lock_free);
+
+        // Atomically clear the previous thread if it's our target.
+        KThread* compare = thread;
+        prev_thread.compare_exchange_strong(compare, nullptr);
+    }
+}
+
 void KScheduler::OnThreadStateChanged(KernelCore& kernel, KThread* thread, ThreadState old_state) {
     ASSERT(kernel.GlobalSchedulerContext().IsLocked());
 
@@ -352,12 +381,14 @@ void KScheduler::DisableScheduling(KernelCore& kernel) {
     }
 }
 
-void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling,
-                                  Core::EmuThreadHandle global_thread) {
+void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling) {
     if (auto* scheduler = kernel.CurrentScheduler(); scheduler) {
-        scheduler->GetCurrentThread()->EnableDispatch();
+        ASSERT(scheduler->GetCurrentThread()->GetDisableDispatchCount() >= 1);
+        if (scheduler->GetCurrentThread()->GetDisableDispatchCount() >= 1) {
+            scheduler->GetCurrentThread()->EnableDispatch();
+        }
     }
-    RescheduleCores(kernel, cores_needing_scheduling, global_thread);
+    RescheduleCores(kernel, cores_needing_scheduling);
 }
 
 u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) {
@@ -372,15 +403,13 @@ KSchedulerPriorityQueue& KScheduler::GetPriorityQueue(KernelCore& kernel) {
     return kernel.GlobalSchedulerContext().priority_queue;
 }
 
-void KScheduler::YieldWithoutCoreMigration() {
-    auto& kernel = system.Kernel();
-
+void KScheduler::YieldWithoutCoreMigration(KernelCore& kernel) {
     // Validate preconditions.
     ASSERT(CanSchedule(kernel));
     ASSERT(kernel.CurrentProcess() != nullptr);
 
     // Get the current thread and process.
-    KThread& cur_thread = *GetCurrentThread();
+    KThread& cur_thread = Kernel::GetCurrentThread(kernel);
     Process& cur_process = *kernel.CurrentProcess();
 
     // If the thread's yield count matches, there's nothing for us to do.
@@ -413,15 +442,13 @@ void KScheduler::YieldWithoutCoreMigration() {
     }
 }
 
-void KScheduler::YieldWithCoreMigration() {
-    auto& kernel = system.Kernel();
-
+void KScheduler::YieldWithCoreMigration(KernelCore& kernel) {
     // Validate preconditions.
     ASSERT(CanSchedule(kernel));
     ASSERT(kernel.CurrentProcess() != nullptr);
 
     // Get the current thread and process.
-    KThread& cur_thread = *GetCurrentThread();
+    KThread& cur_thread = Kernel::GetCurrentThread(kernel);
     Process& cur_process = *kernel.CurrentProcess();
 
     // If the thread's yield count matches, there's nothing for us to do.
@@ -503,15 +530,13 @@ void KScheduler::YieldWithCoreMigration() {
     }
 }
 
-void KScheduler::YieldToAnyThread() {
-    auto& kernel = system.Kernel();
-
+void KScheduler::YieldToAnyThread(KernelCore& kernel) {
     // Validate preconditions.
     ASSERT(CanSchedule(kernel));
     ASSERT(kernel.CurrentProcess() != nullptr);
 
     // Get the current thread and process.
-    KThread& cur_thread = *GetCurrentThread();
+    KThread& cur_thread = Kernel::GetCurrentThread(kernel);
     Process& cur_process = *kernel.CurrentProcess();
 
     // If the thread's yield count matches, there's nothing for us to do.
@@ -581,15 +606,14 @@ void KScheduler::YieldToAnyThread() {
     }
 }
 
-KScheduler::KScheduler(Core::System& system, std::size_t core_id)
-    : system(system), core_id(core_id) {
+KScheduler::KScheduler(Core::System& system, s32 core_id) : system(system), core_id(core_id) {
     switch_fiber = std::make_shared<Common::Fiber>(OnSwitch, this);
-    this->state.needs_scheduling = true;
-    this->state.interrupt_task_thread_runnable = false;
-    this->state.should_count_idle = false;
-    this->state.idle_count = 0;
-    this->state.idle_thread_stack = nullptr;
-    this->state.highest_priority_thread = nullptr;
+    state.needs_scheduling = true;
+    state.interrupt_task_thread_runnable = false;
+    state.should_count_idle = false;
+    state.idle_count = 0;
+    state.idle_thread_stack = nullptr;
+    state.highest_priority_thread = nullptr;
 }
 
 KScheduler::~KScheduler() = default;
@@ -613,7 +637,7 @@ void KScheduler::RescheduleCurrentCore() {
         phys_core.ClearInterrupt();
     }
     guard.lock();
-    if (this->state.needs_scheduling) {
+    if (state.needs_scheduling) {
         Schedule();
     } else {
         guard.unlock();
@@ -625,32 +649,34 @@ void KScheduler::OnThreadStart() {
 }
 
 void KScheduler::Unload(KThread* thread) {
+    LOG_TRACE(Kernel, "core {}, unload thread {}", core_id, thread ? thread->GetName() : "nullptr");
+
     if (thread) {
-        thread->SetIsRunning(false);
-        if (thread->IsContinuousOnSVC()) {
+        if (thread->IsCallingSvc()) {
             system.ArmInterface(core_id).ExceptionalExit();
-            thread->SetContinuousOnSVC(false);
+            thread->ClearIsCallingSvc();
         }
-        if (!thread->HasExited()) {
+        if (!thread->IsTerminationRequested()) {
+            prev_thread = thread;
+
             Core::ARM_Interface& cpu_core = system.ArmInterface(core_id);
             cpu_core.SaveContext(thread->GetContext32());
             cpu_core.SaveContext(thread->GetContext64());
             // Save the TPIDR_EL0 system register in case it was modified.
             thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0());
             cpu_core.ClearExclusiveState();
+        } else {
+            prev_thread = nullptr;
         }
-        thread->context_guard.unlock();
     }
 }
 
 void KScheduler::Reload(KThread* thread) {
+    LOG_TRACE(Kernel, "core {}, reload thread {}", core_id, thread ? thread->GetName() : "nullptr");
+
     if (thread) {
         ASSERT_MSG(thread->GetState() == ThreadState::Runnable, "Thread must be runnable.");
 
-        // Cancel any outstanding wakeup events for this thread
-        thread->SetIsRunning(true);
-        thread->SetWasRunning(false);
-
         auto* const thread_owner_process = thread->GetOwnerProcess();
         if (thread_owner_process != nullptr) {
             system.Kernel().MakeCurrentProcess(thread_owner_process);
@@ -676,7 +702,7 @@ void KScheduler::ScheduleImpl() {
     KThread* previous_thread = current_thread;
     current_thread = state.highest_priority_thread;
 
-    this->state.needs_scheduling = false;
+    state.needs_scheduling = false;
 
     if (current_thread == previous_thread) {
         guard.unlock();
@@ -714,7 +740,7 @@ void KScheduler::SwitchToCurrent() {
         {
             std::scoped_lock lock{guard};
             current_thread = state.highest_priority_thread;
-            this->state.needs_scheduling = false;
+            state.needs_scheduling = false;
         }
         const auto is_switch_pending = [this] {
             std::scoped_lock lock{guard};
@@ -722,13 +748,10 @@ void KScheduler::SwitchToCurrent() {
         };
         do {
             if (current_thread != nullptr) {
-                current_thread->context_guard.lock();
                 if (current_thread->GetRawState() != ThreadState::Runnable) {
-                    current_thread->context_guard.unlock();
                     break;
                 }
-                if (static_cast<u32>(current_thread->GetProcessorID()) != core_id) {
-                    current_thread->context_guard.unlock();
+                if (static_cast<u32>(current_thread->GetActiveCore()) != core_id) {
                     break;
                 }
             }
@@ -749,7 +772,7 @@ void KScheduler::UpdateLastContextSwitchTime(KThread* thread, Process* process)
     const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks;
 
     if (thread != nullptr) {
-        thread->UpdateCPUTimeTicks(update_ticks);
+        thread->AddCpuTime(core_id, update_ticks);
     }
 
     if (process != nullptr) {
@@ -763,15 +786,10 @@ void KScheduler::Initialize() {
     std::string name = "Idle Thread Id:" + std::to_string(core_id);
     std::function<void(void*)> init_func = Core::CpuManager::GetIdleThreadStartFunc();
     void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
-    auto thread_res = KThread::Create(system, ThreadType::Kernel, name, 0,
+    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().get();
-
-    {
-        KScopedSchedulerLock lock{system.Kernel()};
-        idle_thread->SetState(ThreadState::Runnable);
-    }
 }
 
 KScopedSchedulerLock::KScopedSchedulerLock(KernelCore& kernel)
diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h
index 157373934..2308a55be 100644
--- a/src/core/hle/kernel/k_scheduler.h
+++ b/src/core/hle/kernel/k_scheduler.h
@@ -33,15 +33,14 @@ class KThread;
 
 class KScheduler final {
 public:
-    explicit KScheduler(Core::System& system, std::size_t core_id);
+    explicit KScheduler(Core::System& system, s32 core_id);
     ~KScheduler();
 
     /// Reschedules to the next available thread (call after current thread is suspended)
     void RescheduleCurrentCore();
 
     /// Reschedules cores pending reschedule, to be called on EnableScheduling.
-    static void RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule,
-                                Core::EmuThreadHandle global_thread);
+    static void RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule);
 
     /// The next two are for SingleCore Only.
     /// Unload current thread before preempting core.
@@ -53,6 +52,11 @@ public:
     /// Gets the current running thread
     [[nodiscard]] KThread* GetCurrentThread() const;
 
+    /// Returns true if the scheduler is idle
+    [[nodiscard]] bool IsIdle() const {
+        return GetCurrentThread() == idle_thread;
+    }
+
     /// Gets the timestamp for the last context switch in ticks.
     [[nodiscard]] u64 GetLastContextSwitchTicks() const;
 
@@ -79,7 +83,7 @@ public:
      *
      * @note This operation can be redundant and no scheduling is changed if marked as so.
      */
-    void YieldWithoutCoreMigration();
+    static void YieldWithoutCoreMigration(KernelCore& kernel);
 
     /**
      * Takes a thread and moves it to the back of the it's priority list.
@@ -88,7 +92,7 @@ public:
      *
      * @note This operation can be redundant and no scheduling is changed if marked as so.
      */
-    void YieldWithCoreMigration();
+    static void YieldWithCoreMigration(KernelCore& kernel);
 
     /**
      * Takes a thread and moves it out of the scheduling queue.
@@ -97,7 +101,9 @@ public:
      *
      * @note This operation can be redundant and no scheduling is changed if marked as so.
      */
-    void YieldToAnyThread();
+    static void YieldToAnyThread(KernelCore& kernel);
+
+    static void ClearPreviousThread(KernelCore& kernel, KThread* thread);
 
     /// Notify the scheduler a thread's status has changed.
     static void OnThreadStateChanged(KernelCore& kernel, KThread* thread, ThreadState old_state);
@@ -114,8 +120,7 @@ public:
     static void SetSchedulerUpdateNeeded(KernelCore& kernel);
     static void ClearSchedulerUpdateNeeded(KernelCore& kernel);
     static void DisableScheduling(KernelCore& kernel);
-    static void EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling,
-                                 Core::EmuThreadHandle global_thread);
+    static void EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling);
     [[nodiscard]] static u64 UpdateHighestPriorityThreads(KernelCore& kernel);
 
 private:
@@ -168,6 +173,7 @@ private:
     static void OnSwitch(void* this_scheduler);
     void SwitchToCurrent();
 
+    KThread* prev_thread{};
     KThread* current_thread{};
     KThread* idle_thread{};
 
@@ -186,7 +192,7 @@ private:
 
     Core::System& system;
     u64 last_context_switch_time{};
-    const std::size_t core_id;
+    const s32 core_id;
 
     Common::SpinLock guard{};
 };
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index e5be849bb..f021b0550 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -1,4 +1,4 @@
-// Copyright 2014 Citra Emulator Project / PPSSPP Project
+// Copyright 2021 yuzu Emulator Project
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
@@ -8,10 +8,12 @@
 #include <vector>
 
 #include "common/assert.h"
+#include "common/bit_util.h"
 #include "common/common_funcs.h"
 #include "common/common_types.h"
 #include "common/fiber.h"
 #include "common/logging/log.h"
+#include "common/scope_exit.h"
 #include "common/thread_queue_list.h"
 #include "core/core.h"
 #include "core/cpu_manager.h"
@@ -22,10 +24,12 @@
 #include "core/hle/kernel/k_scheduler.h"
 #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
 #include "core/hle/kernel/k_thread.h"
+#include "core/hle/kernel/k_thread_queue.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/memory/memory_layout.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/process.h"
+#include "core/hle/kernel/resource_limit.h"
 #include "core/hle/kernel/svc_results.h"
 #include "core/hle/kernel/time_manager.h"
 #include "core/hle/result.h"
@@ -36,57 +40,7 @@
 #include "core/arm/dynarmic/arm_dynarmic_64.h"
 #endif
 
-namespace Kernel {
-
-bool KThread::IsSignaled() const {
-    return signaled;
-}
-
-KThread::KThread(KernelCore& kernel) : KSynchronizationObject{kernel} {}
-KThread::~KThread() = default;
-
-void KThread::Stop() {
-    {
-        KScopedSchedulerLock lock(kernel);
-        SetState(ThreadState::Terminated);
-        signaled = true;
-        NotifyAvailable();
-        kernel.GlobalHandleTable().Close(global_handle);
-
-        if (owner_process) {
-            owner_process->UnregisterThread(this);
-
-            // Mark the TLS slot in the thread's page as free.
-            owner_process->FreeTLSRegion(tls_address);
-        }
-        has_exited = true;
-    }
-    global_handle = 0;
-}
-
-void KThread::Wakeup() {
-    KScopedSchedulerLock lock(kernel);
-    SetState(ThreadState::Runnable);
-}
-
-ResultCode KThread::Start() {
-    KScopedSchedulerLock lock(kernel);
-    SetState(ThreadState::Runnable);
-    return RESULT_SUCCESS;
-}
-
-void KThread::CancelWait() {
-    KScopedSchedulerLock lock(kernel);
-    if (GetState() != ThreadState::Waiting || !is_cancellable) {
-        is_sync_cancelled = true;
-        return;
-    }
-    // TODO(Blinkhawk): Implement cancel of server session
-    is_sync_cancelled = false;
-    SetSynchronizationResults(nullptr, ERR_SYNCHRONIZATION_CANCELED);
-    SetState(ThreadState::Runnable);
-}
-
+namespace {
 static void ResetThreadContext32(Core::ARM_Interface::ThreadContext32& context, u32 stack_top,
                                  u32 entry_point, u32 arg) {
     context = {};
@@ -104,117 +58,716 @@ static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context,
     // TODO(merry): Perform a hardware test to determine the below value.
     context.fpcr = 0;
 }
+} // namespace
 
-std::shared_ptr<Common::Fiber>& KThread::GetHostContext() {
-    return host_context;
-}
+namespace Kernel {
 
-ResultVal<std::shared_ptr<KThread>> KThread::Create(Core::System& system, ThreadType type_flags,
-                                                    std::string name, VAddr entry_point,
-                                                    u32 priority, u64 arg, s32 processor_id,
-                                                    VAddr stack_top, Process* owner_process) {
-    std::function<void(void*)> init_func = Core::CpuManager::GetGuestThreadStartFunc();
-    void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
-    return Create(system, type_flags, name, entry_point, priority, arg, processor_id, stack_top,
-                  owner_process, std::move(init_func), init_func_parameter);
-}
+KThread::KThread(KernelCore& kernel)
+    : KSynchronizationObject{kernel}, activity_pause_lock{kernel} {}
+KThread::~KThread() = default;
 
-ResultVal<std::shared_ptr<KThread>> KThread::Create(Core::System& system, ThreadType type_flags,
-                                                    std::string name, VAddr entry_point,
-                                                    u32 priority, u64 arg, s32 processor_id,
-                                                    VAddr stack_top, Process* owner_process,
-                                                    std::function<void(void*)>&& thread_start_func,
-                                                    void* thread_start_parameter) {
-    auto& kernel = system.Kernel();
+ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, s32 prio,
+                               s32 virt_core, Process* owner, ThreadType type) {
+    // Assert parameters are valid.
+    ASSERT((type == ThreadType::Main) ||
+           (Svc::HighestThreadPriority <= prio && prio <= Svc::LowestThreadPriority));
+    ASSERT((owner != nullptr) || (type != ThreadType::User));
+    ASSERT(0 <= virt_core && virt_core < static_cast<s32>(Common::BitSize<u64>()));
 
-    if (owner_process) {
-        if (!system.Memory().IsValidVirtualAddress(*owner_process, entry_point)) {
-            LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point);
-            // TODO (bunnei): Find the correct error code to use here
-            return RESULT_UNKNOWN;
+    // Convert the virtual core to a physical core.
+    const s32 phys_core = Core::Hardware::VirtualToPhysicalCoreMap[virt_core];
+    ASSERT(0 <= phys_core && phys_core < static_cast<s32>(Core::Hardware::NUM_CPU_CORES));
+
+    // First, clear the TLS address.
+    tls_address = {};
+
+    // Next, assert things based on the type.
+    switch (type) {
+    case ThreadType::Main:
+        ASSERT(arg == 0);
+        [[fallthrough]];
+    case ThreadType::HighPriority:
+        [[fallthrough]];
+    case ThreadType::User:
+        ASSERT(((owner == nullptr) ||
+                (owner->GetCoreMask() | (1ULL << virt_core)) == owner->GetCoreMask()));
+        ASSERT(((owner == nullptr) ||
+                (owner->GetPriorityMask() | (1ULL << prio)) == owner->GetPriorityMask()));
+        break;
+    case ThreadType::Kernel:
+        UNIMPLEMENTED();
+        break;
+    default:
+        UNREACHABLE_MSG("KThread::Initialize: Unknown ThreadType {}", static_cast<u32>(type));
+        break;
+    }
+
+    // Set the ideal core ID and affinity mask.
+    virtual_ideal_core_id = virt_core;
+    physical_ideal_core_id = phys_core;
+    virtual_affinity_mask = (static_cast<u64>(1) << virt_core);
+    physical_affinity_mask.SetAffinity(phys_core, true);
+
+    // Set the thread state.
+    thread_state = (type == ThreadType::Main) ? ThreadState::Runnable : ThreadState::Initialized;
+
+    // Set TLS address.
+    tls_address = 0;
+
+    // Set parent and condvar tree.
+    parent = nullptr;
+    condvar_tree = nullptr;
+
+    // Set sync booleans.
+    signaled = false;
+    termination_requested = false;
+    wait_cancelled = false;
+    cancellable = false;
+
+    // Set core ID and wait result.
+    core_id = phys_core;
+    wait_result = Svc::ResultNoSynchronizationObject;
+
+    // Set priorities.
+    priority = prio;
+    base_priority = prio;
+
+    // Set sync object and waiting lock to null.
+    synced_object = nullptr;
+
+    // Initialize sleeping queue.
+    sleeping_queue = nullptr;
+
+    // Set suspend flags.
+    suspend_request_flags = 0;
+    suspend_allowed_flags = static_cast<u32>(ThreadState::SuspendFlagMask);
+
+    // We're neither debug attached, nor are we nesting our priority inheritance.
+    debug_attached = false;
+    priority_inheritance_count = 0;
+
+    // We haven't been scheduled, and we have done no light IPC.
+    schedule_count = -1;
+    last_scheduled_tick = 0;
+    light_ipc_data = nullptr;
+
+    // We're not waiting for a lock, and we haven't disabled migration.
+    lock_owner = nullptr;
+    num_core_migration_disables = 0;
+
+    // We have no waiters, but we do have an entrypoint.
+    num_kernel_waiters = 0;
+
+    // Set our current core id.
+    current_core_id = phys_core;
+
+    // We haven't released our resource limit hint, and we've spent no time on the cpu.
+    resource_limit_release_hint = false;
+    cpu_time = 0;
+
+    // Clear our stack parameters.
+    std::memset(static_cast<void*>(std::addressof(GetStackParameters())), 0,
+                sizeof(StackParameters));
+
+    // Setup the TLS, if needed.
+    if (type == ThreadType::User) {
+        tls_address = owner->CreateTLSRegion();
+    }
+
+    // Set parent, if relevant.
+    if (owner != nullptr) {
+        parent = owner;
+        parent->IncrementThreadCount();
+    }
+
+    // Initialize thread context.
+    ResetThreadContext64(thread_context_64, user_stack_top, func, arg);
+    ResetThreadContext32(thread_context_32, static_cast<u32>(user_stack_top),
+                         static_cast<u32>(func), static_cast<u32>(arg));
+
+    // Setup the stack parameters.
+    StackParameters& sp = GetStackParameters();
+    sp.cur_thread = this;
+    sp.disable_count = 1;
+    SetInExceptionHandler();
+
+    // Set thread ID.
+    thread_id = kernel.CreateNewThreadID();
+
+    // We initialized!
+    initialized = true;
+
+    // Register ourselves with our parent process.
+    if (parent != nullptr) {
+        parent->RegisterThread(this);
+        if (parent->IsSuspended()) {
+            RequestSuspend(SuspendType::Process);
         }
     }
 
-    std::shared_ptr<KThread> thread = std::make_shared<KThread>(kernel);
-
-    thread->thread_id = kernel.CreateNewThreadID();
-    thread->thread_state = ThreadState::Initialized;
-    thread->entry_point = entry_point;
-    thread->stack_top = stack_top;
-    thread->disable_count = 1;
-    thread->tpidr_el0 = 0;
-    thread->current_priority = priority;
-    thread->base_priority = priority;
-    thread->lock_owner = nullptr;
-    thread->schedule_count = -1;
-    thread->last_scheduled_tick = 0;
-    thread->processor_id = processor_id;
-    thread->ideal_core = processor_id;
-    thread->affinity_mask.SetAffinity(processor_id, true);
-    thread->name = std::move(name);
-    thread->global_handle = kernel.GlobalHandleTable().Create(thread).Unwrap();
-    thread->owner_process = owner_process;
-    thread->type = type_flags;
-    thread->signaled = false;
-
-    auto& scheduler = kernel.GlobalSchedulerContext();
-    scheduler.AddThread(thread);
-
-    if (owner_process) {
-        thread->tls_address = thread->owner_process->CreateTLSRegion();
-        thread->owner_process->RegisterThread(thread.get());
-    } else {
-        thread->tls_address = 0;
-    }
-
-    ResetThreadContext32(thread->context_32, static_cast<u32>(stack_top),
-                         static_cast<u32>(entry_point), static_cast<u32>(arg));
-    ResetThreadContext64(thread->context_64, stack_top, entry_point, arg);
-
-    thread->host_context =
-        std::make_shared<Common::Fiber>(std::move(thread_start_func), thread_start_parameter);
-
-    return MakeResult<std::shared_ptr<KThread>>(std::move(thread));
+    return RESULT_SUCCESS;
 }
 
-void KThread::SetBasePriority(u32 priority) {
-    ASSERT(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority);
+ResultCode KThread::InitializeThread(KThread* thread, KThreadFunction func, uintptr_t arg,
+                                     VAddr user_stack_top, s32 prio, s32 core, Process* owner,
+                                     ThreadType type) {
+    // Initialize the thread.
+    R_TRY(thread->Initialize(func, arg, user_stack_top, prio, core, owner, type));
 
-    KScopedSchedulerLock lock(kernel);
+    return RESULT_SUCCESS;
+}
+
+void KThread::Finalize() {
+    // If the thread has an owner process, unregister it.
+    if (parent != nullptr) {
+        parent->UnregisterThread(this);
+    }
+
+    // If the thread has a local region, delete it.
+    if (tls_address != 0) {
+        parent->FreeTLSRegion(tls_address);
+    }
+
+    // Release any waiters.
+    {
+        ASSERT(lock_owner == nullptr);
+        KScopedSchedulerLock sl{kernel};
+
+        auto it = waiter_list.begin();
+        while (it != waiter_list.end()) {
+            // The thread shouldn't be a kernel waiter.
+            it->SetLockOwner(nullptr);
+            it->SetSyncedObject(nullptr, Svc::ResultInvalidState);
+            it->Wakeup();
+            it = waiter_list.erase(it);
+        }
+    }
+
+    // Decrement the parent process's thread count.
+    if (parent != nullptr) {
+        parent->DecrementThreadCount();
+    }
+}
+
+bool KThread::IsSignaled() const {
+    return signaled;
+}
+
+void KThread::Wakeup() {
+    KScopedSchedulerLock sl{kernel};
+
+    if (GetState() == ThreadState::Waiting) {
+        if (sleeping_queue != nullptr) {
+            sleeping_queue->WakeupThread(this);
+        } else {
+            SetState(ThreadState::Runnable);
+        }
+    }
+}
+
+void KThread::StartTermination() {
+    ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+
+    // Release user exception and unpin, if relevant.
+    if (parent != nullptr) {
+        parent->ReleaseUserException(this);
+        if (parent->GetPinnedThread(GetCurrentCoreId(kernel)) == this) {
+            parent->UnpinCurrentThread();
+        }
+    }
+
+    // Set state to terminated.
+    SetState(ThreadState::Terminated);
+
+    // Clear the thread's status as running in parent.
+    if (parent != nullptr) {
+        parent->ClearRunningThread(this);
+    }
+
+    // Signal.
+    signaled = true;
+    NotifyAvailable();
+
+    // Clear previous thread in KScheduler.
+    KScheduler::ClearPreviousThread(kernel, this);
+
+    // Register terminated dpc flag.
+    RegisterDpc(DpcFlag::Terminated);
+}
+
+void KThread::Pin() {
+    ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+
+    // Set ourselves as pinned.
+    GetStackParameters().is_pinned = true;
+
+    // Disable core migration.
+    ASSERT(num_core_migration_disables == 0);
+    {
+        ++num_core_migration_disables;
+
+        // Save our ideal state to restore when we're unpinned.
+        original_physical_ideal_core_id = physical_ideal_core_id;
+        original_physical_affinity_mask = physical_affinity_mask;
+
+        // Bind ourselves to this core.
+        const s32 active_core = GetActiveCore();
+        const s32 current_core = GetCurrentCoreId(kernel);
+
+        SetActiveCore(current_core);
+        physical_ideal_core_id = current_core;
+        physical_affinity_mask.SetAffinityMask(1ULL << current_core);
+
+        if (active_core != current_core || physical_affinity_mask.GetAffinityMask() !=
+                                               original_physical_affinity_mask.GetAffinityMask()) {
+            KScheduler::OnThreadAffinityMaskChanged(kernel, this, original_physical_affinity_mask,
+                                                    active_core);
+        }
+    }
+
+    // Disallow performing thread suspension.
+    {
+        // Update our allow flags.
+        suspend_allowed_flags &= ~(1 << (static_cast<u32>(SuspendType::Thread) +
+                                         static_cast<u32>(ThreadState::SuspendShift)));
+
+        // Update our state.
+        const ThreadState old_state = thread_state;
+        thread_state = static_cast<ThreadState>(GetSuspendFlags() |
+                                                static_cast<u32>(old_state & ThreadState::Mask));
+        if (thread_state != old_state) {
+            KScheduler::OnThreadStateChanged(kernel, this, old_state);
+        }
+    }
+
+    // TODO(bunnei): Update our SVC access permissions.
+    ASSERT(parent != nullptr);
+}
+
+void KThread::Unpin() {
+    ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+
+    // Set ourselves as unpinned.
+    GetStackParameters().is_pinned = false;
+
+    // Enable core migration.
+    ASSERT(num_core_migration_disables == 1);
+    {
+        --num_core_migration_disables;
+
+        // Restore our original state.
+        const KAffinityMask old_mask = physical_affinity_mask;
+
+        physical_ideal_core_id = original_physical_ideal_core_id;
+        physical_affinity_mask = original_physical_affinity_mask;
+
+        if (physical_affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) {
+            const s32 active_core = GetActiveCore();
+
+            if (!physical_affinity_mask.GetAffinity(active_core)) {
+                if (physical_ideal_core_id >= 0) {
+                    SetActiveCore(physical_ideal_core_id);
+                } else {
+                    SetActiveCore(static_cast<s32>(
+                        Common::BitSize<u64>() - 1 -
+                        std::countl_zero(physical_affinity_mask.GetAffinityMask())));
+                }
+            }
+            KScheduler::OnThreadAffinityMaskChanged(kernel, this, old_mask, active_core);
+        }
+    }
+
+    // Allow performing thread suspension (if termination hasn't been requested).
+    {
+        // Update our allow flags.
+        if (!IsTerminationRequested()) {
+            suspend_allowed_flags |= (1 << (static_cast<u32>(SuspendType::Thread) +
+                                            static_cast<u32>(ThreadState::SuspendShift)));
+        }
+
+        // Update our state.
+        const ThreadState old_state = thread_state;
+        thread_state = static_cast<ThreadState>(GetSuspendFlags() |
+                                                static_cast<u32>(old_state & ThreadState::Mask));
+        if (thread_state != old_state) {
+            KScheduler::OnThreadStateChanged(kernel, this, old_state);
+        }
+    }
+
+    // TODO(bunnei): Update our SVC access permissions.
+    ASSERT(parent != nullptr);
+
+    // Resume any threads that began waiting on us while we were pinned.
+    for (auto it = pinned_waiter_list.begin(); it != pinned_waiter_list.end(); ++it) {
+        if (it->GetState() == ThreadState::Waiting) {
+            it->SetState(ThreadState::Runnable);
+        }
+    }
+}
+
+ResultCode KThread::GetCoreMask(s32* out_ideal_core, u64* out_affinity_mask) {
+    KScopedSchedulerLock sl{kernel};
+
+    // Get the virtual mask.
+    *out_ideal_core = virtual_ideal_core_id;
+    *out_affinity_mask = virtual_affinity_mask;
+
+    return RESULT_SUCCESS;
+}
+
+ResultCode KThread::GetPhysicalCoreMask(s32* out_ideal_core, u64* out_affinity_mask) {
+    KScopedSchedulerLock sl{kernel};
+    ASSERT(num_core_migration_disables >= 0);
+
+    // Select between core mask and original core mask.
+    if (num_core_migration_disables == 0) {
+        *out_ideal_core = physical_ideal_core_id;
+        *out_affinity_mask = physical_affinity_mask.GetAffinityMask();
+    } else {
+        *out_ideal_core = original_physical_ideal_core_id;
+        *out_affinity_mask = original_physical_affinity_mask.GetAffinityMask();
+    }
+
+    return RESULT_SUCCESS;
+}
+
+ResultCode KThread::SetCoreMask(s32 core_id, u64 v_affinity_mask) {
+    ASSERT(parent != nullptr);
+    ASSERT(v_affinity_mask != 0);
+    KScopedLightLock lk{activity_pause_lock};
+
+    // Set the core mask.
+    u64 p_affinity_mask = 0;
+    {
+        KScopedSchedulerLock sl{kernel};
+        ASSERT(num_core_migration_disables >= 0);
+
+        // If the core id is no-update magic, preserve the ideal core id.
+        if (core_id == Svc::IdealCoreNoUpdate) {
+            core_id = virtual_ideal_core_id;
+            R_UNLESS(((1ULL << core_id) & v_affinity_mask) != 0, Svc::ResultInvalidCombination);
+        }
+
+        // Set the virtual core/affinity mask.
+        virtual_ideal_core_id = core_id;
+        virtual_affinity_mask = v_affinity_mask;
+
+        // Translate the virtual core to a physical core.
+        if (core_id >= 0) {
+            core_id = Core::Hardware::VirtualToPhysicalCoreMap[core_id];
+        }
+
+        // Translate the virtual affinity mask to a physical one.
+        while (v_affinity_mask != 0) {
+            const u64 next = std::countr_zero(v_affinity_mask);
+            v_affinity_mask &= ~(1ULL << next);
+            p_affinity_mask |= (1ULL << Core::Hardware::VirtualToPhysicalCoreMap[next]);
+        }
+
+        // If we haven't disabled migration, perform an affinity change.
+        if (num_core_migration_disables == 0) {
+            const KAffinityMask old_mask = physical_affinity_mask;
+
+            // Set our new ideals.
+            physical_ideal_core_id = core_id;
+            physical_affinity_mask.SetAffinityMask(p_affinity_mask);
+
+            if (physical_affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) {
+                const s32 active_core = GetActiveCore();
+
+                if (active_core >= 0 && !physical_affinity_mask.GetAffinity(active_core)) {
+                    const s32 new_core = static_cast<s32>(
+                        physical_ideal_core_id >= 0
+                            ? physical_ideal_core_id
+                            : Common::BitSize<u64>() - 1 -
+                                  std::countl_zero(physical_affinity_mask.GetAffinityMask()));
+                    SetActiveCore(new_core);
+                }
+                KScheduler::OnThreadAffinityMaskChanged(kernel, this, old_mask, active_core);
+            }
+        } else {
+            // Otherwise, we edit the original affinity for restoration later.
+            original_physical_ideal_core_id = core_id;
+            original_physical_affinity_mask.SetAffinityMask(p_affinity_mask);
+        }
+    }
+
+    // Update the pinned waiter list.
+    {
+        bool retry_update = false;
+        bool thread_is_pinned = false;
+        do {
+            // Lock the scheduler.
+            KScopedSchedulerLock sl{kernel};
+
+            // Don't do any further management if our termination has been requested.
+            R_SUCCEED_IF(IsTerminationRequested());
+
+            // By default, we won't need to retry.
+            retry_update = false;
+
+            // Check if the thread is currently running.
+            bool thread_is_current = false;
+            s32 thread_core;
+            for (thread_core = 0; thread_core < static_cast<s32>(Core::Hardware::NUM_CPU_CORES);
+                 ++thread_core) {
+                if (kernel.Scheduler(thread_core).GetCurrentThread() == this) {
+                    thread_is_current = true;
+                    break;
+                }
+            }
+
+            // If the thread is currently running, check whether it's no longer allowed under the
+            // new mask.
+            if (thread_is_current && ((1ULL << thread_core) & p_affinity_mask) == 0) {
+                // If the thread is pinned, we want to wait until it's not pinned.
+                if (GetStackParameters().is_pinned) {
+                    // Verify that the current thread isn't terminating.
+                    R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(),
+                             Svc::ResultTerminationRequested);
+
+                    // Note that the thread was pinned.
+                    thread_is_pinned = true;
+
+                    // Wait until the thread isn't pinned any more.
+                    pinned_waiter_list.push_back(GetCurrentThread(kernel));
+                    GetCurrentThread(kernel).SetState(ThreadState::Waiting);
+                } else {
+                    // If the thread isn't pinned, release the scheduler lock and retry until it's
+                    // not current.
+                    retry_update = true;
+                }
+            }
+        } while (retry_update);
+
+        // If the thread was pinned, it no longer is, and we should remove the current thread from
+        // our waiter list.
+        if (thread_is_pinned) {
+            // Lock the scheduler.
+            KScopedSchedulerLock sl{kernel};
+
+            // Remove from the list.
+            pinned_waiter_list.erase(pinned_waiter_list.iterator_to(GetCurrentThread(kernel)));
+        }
+    }
+
+    return RESULT_SUCCESS;
+}
+
+void KThread::SetBasePriority(s32 value) {
+    ASSERT(Svc::HighestThreadPriority <= value && value <= Svc::LowestThreadPriority);
+
+    KScopedSchedulerLock sl{kernel};
 
     // Change our base priority.
-    base_priority = priority;
+    base_priority = value;
 
     // Perform a priority restoration.
     RestorePriority(kernel, this);
 }
 
-void KThread::SetSynchronizationResults(KSynchronizationObject* object, ResultCode result) {
-    signaling_object = object;
-    signaling_result = result;
+void KThread::RequestSuspend(SuspendType type) {
+    KScopedSchedulerLock sl{kernel};
+
+    // Note the request in our flags.
+    suspend_request_flags |=
+        (1u << (static_cast<u32>(ThreadState::SuspendShift) + static_cast<u32>(type)));
+
+    // Try to perform the suspend.
+    TrySuspend();
 }
 
-VAddr KThread::GetCommandBufferAddress() const {
-    // Offset from the start of TLS at which the IPC command buffer begins.
-    constexpr u64 command_header_offset = 0x80;
-    return GetTLSAddress() + command_header_offset;
-}
+void KThread::Resume(SuspendType type) {
+    KScopedSchedulerLock sl{kernel};
 
-void KThread::SetState(ThreadState state) {
-    KScopedSchedulerLock sl(kernel);
-
-    // Clear debugging state
-    SetMutexWaitAddressForDebugging({});
-    SetWaitReasonForDebugging({});
+    // Clear the request in our flags.
+    suspend_request_flags &=
+        ~(1u << (static_cast<u32>(ThreadState::SuspendShift) + static_cast<u32>(type)));
 
+    // Update our state.
     const ThreadState old_state = thread_state;
-    thread_state =
-        static_cast<ThreadState>((old_state & ~ThreadState::Mask) | (state & ThreadState::Mask));
+    thread_state = static_cast<ThreadState>(GetSuspendFlags() |
+                                            static_cast<u32>(old_state & ThreadState::Mask));
     if (thread_state != old_state) {
         KScheduler::OnThreadStateChanged(kernel, this, old_state);
     }
 }
 
+void KThread::WaitCancel() {
+    KScopedSchedulerLock sl{kernel};
+
+    // Check if we're waiting and cancellable.
+    if (GetState() == ThreadState::Waiting && cancellable) {
+        if (sleeping_queue != nullptr) {
+            sleeping_queue->WakeupThread(this);
+            wait_cancelled = true;
+        } else {
+            SetSyncedObject(nullptr, Svc::ResultCancelled);
+            SetState(ThreadState::Runnable);
+            wait_cancelled = false;
+        }
+    } else {
+        // Otherwise, note that we cancelled a wait.
+        wait_cancelled = true;
+    }
+}
+
+void KThread::TrySuspend() {
+    ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+    ASSERT(IsSuspendRequested());
+
+    // Ensure that we have no waiters.
+    if (GetNumKernelWaiters() > 0) {
+        return;
+    }
+    ASSERT(GetNumKernelWaiters() == 0);
+
+    // Perform the suspend.
+    Suspend();
+}
+
+void KThread::Suspend() {
+    ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+    ASSERT(IsSuspendRequested());
+
+    // Set our suspend flags in state.
+    const auto old_state = thread_state;
+    thread_state = static_cast<ThreadState>(GetSuspendFlags()) | (old_state & ThreadState::Mask);
+
+    // Note the state change in scheduler.
+    KScheduler::OnThreadStateChanged(kernel, this, old_state);
+}
+
+void KThread::Continue() {
+    ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+
+    // Clear our suspend flags in state.
+    const auto old_state = thread_state;
+    thread_state = old_state & ThreadState::Mask;
+
+    // Note the state change in scheduler.
+    KScheduler::OnThreadStateChanged(kernel, this, old_state);
+}
+
+ResultCode KThread::SetActivity(Svc::ThreadActivity activity) {
+    // Lock ourselves.
+    KScopedLightLock lk(activity_pause_lock);
+
+    // Set the activity.
+    {
+        // Lock the scheduler.
+        KScopedSchedulerLock sl{kernel};
+
+        // Verify our state.
+        const auto cur_state = GetState();
+        R_UNLESS((cur_state == ThreadState::Waiting || cur_state == ThreadState::Runnable),
+                 Svc::ResultInvalidState);
+
+        // Either pause or resume.
+        if (activity == Svc::ThreadActivity::Paused) {
+            // Verify that we're not suspended.
+            R_UNLESS(!IsSuspendRequested(SuspendType::Thread), Svc::ResultInvalidState);
+
+            // Suspend.
+            RequestSuspend(SuspendType::Thread);
+        } else {
+            ASSERT(activity == Svc::ThreadActivity::Runnable);
+
+            // Verify that we're suspended.
+            R_UNLESS(IsSuspendRequested(SuspendType::Thread), Svc::ResultInvalidState);
+
+            // Resume.
+            Resume(SuspendType::Thread);
+        }
+    }
+
+    // If the thread is now paused, update the pinned waiter list.
+    if (activity == Svc::ThreadActivity::Paused) {
+        bool thread_is_pinned = false;
+        bool thread_is_current;
+        do {
+            // Lock the scheduler.
+            KScopedSchedulerLock sl{kernel};
+
+            // Don't do any further management if our termination has been requested.
+            R_SUCCEED_IF(IsTerminationRequested());
+
+            // Check whether the thread is pinned.
+            if (GetStackParameters().is_pinned) {
+                // Verify that the current thread isn't terminating.
+                R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(),
+                         Svc::ResultTerminationRequested);
+
+                // Note that the thread was pinned and not current.
+                thread_is_pinned = true;
+                thread_is_current = false;
+
+                // Wait until the thread isn't pinned any more.
+                pinned_waiter_list.push_back(GetCurrentThread(kernel));
+                GetCurrentThread(kernel).SetState(ThreadState::Waiting);
+            } else {
+                // Check if the thread is currently running.
+                // If it is, we'll need to retry.
+                thread_is_current = false;
+
+                for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) {
+                    if (kernel.Scheduler(i).GetCurrentThread() == this) {
+                        thread_is_current = true;
+                        break;
+                    }
+                }
+            }
+        } while (thread_is_current);
+
+        // If the thread was pinned, it no longer is, and we should remove the current thread from
+        // our waiter list.
+        if (thread_is_pinned) {
+            // Lock the scheduler.
+            KScopedSchedulerLock sl{kernel};
+
+            // Remove from the list.
+            pinned_waiter_list.erase(pinned_waiter_list.iterator_to(GetCurrentThread(kernel)));
+        }
+    }
+
+    return RESULT_SUCCESS;
+}
+
+ResultCode KThread::GetThreadContext3(std::vector<u8>& out) {
+    // Lock ourselves.
+    KScopedLightLock lk{activity_pause_lock};
+
+    // Get the context.
+    {
+        // Lock the scheduler.
+        KScopedSchedulerLock sl{kernel};
+
+        // Verify that we're suspended.
+        R_UNLESS(IsSuspendRequested(SuspendType::Thread), Svc::ResultInvalidState);
+
+        // If we're not terminating, get the thread's user context.
+        if (!IsTerminationRequested()) {
+            if (parent->Is64BitProcess()) {
+                // Mask away mode bits, interrupt bits, IL bit, and other reserved bits.
+                auto context = GetContext64();
+                context.pstate &= 0xFF0FFE20;
+
+                out.resize(sizeof(context));
+                std::memcpy(out.data(), &context, sizeof(context));
+            } else {
+                // Mask away mode bits, interrupt bits, IL bit, and other reserved bits.
+                auto context = GetContext32();
+                context.cpsr &= 0xFF0FFE20;
+
+                out.resize(sizeof(context));
+                std::memcpy(out.data(), &context, sizeof(context));
+            }
+        }
+    }
+
+    return RESULT_SUCCESS;
+}
+
 void KThread::AddWaiterImpl(KThread* thread) {
     ASSERT(kernel.GlobalSchedulerContext().IsLocked());
 
@@ -345,104 +898,150 @@ KThread* KThread::RemoveWaiterByKey(s32* out_num_waiters, VAddr key) {
     return next_lock_owner;
 }
 
-ResultCode KThread::SetActivity(ThreadActivity value) {
-    KScopedSchedulerLock lock(kernel);
+ResultCode KThread::Run() {
+    while (true) {
+        KScopedSchedulerLock lk{kernel};
 
-    auto sched_status = GetState();
+        // If either this thread or the current thread are requesting termination, note it.
+        R_UNLESS(!IsTerminationRequested(), Svc::ResultTerminationRequested);
+        R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(),
+                 Svc::ResultTerminationRequested);
 
-    if (sched_status != ThreadState::Runnable && sched_status != ThreadState::Waiting) {
-        return ERR_INVALID_STATE;
-    }
+        // Ensure our thread state is correct.
+        R_UNLESS(GetState() == ThreadState::Initialized, Svc::ResultInvalidState);
 
-    if (IsTerminationRequested()) {
+        // If the current thread has been asked to suspend, suspend it and retry.
+        if (GetCurrentThread(kernel).IsSuspended()) {
+            GetCurrentThread(kernel).Suspend();
+            continue;
+        }
+
+        // If we're not a kernel thread and we've been asked to suspend, suspend ourselves.
+        if (IsUserThread() && IsSuspended()) {
+            Suspend();
+        }
+
+        // Set our state and finish.
+        SetState(ThreadState::Runnable);
         return RESULT_SUCCESS;
     }
-
-    if (value == ThreadActivity::Paused) {
-        if ((pausing_state & static_cast<u32>(ThreadSchedFlags::ThreadPauseFlag)) != 0) {
-            return ERR_INVALID_STATE;
-        }
-        AddSchedulingFlag(ThreadSchedFlags::ThreadPauseFlag);
-    } else {
-        if ((pausing_state & static_cast<u32>(ThreadSchedFlags::ThreadPauseFlag)) == 0) {
-            return ERR_INVALID_STATE;
-        }
-        RemoveSchedulingFlag(ThreadSchedFlags::ThreadPauseFlag);
-    }
-    return RESULT_SUCCESS;
 }
 
-ResultCode KThread::Sleep(s64 nanoseconds) {
-    Handle event_handle{};
+void KThread::Exit() {
+    ASSERT(this == GetCurrentThreadPointer(kernel));
+
+    // Release the thread resource hint from parent.
+    if (parent != nullptr) {
+        // TODO(bunnei): Hint that the resource is about to be released.
+        resource_limit_release_hint = true;
+    }
+
+    // Perform termination.
     {
-        KScopedSchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds);
+        KScopedSchedulerLock sl{kernel};
+
+        // Disallow all suspension.
+        suspend_allowed_flags = 0;
+
+        // Start termination.
+        StartTermination();
+    }
+}
+
+ResultCode KThread::Sleep(s64 timeout) {
+    ASSERT(!kernel.GlobalSchedulerContext().IsLocked());
+    ASSERT(this == GetCurrentThreadPointer(kernel));
+    ASSERT(timeout > 0);
+
+    {
+        // Setup the scheduling lock and sleep.
+        KScopedSchedulerLockAndSleep slp{kernel, this, timeout};
+
+        // Check if the thread should terminate.
+        if (IsTerminationRequested()) {
+            slp.CancelSleep();
+            return Svc::ResultTerminationRequested;
+        }
+
+        // Mark the thread as waiting.
         SetState(ThreadState::Waiting);
         SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Sleep);
     }
 
-    if (event_handle != InvalidHandle) {
-        auto& time_manager = kernel.TimeManager();
-        time_manager.UnscheduleTimeEvent(event_handle);
-    }
+    // The lock/sleep is done.
+
+    // Cancel the timer.
+    kernel.TimeManager().UnscheduleTimeEvent(this);
+
     return RESULT_SUCCESS;
 }
 
-void KThread::AddSchedulingFlag(ThreadSchedFlags flag) {
-    const auto old_state = GetRawState();
-    pausing_state |= static_cast<u32>(flag);
-    const auto base_scheduling = GetState();
-    thread_state = base_scheduling | static_cast<ThreadState>(pausing_state);
-    KScheduler::OnThreadStateChanged(kernel, this, old_state);
+void KThread::SetState(ThreadState state) {
+    KScopedSchedulerLock sl{kernel};
+
+    // Clear debugging state
+    SetMutexWaitAddressForDebugging({});
+    SetWaitReasonForDebugging({});
+
+    const ThreadState old_state = thread_state;
+    thread_state =
+        static_cast<ThreadState>((old_state & ~ThreadState::Mask) | (state & ThreadState::Mask));
+    if (thread_state != old_state) {
+        KScheduler::OnThreadStateChanged(kernel, this, old_state);
+    }
 }
 
-void KThread::RemoveSchedulingFlag(ThreadSchedFlags flag) {
-    const auto old_state = GetRawState();
-    pausing_state &= ~static_cast<u32>(flag);
-    const auto base_scheduling = GetState();
-    thread_state = base_scheduling | static_cast<ThreadState>(pausing_state);
-    KScheduler::OnThreadStateChanged(kernel, this, old_state);
+std::shared_ptr<Common::Fiber>& KThread::GetHostContext() {
+    return host_context;
 }
 
-ResultCode KThread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) {
-    KScopedSchedulerLock lock(kernel);
-    const auto HighestSetCore = [](u64 mask, u32 max_cores) {
-        for (s32 core = static_cast<s32>(max_cores - 1); core >= 0; core--) {
-            if (((mask >> core) & 1) != 0) {
-                return core;
-            }
-        }
-        return -1;
-    };
+ResultVal<std::shared_ptr<KThread>> KThread::Create(Core::System& system, ThreadType type_flags,
+                                                    std::string name, VAddr entry_point,
+                                                    u32 priority, u64 arg, s32 processor_id,
+                                                    VAddr stack_top, Process* owner_process) {
+    std::function<void(void*)> init_func = Core::CpuManager::GetGuestThreadStartFunc();
+    void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
+    return Create(system, type_flags, name, entry_point, priority, arg, processor_id, stack_top,
+                  owner_process, std::move(init_func), init_func_parameter);
+}
 
-    const bool use_override = affinity_override_count != 0;
-    if (new_core == Svc::IdealCoreNoUpdate) {
-        new_core = use_override ? ideal_core_override : ideal_core;
-        if ((new_affinity_mask & (1ULL << new_core)) == 0) {
-            LOG_ERROR(Kernel, "New affinity mask is incorrect! new_core={}, new_affinity_mask={}",
-                      new_core, new_affinity_mask);
-            return ERR_INVALID_COMBINATION;
-        }
+ResultVal<std::shared_ptr<KThread>> KThread::Create(Core::System& system, ThreadType type_flags,
+                                                    std::string name, VAddr entry_point,
+                                                    u32 priority, u64 arg, s32 processor_id,
+                                                    VAddr stack_top, Process* owner_process,
+                                                    std::function<void(void*)>&& thread_start_func,
+                                                    void* thread_start_parameter) {
+    auto& kernel = system.Kernel();
+
+    std::shared_ptr<KThread> thread = std::make_shared<KThread>(kernel);
+
+    thread->InitializeThread(thread.get(), entry_point, arg, stack_top, priority, processor_id,
+                             owner_process, type_flags);
+    thread->name = name;
+
+    auto& scheduler = kernel.GlobalSchedulerContext();
+    scheduler.AddThread(thread);
+
+    thread->host_context =
+        std::make_shared<Common::Fiber>(std::move(thread_start_func), thread_start_parameter);
+
+    return MakeResult<std::shared_ptr<KThread>>(std::move(thread));
+}
+
+KThread* GetCurrentThreadPointer(KernelCore& kernel) {
+    if (!kernel.CurrentScheduler()) {
+        // We are not called from a core thread
+        return {};
     }
-    if (use_override) {
-        ideal_core_override = new_core;
-    } else {
-        const auto old_affinity_mask = affinity_mask;
-        affinity_mask.SetAffinityMask(new_affinity_mask);
-        ideal_core = new_core;
-        if (old_affinity_mask.GetAffinityMask() != new_affinity_mask) {
-            const s32 old_core = processor_id;
-            if (processor_id >= 0 && !affinity_mask.GetAffinity(processor_id)) {
-                if (static_cast<s32>(ideal_core) < 0) {
-                    processor_id = HighestSetCore(affinity_mask.GetAffinityMask(),
-                                                  Core::Hardware::NUM_CPU_CORES);
-                } else {
-                    processor_id = ideal_core;
-                }
-            }
-            KScheduler::OnThreadAffinityMaskChanged(kernel, this, old_affinity_mask, old_core);
-        }
-    }
-    return RESULT_SUCCESS;
+    return kernel.CurrentScheduler()->GetCurrentThread();
+}
+
+KThread& GetCurrentThread(KernelCore& kernel) {
+    return *GetCurrentThreadPointer(kernel);
+}
+
+s32 GetCurrentCoreId(KernelCore& kernel) {
+    return GetCurrentThread(kernel).GetCurrentCore();
 }
 
 } // namespace Kernel
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index ef2313f87..7845821ba 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -1,11 +1,10 @@
-// Copyright 2014 Citra Emulator Project / PPSSPP Project
+// Copyright 2021 yuzu Emulator Project
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
 #pragma once
 
 #include <array>
-#include <functional>
 #include <span>
 #include <string>
 #include <utility>
@@ -18,9 +17,11 @@
 #include "common/spin_lock.h"
 #include "core/arm/arm_interface.h"
 #include "core/hle/kernel/k_affinity_mask.h"
+#include "core/hle/kernel/k_light_lock.h"
 #include "core/hle/kernel/k_synchronization_object.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/svc_common.h"
+#include "core/hle/kernel/svc_types.h"
 #include "core/hle/result.h"
 
 namespace Common {
@@ -38,6 +39,9 @@ class GlobalSchedulerContext;
 class KernelCore;
 class Process;
 class KScheduler;
+class KThreadQueue;
+
+using KThreadFunction = VAddr;
 
 enum class ThreadType : u32 {
     Main = 0,
@@ -47,6 +51,16 @@ enum class ThreadType : u32 {
 };
 DECLARE_ENUM_FLAG_OPERATORS(ThreadType);
 
+enum class SuspendType : u32 {
+    Process = 0,
+    Thread = 1,
+    Debug = 2,
+    Backtrace = 3,
+    Init = 4,
+
+    Count,
+};
+
 enum class ThreadState : u16 {
     Initialized = 0,
     Waiting = 1,
@@ -66,21 +80,9 @@ enum class ThreadState : u16 {
 };
 DECLARE_ENUM_FLAG_OPERATORS(ThreadState);
 
-enum class ThreadWakeupReason {
-    Signal, // The thread was woken up by WakeupAllWaitingThreads due to an object signal.
-    Timeout // The thread was woken up due to a wait timeout.
-};
-
-enum class ThreadActivity : u32 {
-    Normal = 0,
-    Paused = 1,
-};
-
-enum class ThreadSchedFlags : u32 {
-    ProcessPauseFlag = 1 << 4,
-    ThreadPauseFlag = 1 << 5,
-    ProcessDebugPauseFlag = 1 << 6,
-    KernelInitPauseFlag = 1 << 8,
+enum class DpcFlag : u32 {
+    Terminating = (1 << 0),
+    Terminated = (1 << 1),
 };
 
 enum class ThreadWaitReasonForDebugging : u32 {
@@ -93,21 +95,25 @@ enum class ThreadWaitReasonForDebugging : u32 {
     Suspended,       ///< Thread is waiting due to process suspension
 };
 
+[[nodiscard]] KThread* GetCurrentThreadPointer(KernelCore& kernel);
+[[nodiscard]] KThread& GetCurrentThread(KernelCore& kernel);
+[[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel);
+
 class KThread final : public KSynchronizationObject, public boost::intrusive::list_base_hook<> {
     friend class KScheduler;
     friend class Process;
 
 public:
     static constexpr s32 DefaultThreadPriority = 44;
-    static constexpr s32 IdleThreadPriority = 64;
+    static constexpr s32 IdleThreadPriority = Svc::LowestThreadPriority + 1;
 
     explicit KThread(KernelCore& kernel);
     ~KThread() override;
 
-    using MutexWaitingThreads = std::vector<std::shared_ptr<KThread>>;
-
+public:
     using ThreadContext32 = Core::ARM_Interface::ThreadContext32;
     using ThreadContext64 = Core::ARM_Interface::ThreadContext64;
+    using WaiterList = boost::intrusive::list<KThread>;
 
     /**
      * Creates and returns a new thread. The new thread is immediately scheduled
@@ -121,10 +127,9 @@ public:
      * @param owner_process The parent process for the thread, if null, it's a kernel thread
      * @return A shared pointer to the newly created thread
      */
-    static ResultVal<std::shared_ptr<KThread>> Create(Core::System& system, ThreadType type_flags,
-                                                      std::string name, VAddr entry_point,
-                                                      u32 priority, u64 arg, s32 processor_id,
-                                                      VAddr stack_top, Process* owner_process);
+    [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> Create(
+        Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point,
+        u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process);
 
     /**
      * Creates and returns a new thread. The new thread is immediately scheduled
@@ -140,12 +145,12 @@ public:
      * @param thread_start_parameter The parameter which will passed to host context on init
      * @return A shared pointer to the newly created thread
      */
-    static ResultVal<std::shared_ptr<KThread>> Create(
+    [[nodiscard]] static ResultVal<std::shared_ptr<KThread>> Create(
         Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point,
         u32 priority, u64 arg, s32 processor_id, VAddr stack_top, Process* owner_process,
         std::function<void(void*)>&& thread_start_func, void* thread_start_parameter);
 
-    std::string GetName() const override {
+    [[nodiscard]] std::string GetName() const override {
         return name;
     }
 
@@ -153,12 +158,12 @@ public:
         name = std::move(new_name);
     }
 
-    std::string GetTypeName() const override {
+    [[nodiscard]] std::string GetTypeName() const override {
         return "Thread";
     }
 
     static constexpr HandleType HANDLE_TYPE = HandleType::Thread;
-    HandleType GetHandleType() const override {
+    [[nodiscard]] HandleType GetHandleType() const override {
         return HANDLE_TYPE;
     }
 
@@ -167,15 +172,15 @@ public:
      * @return The current thread's priority
      */
     [[nodiscard]] s32 GetPriority() const {
-        return current_priority;
+        return priority;
     }
 
     /**
      * Sets the thread's current priority.
      * @param priority The new priority.
      */
-    void SetPriority(s32 priority) {
-        current_priority = priority;
+    void SetPriority(s32 value) {
+        priority = value;
     }
 
     /**
@@ -186,15 +191,6 @@ public:
         return base_priority;
     }
 
-    /**
-     * Sets the thread's nominal priority.
-     * @param priority The new priority.
-     */
-    void SetBasePriority(u32 priority);
-
-    /// Changes the core that the thread is running or scheduled to run on.
-    [[nodiscard]] ResultCode SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask);
-
     /**
      * Gets the thread's thread ID
      * @return The thread's ID
@@ -203,46 +199,67 @@ public:
         return thread_id;
     }
 
-    /// Resumes a thread from waiting
+    void ContinueIfHasKernelWaiters() {
+        if (GetNumKernelWaiters() > 0) {
+            Continue();
+        }
+    }
+
     void Wakeup();
 
-    ResultCode Start();
+    void SetBasePriority(s32 value);
 
-    virtual bool IsSignaled() const override;
+    [[nodiscard]] ResultCode Run();
 
-    /// Cancels a waiting operation that this thread may or may not be within.
-    ///
-    /// When the thread is within a waiting state, this will set the thread's
-    /// waiting result to signal a canceled wait. The function will then resume
-    /// this thread.
-    ///
-    void CancelWait();
+    void Exit();
 
-    void SetSynchronizationResults(KSynchronizationObject* object, ResultCode result);
-
-    void SetSyncedObject(KSynchronizationObject* object, ResultCode result) {
-        SetSynchronizationResults(object, result);
+    [[nodiscard]] u32 GetSuspendFlags() const {
+        return suspend_allowed_flags & suspend_request_flags;
     }
 
-    ResultCode GetWaitResult(KSynchronizationObject** out) const {
-        *out = signaling_object;
-        return signaling_result;
+    [[nodiscard]] bool IsSuspended() const {
+        return GetSuspendFlags() != 0;
     }
 
-    ResultCode GetSignalingResult() const {
-        return signaling_result;
+    [[nodiscard]] bool IsSuspendRequested(SuspendType type) const {
+        return (suspend_request_flags &
+                (1u << (static_cast<u32>(ThreadState::SuspendShift) + static_cast<u32>(type)))) !=
+               0;
     }
 
-    /**
-     * Stops a thread, invalidating it from further use
-     */
-    void Stop();
+    [[nodiscard]] bool IsSuspendRequested() const {
+        return suspend_request_flags != 0;
+    }
+
+    void RequestSuspend(SuspendType type);
+
+    void Resume(SuspendType type);
+
+    void TrySuspend();
+
+    void Continue();
+
+    void Suspend();
+
+    void Finalize() override;
+
+    bool IsSignaled() const override;
+
+    void SetSyncedObject(KSynchronizationObject* obj, ResultCode wait_res) {
+        synced_object = obj;
+        wait_result = wait_res;
+    }
+
+    [[nodiscard]] ResultCode GetWaitResult(KSynchronizationObject** out) const {
+        *out = synced_object;
+        return wait_result;
+    }
 
     /*
      * Returns the Thread Local Storage address of the current thread
      * @returns VAddr of the thread's TLS
      */
-    VAddr GetTLSAddress() const {
+    [[nodiscard]] VAddr GetTLSAddress() const {
         return tls_address;
     }
 
@@ -250,62 +267,45 @@ public:
      * Returns the value of the TPIDR_EL0 Read/Write system register for this thread.
      * @returns The value of the TPIDR_EL0 register.
      */
-    u64 GetTPIDR_EL0() const {
-        return tpidr_el0;
+    [[nodiscard]] u64 GetTPIDR_EL0() const {
+        return thread_context_64.tpidr;
     }
 
     /// Sets the value of the TPIDR_EL0 Read/Write system register for this thread.
     void SetTPIDR_EL0(u64 value) {
-        tpidr_el0 = value;
+        thread_context_64.tpidr = value;
+        thread_context_32.tpidr = static_cast<u32>(value);
     }
 
-    /*
-     * Returns the address of the current thread's command buffer, located in the TLS.
-     * @returns VAddr of the thread's command buffer.
-     */
-    VAddr GetCommandBufferAddress() const;
-
-    ThreadContext32& GetContext32() {
-        return context_32;
+    [[nodiscard]] ThreadContext32& GetContext32() {
+        return thread_context_32;
     }
 
-    const ThreadContext32& GetContext32() const {
-        return context_32;
+    [[nodiscard]] const ThreadContext32& GetContext32() const {
+        return thread_context_32;
     }
 
-    ThreadContext64& GetContext64() {
-        return context_64;
+    [[nodiscard]] ThreadContext64& GetContext64() {
+        return thread_context_64;
     }
 
-    const ThreadContext64& GetContext64() const {
-        return context_64;
+    [[nodiscard]] const ThreadContext64& GetContext64() const {
+        return thread_context_64;
     }
 
-    bool IsKernelThread() const {
-        return type == ThreadType::Kernel;
-    }
+    [[nodiscard]] std::shared_ptr<Common::Fiber>& GetHostContext();
 
-    bool WasRunning() const {
-        return was_running;
-    }
-
-    void SetWasRunning(bool value) {
-        was_running = value;
-    }
-
-    std::shared_ptr<Common::Fiber>& GetHostContext();
-
-    ThreadState GetState() const {
+    [[nodiscard]] ThreadState GetState() const {
         return thread_state & ThreadState::Mask;
     }
 
-    ThreadState GetRawState() const {
+    [[nodiscard]] ThreadState GetRawState() const {
         return thread_state;
     }
 
     void SetState(ThreadState state);
 
-    s64 GetLastScheduledTick() const {
+    [[nodiscard]] s64 GetLastScheduledTick() const {
         return last_scheduled_tick;
     }
 
@@ -313,43 +313,44 @@ public:
         last_scheduled_tick = tick;
     }
 
-    u64 GetTotalCPUTimeTicks() const {
-        return total_cpu_time_ticks;
+    void AddCpuTime([[maybe_unused]] s32 core_id_, s64 amount) {
+        cpu_time += amount;
+        // TODO(bunnei): Debug kernels track per-core tick counts. Should we?
     }
 
-    void UpdateCPUTimeTicks(u64 ticks) {
-        total_cpu_time_ticks += ticks;
+    [[nodiscard]] s64 GetCpuTime() const {
+        return cpu_time;
     }
 
-    s32 GetProcessorID() const {
-        return processor_id;
+    [[nodiscard]] s32 GetActiveCore() const {
+        return core_id;
     }
 
-    s32 GetActiveCore() const {
-        return GetProcessorID();
+    void SetActiveCore(s32 core) {
+        core_id = core;
     }
 
-    void SetProcessorID(s32 new_core) {
-        processor_id = new_core;
+    [[nodiscard]] s32 GetCurrentCore() const {
+        return current_core_id;
     }
 
-    void SetActiveCore(s32 new_core) {
-        processor_id = new_core;
+    void SetCurrentCore(s32 core) {
+        current_core_id = core;
     }
 
-    Process* GetOwnerProcess() {
-        return owner_process;
+    [[nodiscard]] Process* GetOwnerProcess() {
+        return parent;
     }
 
-    const Process* GetOwnerProcess() const {
-        return owner_process;
+    [[nodiscard]] const Process* GetOwnerProcess() const {
+        return parent;
     }
 
-    const MutexWaitingThreads& GetMutexWaitingThreads() const {
-        return wait_mutex_threads;
+    [[nodiscard]] bool IsUserThread() const {
+        return parent != nullptr;
     }
 
-    KThread* GetLockOwner() const {
+    [[nodiscard]] KThread* GetLockOwner() const {
         return lock_owner;
     }
 
@@ -357,20 +358,21 @@ public:
         lock_owner = owner;
     }
 
-    u32 GetIdealCore() const {
-        return ideal_core;
+    [[nodiscard]] const KAffinityMask& GetAffinityMask() const {
+        return physical_affinity_mask;
     }
 
-    const KAffinityMask& GetAffinityMask() const {
-        return affinity_mask;
-    }
+    [[nodiscard]] ResultCode GetCoreMask(s32* out_ideal_core, u64* out_affinity_mask);
 
-    ResultCode SetActivity(ThreadActivity value);
+    [[nodiscard]] ResultCode GetPhysicalCoreMask(s32* out_ideal_core, u64* out_affinity_mask);
 
-    /// Sleeps this thread for the given amount of nanoseconds.
-    ResultCode Sleep(s64 nanoseconds);
+    [[nodiscard]] ResultCode SetCoreMask(s32 core_id, u64 v_affinity_mask);
 
-    s64 GetYieldScheduleCount() const {
+    [[nodiscard]] ResultCode SetActivity(Svc::ThreadActivity activity);
+
+    [[nodiscard]] ResultCode Sleep(s64 timeout);
+
+    [[nodiscard]] s64 GetYieldScheduleCount() const {
         return schedule_count;
     }
 
@@ -378,56 +380,49 @@ public:
         schedule_count = count;
     }
 
-    bool IsRunning() const {
-        return is_running;
+    void WaitCancel();
+
+    [[nodiscard]] bool IsWaitCancelled() const {
+        return wait_cancelled;
     }
 
-    void SetIsRunning(bool value) {
-        is_running = value;
+    [[nodiscard]] void ClearWaitCancelled() {
+        wait_cancelled = false;
     }
 
-    bool IsWaitCancelled() const {
-        return is_sync_cancelled;
-    }
-
-    void ClearWaitCancelled() {
-        is_sync_cancelled = false;
-    }
-
-    Handle GetGlobalHandle() const {
-        return global_handle;
-    }
-
-    bool IsCancellable() const {
-        return is_cancellable;
+    [[nodiscard]] bool IsCancellable() const {
+        return cancellable;
     }
 
     void SetCancellable() {
-        is_cancellable = true;
+        cancellable = true;
     }
 
     void ClearCancellable() {
-        is_cancellable = false;
+        cancellable = false;
     }
 
-    bool IsTerminationRequested() const {
-        return will_be_terminated || GetRawState() == ThreadState::Terminated;
+    [[nodiscard]] bool IsTerminationRequested() const {
+        return termination_requested || GetRawState() == ThreadState::Terminated;
     }
 
-    bool IsPaused() const {
-        return pausing_state != 0;
+    struct StackParameters {
+        u8 svc_permission[0x10];
+        std::atomic<u8> dpc_flags;
+        u8 current_svc_id;
+        bool is_calling_svc;
+        bool is_in_exception_handler;
+        bool is_pinned;
+        s32 disable_count;
+        KThread* cur_thread;
+    };
+
+    [[nodiscard]] StackParameters& GetStackParameters() {
+        return stack_parameters;
     }
 
-    bool IsContinuousOnSVC() const {
-        return is_continuous_on_svc;
-    }
-
-    void SetContinuousOnSVC(bool is_continuous) {
-        is_continuous_on_svc = is_continuous;
-    }
-
-    bool HasExited() const {
-        return has_exited;
+    [[nodiscard]] const StackParameters& GetStackParameters() const {
+        return stack_parameters;
     }
 
     class QueueEntry {
@@ -457,26 +452,78 @@ public:
         KThread* next{};
     };
 
-    QueueEntry& GetPriorityQueueEntry(s32 core) {
+    [[nodiscard]] QueueEntry& GetPriorityQueueEntry(s32 core) {
         return per_core_priority_queue_entry[core];
     }
 
-    const QueueEntry& GetPriorityQueueEntry(s32 core) const {
+    [[nodiscard]] const QueueEntry& GetPriorityQueueEntry(s32 core) const {
         return per_core_priority_queue_entry[core];
     }
 
-    s32 GetDisableDispatchCount() const {
-        return disable_count;
+    void SetSleepingQueue(KThreadQueue* q) {
+        sleeping_queue = q;
+    }
+
+    [[nodiscard]] s32 GetDisableDispatchCount() const {
+        return this->GetStackParameters().disable_count;
     }
 
     void DisableDispatch() {
-        ASSERT(GetDisableDispatchCount() >= 0);
-        disable_count++;
+        ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() >= 0);
+        this->GetStackParameters().disable_count++;
     }
 
     void EnableDispatch() {
-        ASSERT(GetDisableDispatchCount() > 0);
-        disable_count--;
+        ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() > 0);
+        this->GetStackParameters().disable_count--;
+    }
+
+    void Pin();
+
+    void Unpin();
+
+    void SetInExceptionHandler() {
+        this->GetStackParameters().is_in_exception_handler = true;
+    }
+
+    void ClearInExceptionHandler() {
+        this->GetStackParameters().is_in_exception_handler = false;
+    }
+
+    [[nodiscard]] bool IsInExceptionHandler() const {
+        return this->GetStackParameters().is_in_exception_handler;
+    }
+
+    void SetIsCallingSvc() {
+        this->GetStackParameters().is_calling_svc = true;
+    }
+
+    void ClearIsCallingSvc() {
+        this->GetStackParameters().is_calling_svc = false;
+    }
+
+    [[nodiscard]] bool IsCallingSvc() const {
+        return this->GetStackParameters().is_calling_svc;
+    }
+
+    [[nodiscard]] u8 GetSvcId() const {
+        return this->GetStackParameters().current_svc_id;
+    }
+
+    void RegisterDpc(DpcFlag flag) {
+        this->GetStackParameters().dpc_flags |= static_cast<u8>(flag);
+    }
+
+    void ClearDpc(DpcFlag flag) {
+        this->GetStackParameters().dpc_flags &= ~static_cast<u8>(flag);
+    }
+
+    [[nodiscard]] u8 GetDpc() const {
+        return this->GetStackParameters().dpc_flags;
+    }
+
+    [[nodiscard]] bool HasDpc() const {
+        return this->GetDpc() != 0;
     }
 
     void SetWaitReasonForDebugging(ThreadWaitReasonForDebugging reason) {
@@ -507,10 +554,16 @@ public:
         return mutex_wait_address_for_debugging;
     }
 
+    [[nodiscard]] s32 GetIdealCoreForDebugging() const {
+        return virtual_ideal_core_id;
+    }
+
     void AddWaiter(KThread* thread);
 
     void RemoveWaiter(KThread* thread);
 
+    [[nodiscard]] ResultCode GetThreadContext3(std::vector<u8>& out);
+
     [[nodiscard]] KThread* RemoveWaiterByKey(s32* out_num_waiters, VAddr key);
 
     [[nodiscard]] VAddr GetAddressKey() const {
@@ -530,6 +583,22 @@ public:
         address_key_value = val;
     }
 
+    [[nodiscard]] bool HasWaiters() const {
+        return !waiter_list.empty();
+    }
+
+    [[nodiscard]] s32 GetNumKernelWaiters() const {
+        return num_kernel_waiters;
+    }
+
+    [[nodiscard]] u64 GetConditionVariableKey() const {
+        return condvar_key;
+    }
+
+    [[nodiscard]] u64 GetAddressArbiterKey() const {
+        return condvar_key;
+    }
+
 private:
     static constexpr size_t PriorityInheritanceCountMax = 10;
     union SyncObjectBuffer {
@@ -560,8 +629,8 @@ private:
             std::same_as<T, KThread> ||
             std::same_as<T, LightCompareType>) static constexpr int Compare(const T& lhs,
                                                                             const KThread& rhs) {
-            const uintptr_t l_key = lhs.GetConditionVariableKey();
-            const uintptr_t r_key = rhs.GetConditionVariableKey();
+            const u64 l_key = lhs.GetConditionVariableKey();
+            const u64 r_key = rhs.GetConditionVariableKey();
 
             if (l_key < r_key) {
                 // Sort first by key
@@ -575,26 +644,88 @@ private:
         }
     };
 
-    Common::IntrusiveRedBlackTreeNode condvar_arbiter_tree_node{};
+    void AddWaiterImpl(KThread* thread);
 
+    void RemoveWaiterImpl(KThread* thread);
+
+    void StartTermination();
+
+    [[nodiscard]] ResultCode Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top,
+                                        s32 prio, s32 virt_core, Process* owner, ThreadType type);
+
+    [[nodiscard]] static ResultCode InitializeThread(KThread* thread, KThreadFunction func,
+                                                     uintptr_t arg, VAddr user_stack_top, s32 prio,
+                                                     s32 core, Process* owner, ThreadType type);
+
+    static void RestorePriority(KernelCore& kernel, KThread* thread);
+
+    // For core KThread implementation
+    ThreadContext32 thread_context_32{};
+    ThreadContext64 thread_context_64{};
+    Common::IntrusiveRedBlackTreeNode condvar_arbiter_tree_node{};
+    s32 priority{};
     using ConditionVariableThreadTreeTraits =
         Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<
             &KThread::condvar_arbiter_tree_node>;
     using ConditionVariableThreadTree =
         ConditionVariableThreadTreeTraits::TreeType<ConditionVariableComparator>;
+    ConditionVariableThreadTree* condvar_tree{};
+    u64 condvar_key{};
+    u64 virtual_affinity_mask{};
+    KAffinityMask physical_affinity_mask{};
+    u64 thread_id{};
+    std::atomic<s64> cpu_time{};
+    KSynchronizationObject* synced_object{};
+    VAddr address_key{};
+    Process* parent{};
+    VAddr kernel_stack_top{};
+    u32* light_ipc_data{};
+    VAddr tls_address{};
+    KLightLock activity_pause_lock;
+    s64 schedule_count{};
+    s64 last_scheduled_tick{};
+    std::array<QueueEntry, Core::Hardware::NUM_CPU_CORES> per_core_priority_queue_entry{};
+    KThreadQueue* sleeping_queue{};
+    WaiterList waiter_list{};
+    WaiterList pinned_waiter_list{};
+    KThread* lock_owner{};
+    u32 address_key_value{};
+    u32 suspend_request_flags{};
+    u32 suspend_allowed_flags{};
+    ResultCode wait_result{RESULT_SUCCESS};
+    s32 base_priority{};
+    s32 physical_ideal_core_id{};
+    s32 virtual_ideal_core_id{};
+    s32 num_kernel_waiters{};
+    s32 current_core_id{};
+    s32 core_id{};
+    KAffinityMask original_physical_affinity_mask{};
+    s32 original_physical_ideal_core_id{};
+    s32 num_core_migration_disables{};
+    ThreadState thread_state{};
+    std::atomic<bool> termination_requested{};
+    bool wait_cancelled{};
+    bool cancellable{};
+    bool signaled{};
+    bool initialized{};
+    bool debug_attached{};
+    s8 priority_inheritance_count{};
+    bool resource_limit_release_hint{};
+    StackParameters stack_parameters{};
+
+    // For emulation
+    std::shared_ptr<Common::Fiber> host_context{};
+
+    // For debugging
+    std::vector<KSynchronizationObject*> wait_objects_for_debugging;
+    VAddr mutex_wait_address_for_debugging{};
+    ThreadWaitReasonForDebugging wait_reason_for_debugging{};
+    std::string name;
 
 public:
     using ConditionVariableThreadTreeType = ConditionVariableThreadTree;
 
-    [[nodiscard]] uintptr_t GetConditionVariableKey() const {
-        return condvar_key;
-    }
-
-    [[nodiscard]] uintptr_t GetAddressArbiterKey() const {
-        return condvar_key;
-    }
-
-    void SetConditionVariable(ConditionVariableThreadTree* tree, VAddr address, uintptr_t cv_key,
+    void SetConditionVariable(ConditionVariableThreadTree* tree, VAddr address, u64 cv_key,
                               u32 value) {
         condvar_tree = tree;
         condvar_key = cv_key;
@@ -610,7 +741,7 @@ public:
         return condvar_tree != nullptr;
     }
 
-    void SetAddressArbiter(ConditionVariableThreadTree* tree, uintptr_t address) {
+    void SetAddressArbiter(ConditionVariableThreadTree* tree, u64 address) {
         condvar_tree = tree;
         condvar_key = address;
     }
@@ -626,111 +757,6 @@ public:
     [[nodiscard]] ConditionVariableThreadTree* GetConditionVariableTree() const {
         return condvar_tree;
     }
-
-    [[nodiscard]] bool HasWaiters() const {
-        return !waiter_list.empty();
-    }
-
-private:
-    void AddSchedulingFlag(ThreadSchedFlags flag);
-    void RemoveSchedulingFlag(ThreadSchedFlags flag);
-    void AddWaiterImpl(KThread* thread);
-    void RemoveWaiterImpl(KThread* thread);
-    static void RestorePriority(KernelCore& kernel, KThread* thread);
-
-    Common::SpinLock context_guard{};
-    ThreadContext32 context_32{};
-    ThreadContext64 context_64{};
-    std::shared_ptr<Common::Fiber> host_context{};
-
-    ThreadState thread_state = ThreadState::Initialized;
-
-    u64 thread_id = 0;
-
-    VAddr entry_point = 0;
-    VAddr stack_top = 0;
-    std::atomic_int disable_count = 0;
-
-    ThreadType type;
-
-    /// Nominal thread priority, as set by the emulated application.
-    /// The nominal priority is the thread priority without priority
-    /// inheritance taken into account.
-    s32 base_priority{};
-
-    /// Current thread priority. This may change over the course of the
-    /// thread's lifetime in order to facilitate priority inheritance.
-    s32 current_priority{};
-
-    u64 total_cpu_time_ticks = 0; ///< Total CPU running ticks.
-    s64 schedule_count{};
-    s64 last_scheduled_tick{};
-
-    s32 processor_id = 0;
-
-    VAddr tls_address = 0; ///< Virtual address of the Thread Local Storage of the thread
-    u64 tpidr_el0 = 0;     ///< TPIDR_EL0 read/write system register.
-
-    /// Process that owns this thread
-    Process* owner_process;
-
-    /// Objects that the thread is waiting on, in the same order as they were
-    /// passed to WaitSynchronization. This is used for debugging only.
-    std::vector<KSynchronizationObject*> wait_objects_for_debugging;
-
-    /// The current mutex wait address. This is used for debugging only.
-    VAddr mutex_wait_address_for_debugging{};
-
-    /// The reason the thread is waiting. This is used for debugging only.
-    ThreadWaitReasonForDebugging wait_reason_for_debugging{};
-
-    KSynchronizationObject* signaling_object;
-    ResultCode signaling_result{RESULT_SUCCESS};
-
-    /// List of threads that are waiting for a mutex that is held by this thread.
-    MutexWaitingThreads wait_mutex_threads;
-
-    /// Thread that owns the lock that this thread is waiting for.
-    KThread* lock_owner{};
-
-    /// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
-    Handle global_handle = 0;
-
-    KScheduler* scheduler = nullptr;
-
-    std::array<QueueEntry, Core::Hardware::NUM_CPU_CORES> per_core_priority_queue_entry{};
-
-    u32 ideal_core{0xFFFFFFFF};
-    KAffinityMask affinity_mask{};
-
-    s32 ideal_core_override = -1;
-    u32 affinity_override_count = 0;
-
-    u32 pausing_state = 0;
-    bool is_running = false;
-    bool is_cancellable = false;
-    bool is_sync_cancelled = false;
-
-    bool is_continuous_on_svc = false;
-
-    bool will_be_terminated = false;
-    bool has_exited = false;
-
-    bool was_running = false;
-
-    bool signaled{};
-
-    ConditionVariableThreadTree* condvar_tree{};
-    uintptr_t condvar_key{};
-    VAddr address_key{};
-    u32 address_key_value{};
-    s32 num_kernel_waiters{};
-
-    using WaiterList = boost::intrusive::list<KThread>;
-    WaiterList waiter_list{};
-    WaiterList pinned_waiter_list{};
-
-    std::string name;
 };
 
 } // namespace Kernel
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 39d5122f5..d61659453 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -117,14 +117,14 @@ struct KernelCore::Impl {
     void InitializePhysicalCores() {
         exclusive_monitor =
             Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES);
-        for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
+        for (s32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
             schedulers[i] = std::make_unique<Kernel::KScheduler>(system, i);
             cores.emplace_back(i, system, *schedulers[i], interrupts);
         }
     }
 
     void InitializeSchedulers() {
-        for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
+        for (s32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
             cores[i].Scheduler().Initialize();
         }
     }
@@ -169,9 +169,9 @@ struct KernelCore::Impl {
             std::string name = "Suspend Thread Id:" + std::to_string(i);
             std::function<void(void*)> init_func = Core::CpuManager::GetSuspendThreadStartFunc();
             void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
-            auto thread_res = KThread::Create(system, ThreadType::Kernel, std::move(name), 0, 0, 0,
-                                              static_cast<u32>(i), 0, nullptr, std::move(init_func),
-                                              init_func_parameter);
+            auto thread_res = KThread::Create(system, ThreadType::HighPriority, std::move(name), 0,
+                                              0, 0, static_cast<u32>(i), 0, nullptr,
+                                              std::move(init_func), init_func_parameter);
 
             suspend_threads[i] = std::move(thread_res).Unwrap();
         }
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 819e275ff..9f4583b49 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -136,6 +136,23 @@ std::shared_ptr<ResourceLimit> Process::GetResourceLimit() const {
     return resource_limit;
 }
 
+void Process::IncrementThreadCount() {
+    ASSERT(num_threads >= 0);
+    ++num_created_threads;
+
+    if (const auto count = ++num_threads; count > peak_num_threads) {
+        peak_num_threads = count;
+    }
+}
+
+void Process::DecrementThreadCount() {
+    ASSERT(num_threads > 0);
+
+    if (const auto count = --num_threads; count == 0) {
+        UNIMPLEMENTED_MSG("Process termination is not implemented!");
+    }
+}
+
 u64 Process::GetTotalPhysicalMemoryAvailable() const {
     const u64 capacity{resource_limit->GetCurrentResourceValue(ResourceType::PhysicalMemory) +
                        page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size +
@@ -161,6 +178,61 @@ u64 Process::GetTotalPhysicalMemoryUsedWithoutSystemResource() const {
     return GetTotalPhysicalMemoryUsed() - GetSystemResourceUsage();
 }
 
+bool Process::ReleaseUserException(KThread* thread) {
+    KScopedSchedulerLock sl{kernel};
+
+    if (exception_thread == thread) {
+        exception_thread = nullptr;
+
+        // Remove waiter thread.
+        s32 num_waiters{};
+        KThread* next = thread->RemoveWaiterByKey(
+            std::addressof(num_waiters),
+            reinterpret_cast<uintptr_t>(std::addressof(exception_thread)));
+        if (next != nullptr) {
+            if (next->GetState() == ThreadState::Waiting) {
+                next->SetState(ThreadState::Runnable);
+            } else {
+                KScheduler::SetSchedulerUpdateNeeded(kernel);
+            }
+        }
+
+        return true;
+    } else {
+        return false;
+    }
+}
+
+void Process::PinCurrentThread() {
+    ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+
+    // Get the current thread.
+    const s32 core_id = GetCurrentCoreId(kernel);
+    KThread* cur_thread = GetCurrentThreadPointer(kernel);
+
+    // Pin it.
+    PinThread(core_id, cur_thread);
+    cur_thread->Pin();
+
+    // An update is needed.
+    KScheduler::SetSchedulerUpdateNeeded(kernel);
+}
+
+void Process::UnpinCurrentThread() {
+    ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+
+    // Get the current thread.
+    const s32 core_id = GetCurrentCoreId(kernel);
+    KThread* cur_thread = GetCurrentThreadPointer(kernel);
+
+    // Unpin it.
+    cur_thread->Unpin();
+    UnpinThread(core_id, cur_thread);
+
+    // An update is needed.
+    KScheduler::SetSchedulerUpdateNeeded(kernel);
+}
+
 void Process::RegisterThread(const KThread* thread) {
     thread_list.push_back(thread);
 }
@@ -278,7 +350,7 @@ void Process::PrepareForTermination() {
             ASSERT_MSG(thread->GetState() == ThreadState::Waiting,
                        "Exiting processes with non-waiting threads is currently unimplemented");
 
-            thread->Stop();
+            thread->Exit();
         }
     };
 
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 917babfb4..11d78f3a8 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -217,6 +217,14 @@ public:
         return is_64bit_process;
     }
 
+    [[nodiscard]] bool IsSuspended() const {
+        return is_suspended;
+    }
+
+    void SetSuspended(bool suspended) {
+        is_suspended = suspended;
+    }
+
     /// Gets the total running time of the process instance in ticks.
     u64 GetCPUTimeTicks() const {
         return total_process_running_time_ticks;
@@ -237,6 +245,33 @@ public:
         ++schedule_count;
     }
 
+    void IncrementThreadCount();
+    void DecrementThreadCount();
+
+    void SetRunningThread(s32 core, KThread* thread, u64 idle_count) {
+        running_threads[core] = thread;
+        running_thread_idle_counts[core] = idle_count;
+    }
+
+    void ClearRunningThread(KThread* thread) {
+        for (size_t i = 0; i < running_threads.size(); ++i) {
+            if (running_threads[i] == thread) {
+                running_threads[i] = nullptr;
+            }
+        }
+    }
+
+    [[nodiscard]] KThread* GetRunningThread(s32 core) const {
+        return running_threads[core];
+    }
+
+    bool ReleaseUserException(KThread* thread);
+
+    [[nodiscard]] KThread* GetPinnedThread(s32 core_id) const {
+        ASSERT(0 <= core_id && core_id < static_cast<s32>(Core::Hardware::NUM_CPU_CORES));
+        return pinned_threads[core_id];
+    }
+
     /// Gets 8 bytes of random data for svcGetInfo RandomEntropy
     u64 GetRandomEntropy(std::size_t index) const {
         return random_entropy.at(index);
@@ -310,6 +345,9 @@ public:
 
     void Finalize() override {}
 
+    void PinCurrentThread();
+    void UnpinCurrentThread();
+
     ///////////////////////////////////////////////////////////////////////////////////////////////
     // Thread-local storage management
 
@@ -320,6 +358,20 @@ public:
     void FreeTLSRegion(VAddr tls_address);
 
 private:
+    void PinThread(s32 core_id, KThread* thread) {
+        ASSERT(0 <= core_id && core_id < static_cast<s32>(Core::Hardware::NUM_CPU_CORES));
+        ASSERT(thread != nullptr);
+        ASSERT(pinned_threads[core_id] == nullptr);
+        pinned_threads[core_id] = thread;
+    }
+
+    void UnpinThread(s32 core_id, KThread* thread) {
+        ASSERT(0 <= core_id && core_id < static_cast<s32>(Core::Hardware::NUM_CPU_CORES));
+        ASSERT(thread != nullptr);
+        ASSERT(pinned_threads[core_id] == thread);
+        pinned_threads[core_id] = nullptr;
+    }
+
     /// Changes the process status. If the status is different
     /// from the current process status, then this will trigger
     /// a process signal.
@@ -408,6 +460,17 @@ private:
     s64 schedule_count{};
 
     bool is_signaled{};
+    bool is_suspended{};
+
+    std::atomic<s32> num_created_threads{};
+    std::atomic<u16> num_threads{};
+    u16 peak_num_threads{};
+
+    std::array<KThread*, Core::Hardware::NUM_CPU_CORES> running_threads{};
+    std::array<u64, Core::Hardware::NUM_CPU_CORES> running_thread_idle_counts{};
+    std::array<KThread*, Core::Hardware::NUM_CPU_CORES> pinned_threads{};
+
+    KThread* exception_thread{};
 
     /// System context
     Core::System& system;
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 280c9b5f6..790dbb998 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -154,7 +154,7 @@ ResultCode ServerSession::CompleteSyncRequest(HLERequestContext& context) {
         KScopedSchedulerLock lock(kernel);
         if (!context.IsThreadWaiting()) {
             context.GetThread().Wakeup();
-            context.GetThread().SetSynchronizationResults(nullptr, result);
+            context.GetThread().SetSyncedObject(nullptr, result);
         }
     }
 
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 2512bfd98..dbef854f8 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -351,7 +351,8 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
         session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming());
     }
 
-    return thread->GetSignalingResult();
+    KSynchronizationObject* dummy{};
+    return thread->GetWaitResult(std::addressof(dummy));
 }
 
 static ResultCode SendSyncRequest32(Core::System& system, Handle handle) {
@@ -359,27 +360,26 @@ static ResultCode SendSyncRequest32(Core::System& system, Handle handle) {
 }
 
 /// Get the ID for the specified thread.
-static ResultCode GetThreadId(Core::System& system, u64* thread_id, Handle thread_handle) {
+static ResultCode GetThreadId(Core::System& system, u64* out_thread_id, Handle thread_handle) {
     LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
 
+    // Get the thread from its handle.
     const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
     const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
-    if (!thread) {
-        LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", thread_handle);
-        return ERR_INVALID_HANDLE;
-    }
+    R_UNLESS(thread, Svc::ResultInvalidHandle);
 
-    *thread_id = thread->GetThreadID();
+    // Get the thread's id.
+    *out_thread_id = thread->GetThreadID();
     return RESULT_SUCCESS;
 }
 
-static ResultCode GetThreadId32(Core::System& system, u32* thread_id_low, u32* thread_id_high,
-                                Handle thread_handle) {
-    u64 thread_id{};
-    const ResultCode result{GetThreadId(system, &thread_id, thread_handle)};
+static ResultCode GetThreadId32(Core::System& system, u32* out_thread_id_low,
+                                u32* out_thread_id_high, Handle thread_handle) {
+    u64 out_thread_id{};
+    const ResultCode result{GetThreadId(system, &out_thread_id, thread_handle)};
 
-    *thread_id_low = static_cast<u32>(thread_id >> 32);
-    *thread_id_high = static_cast<u32>(thread_id & std::numeric_limits<u32>::max());
+    *out_thread_id_low = static_cast<u32>(out_thread_id >> 32);
+    *out_thread_id_high = static_cast<u32>(out_thread_id & std::numeric_limits<u32>::max());
 
     return result;
 }
@@ -473,15 +473,13 @@ static ResultCode WaitSynchronization32(Core::System& system, u32 timeout_low, u
 static ResultCode CancelSynchronization(Core::System& system, Handle thread_handle) {
     LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle);
 
+    // Get the thread from its handle.
     const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
     std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
-    if (!thread) {
-        LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
-                  thread_handle);
-        return ERR_INVALID_HANDLE;
-    }
+    R_UNLESS(thread, Svc::ResultInvalidHandle);
 
-    thread->CancelWait();
+    // Cancel the thread's wait.
+    thread->WaitCancel();
     return RESULT_SUCCESS;
 }
 
@@ -630,7 +628,7 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) {
         handle_debug_buffer(info1, info2);
 
         auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread();
-        const auto thread_processor_id = current_thread->GetProcessorID();
+        const auto thread_processor_id = current_thread->GetActiveCore();
         system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace();
     }
 }
@@ -888,7 +886,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
         const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTicks();
         u64 out_ticks = 0;
         if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) {
-            const u64 thread_ticks = current_thread->GetTotalCPUTimeTicks();
+            const u64 thread_ticks = current_thread->GetCpuTime();
 
             out_ticks = thread_ticks + (core_timing.GetCPUTicks() - prev_ctx_ticks);
         } else if (same_thread && info_sub_id == system.CurrentCoreIndex()) {
@@ -1025,127 +1023,109 @@ static ResultCode UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 size
     return UnmapPhysicalMemory(system, addr, size);
 }
 
-/// Sets the thread activity
-static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 activity) {
-    LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", handle, activity);
-    if (activity > static_cast<u32>(ThreadActivity::Paused)) {
-        return ERR_INVALID_ENUM_VALUE;
+constexpr bool IsValidThreadActivity(Svc::ThreadActivity thread_activity) {
+    switch (thread_activity) {
+    case Svc::ThreadActivity::Runnable:
+    case Svc::ThreadActivity::Paused:
+        return true;
+    default:
+        return false;
     }
-
-    const auto* current_process = system.Kernel().CurrentProcess();
-    const std::shared_ptr<KThread> thread = current_process->GetHandleTable().Get<KThread>(handle);
-    if (!thread) {
-        LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
-        return ERR_INVALID_HANDLE;
-    }
-
-    if (thread->GetOwnerProcess() != current_process) {
-        LOG_ERROR(Kernel_SVC,
-                  "The current process does not own the current thread, thread_handle={:08X} "
-                  "thread_pid={}, "
-                  "current_process_pid={}",
-                  handle, thread->GetOwnerProcess()->GetProcessID(),
-                  current_process->GetProcessID());
-        return ERR_INVALID_HANDLE;
-    }
-
-    if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) {
-        LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread");
-        return ERR_BUSY;
-    }
-
-    return thread->SetActivity(static_cast<ThreadActivity>(activity));
 }
 
-static ResultCode SetThreadActivity32(Core::System& system, Handle handle, u32 activity) {
-    return SetThreadActivity(system, handle, activity);
+/// Sets the thread activity
+static ResultCode SetThreadActivity(Core::System& system, Handle thread_handle,
+                                    Svc::ThreadActivity thread_activity) {
+    LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", thread_handle,
+              thread_activity);
+
+    // Validate the activity.
+    R_UNLESS(IsValidThreadActivity(thread_activity), Svc::ResultInvalidEnumValue);
+
+    // Get the thread from its handle.
+    auto& kernel = system.Kernel();
+    const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
+    const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
+    R_UNLESS(thread, Svc::ResultInvalidHandle);
+
+    // Check that the activity is being set on a non-current thread for the current process.
+    R_UNLESS(thread->GetOwnerProcess() == kernel.CurrentProcess(), Svc::ResultInvalidHandle);
+    R_UNLESS(thread.get() != GetCurrentThreadPointer(kernel), Svc::ResultBusy);
+
+    // Set the activity.
+    R_TRY(thread->SetActivity(thread_activity));
+
+    return RESULT_SUCCESS;
+}
+
+static ResultCode SetThreadActivity32(Core::System& system, Handle thread_handle,
+                                      Svc::ThreadActivity thread_activity) {
+    return SetThreadActivity(system, thread_handle, thread_activity);
 }
 
 /// Gets the thread context
-static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, Handle handle) {
-    LOG_DEBUG(Kernel_SVC, "called, context=0x{:08X}, thread=0x{:X}", thread_context, handle);
+static ResultCode GetThreadContext(Core::System& system, VAddr out_context, Handle thread_handle) {
+    LOG_DEBUG(Kernel_SVC, "called, out_context=0x{:08X}, thread_handle=0x{:X}", out_context,
+              thread_handle);
 
+    // Get the thread from its handle.
     const auto* current_process = system.Kernel().CurrentProcess();
-    const std::shared_ptr<KThread> thread = current_process->GetHandleTable().Get<KThread>(handle);
-    if (!thread) {
-        LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
-        return ERR_INVALID_HANDLE;
-    }
+    const std::shared_ptr<KThread> thread =
+        current_process->GetHandleTable().Get<KThread>(thread_handle);
+    R_UNLESS(thread, Svc::ResultInvalidHandle);
 
-    if (thread->GetOwnerProcess() != current_process) {
-        LOG_ERROR(Kernel_SVC,
-                  "The current process does not own the current thread, thread_handle={:08X} "
-                  "thread_pid={}, "
-                  "current_process_pid={}",
-                  handle, thread->GetOwnerProcess()->GetProcessID(),
-                  current_process->GetProcessID());
-        return ERR_INVALID_HANDLE;
-    }
+    // Require the handle be to a non-current thread in the current process.
+    R_UNLESS(thread->GetOwnerProcess() == current_process, Svc::ResultInvalidHandle);
+    R_UNLESS(thread.get() != system.Kernel().CurrentScheduler()->GetCurrentThread(),
+             Svc::ResultBusy);
 
-    if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) {
-        LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread");
-        return ERR_BUSY;
-    }
+    // Get the thread context.
+    std::vector<u8> context;
+    R_TRY(thread->GetThreadContext3(context));
 
-    Core::ARM_Interface::ThreadContext64 ctx = thread->GetContext64();
-    // Mask away mode bits, interrupt bits, IL bit, and other reserved bits.
-    ctx.pstate &= 0xFF0FFE20;
+    // Copy the thread context to user space.
+    system.Memory().WriteBlock(out_context, context.data(), context.size());
 
-    // If 64-bit, we can just write the context registers directly and we're good.
-    // However, if 32-bit, we have to ensure some registers are zeroed out.
-    if (!current_process->Is64BitProcess()) {
-        std::fill(ctx.cpu_registers.begin() + 15, ctx.cpu_registers.end(), 0);
-        std::fill(ctx.vector_registers.begin() + 16, ctx.vector_registers.end(), u128{});
-    }
-
-    system.Memory().WriteBlock(thread_context, &ctx, sizeof(ctx));
     return RESULT_SUCCESS;
 }
 
-static ResultCode GetThreadContext32(Core::System& system, u32 thread_context, Handle handle) {
-    return GetThreadContext(system, thread_context, handle);
+static ResultCode GetThreadContext32(Core::System& system, u32 out_context, Handle thread_handle) {
+    return GetThreadContext(system, out_context, thread_handle);
 }
 
 /// Gets the priority for the specified thread
-static ResultCode GetThreadPriority(Core::System& system, u32* priority, Handle handle) {
+static ResultCode GetThreadPriority(Core::System& system, u32* out_priority, Handle handle) {
     LOG_TRACE(Kernel_SVC, "called");
 
+    // Get the thread from its handle.
     const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
     const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle);
-    if (!thread) {
-        *priority = 0;
-        LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
-        return ERR_INVALID_HANDLE;
-    }
+    R_UNLESS(thread, Svc::ResultInvalidHandle);
 
-    *priority = thread->GetPriority();
+    // Get the thread's priority.
+    *out_priority = thread->GetPriority();
     return RESULT_SUCCESS;
 }
 
-static ResultCode GetThreadPriority32(Core::System& system, u32* priority, Handle handle) {
-    return GetThreadPriority(system, priority, handle);
+static ResultCode GetThreadPriority32(Core::System& system, u32* out_priority, Handle handle) {
+    return GetThreadPriority(system, out_priority, handle);
 }
 
 /// Sets the priority for the specified thread
 static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 priority) {
     LOG_TRACE(Kernel_SVC, "called");
 
-    if (priority > Svc::LowestThreadPriority) {
-        LOG_ERROR(Kernel_SVC, "An invalid priority was specified {} for thread_handle={:08X}",
-                  priority, handle);
-        return ERR_INVALID_THREAD_PRIORITY;
-    }
+    // Validate the priority.
+    R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority,
+             Svc::ResultInvalidPriority);
 
-    const auto* const current_process = system.Kernel().CurrentProcess();
-
-    std::shared_ptr<KThread> thread = current_process->GetHandleTable().Get<KThread>(handle);
-    if (!thread) {
-        LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
-        return ERR_INVALID_HANDLE;
-    }
+    // Get the thread from its handle.
+    const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
+    const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle);
+    R_UNLESS(thread, Svc::ResultInvalidHandle);
 
+    // Set the thread priority.
     thread->SetBasePriority(priority);
-
     return RESULT_SUCCESS;
 }
 
@@ -1436,7 +1416,7 @@ static void ExitProcess(Core::System& system) {
     current_process->PrepareForTermination();
 
     // Kill the current thread
-    system.Kernel().CurrentScheduler()->GetCurrentThread()->Stop();
+    system.Kernel().CurrentScheduler()->GetCurrentThread()->Exit();
 }
 
 static void ExitProcess32(Core::System& system) {
@@ -1500,17 +1480,15 @@ static ResultCode CreateThread32(Core::System& system, Handle* out_handle, u32 p
 static ResultCode StartThread(Core::System& system, Handle thread_handle) {
     LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
 
+    // Get the thread from its handle.
     const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
     const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
-    if (!thread) {
-        LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
-                  thread_handle);
-        return ERR_INVALID_HANDLE;
-    }
+    R_UNLESS(thread, Svc::ResultInvalidHandle);
 
-    ASSERT(thread->GetState() == ThreadState::Initialized);
+    // Try to start the thread.
+    R_TRY(thread->Run());
 
-    return thread->Start();
+    return RESULT_SUCCESS;
 }
 
 static ResultCode StartThread32(Core::System& system, Handle thread_handle) {
@@ -1523,7 +1501,7 @@ static void ExitThread(Core::System& system) {
 
     auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread();
     system.GlobalSchedulerContext().RemoveThread(SharedFrom(current_thread));
-    current_thread->Stop();
+    current_thread->Exit();
 }
 
 static void ExitThread32(Core::System& system) {
@@ -1532,34 +1510,28 @@ static void ExitThread32(Core::System& system) {
 
 /// Sleep the current thread
 static void SleepThread(Core::System& system, s64 nanoseconds) {
+    auto& kernel = system.Kernel();
+    const auto yield_type = static_cast<Svc::YieldType>(nanoseconds);
+
     LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds);
 
-    enum class SleepType : s64 {
-        YieldWithoutCoreMigration = 0,
-        YieldWithCoreMigration = -1,
-        YieldAndWaitForLoadBalancing = -2,
-    };
+    // When the input tick is positive, sleep.
+    if (nanoseconds > 0) {
+        // Convert the timeout from nanoseconds to ticks.
+        // NOTE: Nintendo does not use this conversion logic in WaitSynchronization...
 
-    auto& scheduler = *system.Kernel().CurrentScheduler();
-    if (nanoseconds <= 0) {
-        switch (static_cast<SleepType>(nanoseconds)) {
-        case SleepType::YieldWithoutCoreMigration: {
-            scheduler.YieldWithoutCoreMigration();
-            break;
-        }
-        case SleepType::YieldWithCoreMigration: {
-            scheduler.YieldWithCoreMigration();
-            break;
-        }
-        case SleepType::YieldAndWaitForLoadBalancing: {
-            scheduler.YieldToAnyThread();
-            break;
-        }
-        default:
-            UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds);
-        }
+        // Sleep.
+        // NOTE: Nintendo does not check the result of this sleep.
+        static_cast<void>(GetCurrentThread(kernel).Sleep(nanoseconds));
+    } else if (yield_type == Svc::YieldType::WithoutCoreMigration) {
+        KScheduler::YieldWithoutCoreMigration(kernel);
+    } else if (yield_type == Svc::YieldType::WithCoreMigration) {
+        KScheduler::YieldWithCoreMigration(kernel);
+    } else if (yield_type == Svc::YieldType::ToAnyThread) {
+        KScheduler::YieldToAnyThread(kernel);
     } else {
-        scheduler.GetCurrentThread()->Sleep(nanoseconds);
+        // Nintendo does nothing at all if an otherwise invalid value is passed.
+        UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds);
     }
 }
 
@@ -1822,95 +1794,72 @@ static ResultCode CreateTransferMemory32(Core::System& system, Handle* handle, u
     return CreateTransferMemory(system, handle, addr, size, permissions);
 }
 
-static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, u32* core,
-                                    u64* mask) {
+static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, s32* out_core_id,
+                                    u64* out_affinity_mask) {
     LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle);
 
+    // Get the thread from its handle.
     const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
     const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
-    if (!thread) {
-        LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
-                  thread_handle);
-        *core = 0;
-        *mask = 0;
-        return ERR_INVALID_HANDLE;
-    }
+    R_UNLESS(thread, Svc::ResultInvalidHandle);
 
-    *core = thread->GetIdealCore();
-    *mask = thread->GetAffinityMask().GetAffinityMask();
+    // Get the core mask.
+    R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask));
 
     return RESULT_SUCCESS;
 }
 
-static ResultCode GetThreadCoreMask32(Core::System& system, Handle thread_handle, u32* core,
-                                      u32* mask_low, u32* mask_high) {
-    u64 mask{};
-    const auto result = GetThreadCoreMask(system, thread_handle, core, &mask);
-    *mask_high = static_cast<u32>(mask >> 32);
-    *mask_low = static_cast<u32>(mask);
+static ResultCode GetThreadCoreMask32(Core::System& system, Handle thread_handle, s32* out_core_id,
+                                      u32* out_affinity_mask_low, u32* out_affinity_mask_high) {
+    u64 out_affinity_mask{};
+    const auto result = GetThreadCoreMask(system, thread_handle, out_core_id, &out_affinity_mask);
+    *out_affinity_mask_high = static_cast<u32>(out_affinity_mask >> 32);
+    *out_affinity_mask_low = static_cast<u32>(out_affinity_mask);
     return result;
 }
 
-static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, u32 core,
+static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, s32 core_id,
                                     u64 affinity_mask) {
-    LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core=0x{:X}, affinity_mask=0x{:016X}",
-              thread_handle, core, affinity_mask);
+    LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core_id=0x{:X}, affinity_mask=0x{:016X}",
+              thread_handle, core_id, affinity_mask);
 
-    const auto* const current_process = system.Kernel().CurrentProcess();
+    const auto& current_process = *system.Kernel().CurrentProcess();
 
-    if (core == static_cast<u32>(Svc::IdealCoreUseProcessValue)) {
-        const u8 ideal_cpu_core = current_process->GetIdealCoreId();
-
-        ASSERT(ideal_cpu_core != static_cast<u8>(Svc::IdealCoreUseProcessValue));
-
-        // Set the target CPU to the ideal core specified by the process.
-        core = ideal_cpu_core;
-        affinity_mask = 1ULL << core;
+    // Determine the core id/affinity mask.
+    if (core_id == Svc::IdealCoreUseProcessValue) {
+        core_id = current_process.GetIdealCoreId();
+        affinity_mask = (1ULL << core_id);
     } else {
-        const u64 core_mask = current_process->GetCoreMask();
+        // Validate the affinity mask.
+        const u64 process_core_mask = current_process.GetCoreMask();
+        R_UNLESS((affinity_mask | process_core_mask) == process_core_mask,
+                 Svc::ResultInvalidCoreId);
+        R_UNLESS(affinity_mask != 0, Svc::ResultInvalidCombination);
 
-        if ((core_mask | affinity_mask) != core_mask) {
-            LOG_ERROR(
-                Kernel_SVC,
-                "Invalid processor ID specified (core_mask=0x{:08X}, affinity_mask=0x{:016X})",
-                core_mask, affinity_mask);
-            return ERR_INVALID_PROCESSOR_ID;
-        }
-
-        if (affinity_mask == 0) {
-            LOG_ERROR(Kernel_SVC, "Specfified affinity mask is zero.");
-            return ERR_INVALID_COMBINATION;
-        }
-
-        if (core < Core::Hardware::NUM_CPU_CORES) {
-            if ((affinity_mask & (1ULL << core)) == 0) {
-                LOG_ERROR(Kernel_SVC,
-                          "Core is not enabled for the current mask, core={}, mask={:016X}", core,
-                          affinity_mask);
-                return ERR_INVALID_COMBINATION;
-            }
-        } else if (core != static_cast<u32>(Svc::IdealCoreDontCare) &&
-                   core != static_cast<u32>(Svc::IdealCoreNoUpdate)) {
-            LOG_ERROR(Kernel_SVC, "Invalid processor ID specified (core={}).", core);
-            return ERR_INVALID_PROCESSOR_ID;
+        // Validate the core id.
+        if (IsValidCoreId(core_id)) {
+            R_UNLESS(((1ULL << core_id) & affinity_mask) != 0, Svc::ResultInvalidCombination);
+        } else {
+            R_UNLESS(core_id == Svc::IdealCoreNoUpdate || core_id == Svc::IdealCoreDontCare,
+                     Svc::ResultInvalidCoreId);
         }
     }
 
-    const auto& handle_table = current_process->GetHandleTable();
+    // Get the thread from its handle.
+    const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
     const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
-    if (!thread) {
-        LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
-                  thread_handle);
-        return ERR_INVALID_HANDLE;
-    }
+    R_UNLESS(thread, Svc::ResultInvalidHandle);
 
-    return thread->SetCoreAndAffinityMask(core, affinity_mask);
+    // Set the core mask.
+    R_TRY(thread->SetCoreMask(core_id, affinity_mask));
+
+    return RESULT_SUCCESS;
 }
 
-static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle, u32 core,
+static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle, s32 core_id,
                                       u32 affinity_mask_low, u32 affinity_mask_high) {
     const auto affinity_mask = u64{affinity_mask_low} | (u64{affinity_mask_high} << 32);
-    return SetThreadCoreMask(system, thread_handle, core, affinity_mask);
+    return SetThreadCoreMask(system, thread_handle, core_id, affinity_mask);
 }
 
 static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle* read_handle) {
@@ -2474,7 +2423,7 @@ void Call(Core::System& system, u32 immediate) {
     kernel.EnterSVCProfile();
 
     auto* thread = kernel.CurrentScheduler()->GetCurrentThread();
-    thread->SetContinuousOnSVC(true);
+    thread->SetIsCallingSvc();
 
     const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate)
                                                                         : GetSVCInfo32(immediate);
@@ -2490,7 +2439,7 @@ void Call(Core::System& system, u32 immediate) {
 
     kernel.ExitSVCProfile();
 
-    if (!thread->IsContinuousOnSVC()) {
+    if (!thread->IsCallingSvc()) {
         auto* host_context = thread->GetHostContext().get();
         host_context->Rewind();
     }
diff --git a/src/core/hle/kernel/svc_types.h b/src/core/hle/kernel/svc_types.h
index ded55af9a..ec463b97c 100644
--- a/src/core/hle/kernel/svc_types.h
+++ b/src/core/hle/kernel/svc_types.h
@@ -77,6 +77,12 @@ enum class ArbitrationType : u32 {
     WaitIfEqual = 2,
 };
 
+enum class YieldType : s64 {
+    WithoutCoreMigration = 0,
+    WithCoreMigration = -1,
+    ToAnyThread = -2,
+};
+
 enum class ThreadActivity : u32 {
     Runnable = 0,
     Paused = 1,
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h
index a32750ed7..96afd544b 100644
--- a/src/core/hle/kernel/svc_wrap.h
+++ b/src/core/hle/kernel/svc_wrap.h
@@ -58,6 +58,14 @@ void SvcWrap64(Core::System& system) {
         func(system, static_cast<u32>(Param(system, 0)), static_cast<u32>(Param(system, 1))).raw);
 }
 
+// Used by SetThreadActivity
+template <ResultCode func(Core::System&, Handle, Svc::ThreadActivity)>
+void SvcWrap64(Core::System& system) {
+    FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)),
+                            static_cast<Svc::ThreadActivity>(Param(system, 1)))
+                           .raw);
+}
+
 template <ResultCode func(Core::System&, u32, u64, u64, u64)>
 void SvcWrap64(Core::System& system) {
     FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1),
@@ -158,9 +166,18 @@ void SvcWrap64(Core::System& system) {
                            .raw);
 }
 
-template <ResultCode func(Core::System&, u32, u32*, u64*)>
+// Used by SetThreadCoreMask
+template <ResultCode func(Core::System&, Handle, s32, u64)>
 void SvcWrap64(Core::System& system) {
-    u32 param_1 = 0;
+    FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)),
+                            static_cast<s32>(Param(system, 1)), Param(system, 2))
+                           .raw);
+}
+
+// Used by GetThreadCoreMask
+template <ResultCode func(Core::System&, Handle, s32*, u64*)>
+void SvcWrap64(Core::System& system) {
+    s32 param_1 = 0;
     u64 param_2 = 0;
     const ResultCode retval = func(system, static_cast<u32>(Param(system, 2)), &param_1, &param_2);
 
@@ -473,12 +490,35 @@ void SvcWrap32(Core::System& system) {
     FuncReturn(system, retval);
 }
 
+// Used by GetThreadCoreMask32
+template <ResultCode func(Core::System&, Handle, s32*, u32*, u32*)>
+void SvcWrap32(Core::System& system) {
+    s32 param_1 = 0;
+    u32 param_2 = 0;
+    u32 param_3 = 0;
+
+    const u32 retval = func(system, Param32(system, 2), &param_1, &param_2, &param_3).raw;
+    system.CurrentArmInterface().SetReg(1, param_1);
+    system.CurrentArmInterface().SetReg(2, param_2);
+    system.CurrentArmInterface().SetReg(3, param_3);
+    FuncReturn(system, retval);
+}
+
 // Used by SignalProcessWideKey32
 template <void func(Core::System&, u32, s32)>
 void SvcWrap32(Core::System& system) {
     func(system, static_cast<u32>(Param(system, 0)), static_cast<s32>(Param(system, 1)));
 }
 
+// Used by SetThreadActivity32
+template <ResultCode func(Core::System&, Handle, Svc::ThreadActivity)>
+void SvcWrap32(Core::System& system) {
+    const u32 retval = func(system, static_cast<Handle>(Param(system, 0)),
+                            static_cast<Svc::ThreadActivity>(Param(system, 1)))
+                           .raw;
+    FuncReturn(system, retval);
+}
+
 // Used by SetThreadPriority32
 template <ResultCode func(Core::System&, Handle, u32)>
 void SvcWrap32(Core::System& system) {
@@ -487,7 +527,7 @@ void SvcWrap32(Core::System& system) {
     FuncReturn(system, retval);
 }
 
-// Used by SetThreadCoreMask32
+// Used by SetMemoryAttribute32
 template <ResultCode func(Core::System&, Handle, u32, u32, u32)>
 void SvcWrap32(Core::System& system) {
     const u32 retval =
@@ -497,6 +537,16 @@ void SvcWrap32(Core::System& system) {
     FuncReturn(system, retval);
 }
 
+// Used by SetThreadCoreMask32
+template <ResultCode func(Core::System&, Handle, s32, u32, u32)>
+void SvcWrap32(Core::System& system) {
+    const u32 retval =
+        func(system, static_cast<Handle>(Param(system, 0)), static_cast<s32>(Param(system, 1)),
+             static_cast<u32>(Param(system, 2)), static_cast<u32>(Param(system, 3)))
+            .raw;
+    FuncReturn(system, retval);
+}
+
 // Used by WaitProcessWideKeyAtomic32
 template <ResultCode func(Core::System&, u32, u32, Handle, u32, u32)>
 void SvcWrap32(Core::System& system) {
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp
index d6354b01d..cbec692f9 100644
--- a/src/yuzu/debugger/wait_tree.cpp
+++ b/src/yuzu/debugger/wait_tree.cpp
@@ -235,12 +235,8 @@ QString WaitTreeThread::GetText() const {
     QString status;
     switch (thread.GetState()) {
     case Kernel::ThreadState::Runnable:
-        if (!thread.IsPaused()) {
-            if (thread.WasRunning()) {
-                status = tr("running");
-            } else {
-                status = tr("ready");
-            }
+        if (!thread.IsSuspended()) {
+            status = tr("runnable");
         } else {
             status = tr("paused");
         }
@@ -295,12 +291,8 @@ QColor WaitTreeThread::GetColor() const {
     const auto& thread = static_cast<const Kernel::KThread&>(object);
     switch (thread.GetState()) {
     case Kernel::ThreadState::Runnable:
-        if (!thread.IsPaused()) {
-            if (thread.WasRunning()) {
-                return QColor(WaitTreeColors[0][color_index]);
-            } else {
-                return QColor(WaitTreeColors[1][color_index]);
-            }
+        if (!thread.IsSuspended()) {
+            return QColor(WaitTreeColors[0][color_index]);
         } else {
             return QColor(WaitTreeColors[2][color_index]);
         }
@@ -334,18 +326,18 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
     const auto& thread = static_cast<const Kernel::KThread&>(object);
 
     QString processor;
-    switch (thread.GetProcessorID()) {
+    switch (thread.GetActiveCore()) {
     case Kernel::Svc::IdealCoreUseProcessValue:
         processor = tr("ideal");
         break;
     default:
-        processor = tr("core %1").arg(thread.GetProcessorID());
+        processor = tr("core %1").arg(thread.GetActiveCore());
         break;
     }
 
     list.push_back(std::make_unique<WaitTreeText>(tr("processor = %1").arg(processor)));
-    list.push_back(
-        std::make_unique<WaitTreeText>(tr("ideal core = %1").arg(thread.GetIdealCore())));
+    list.push_back(std::make_unique<WaitTreeText>(
+        tr("ideal core = %1").arg(thread.GetIdealCoreForDebugging())));
     list.push_back(std::make_unique<WaitTreeText>(
         tr("affinity mask = %1").arg(thread.GetAffinityMask().GetAffinityMask())));
     list.push_back(std::make_unique<WaitTreeText>(tr("thread id = %1").arg(thread.GetThreadID())));

From ca78f77827376af1cd42f655dca6f8d1d2725200 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Wed, 20 Jan 2021 16:47:57 -0800
Subject: [PATCH 19/34] hle: kernel: KScheduler: Introduce thread
 context_guard.

---
 src/core/hle/kernel/k_scheduler.cpp | 18 +++++++++++++++---
 src/core/hle/kernel/k_thread.h      |  1 +
 2 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index 5bdbd9a9b..e99122f4c 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -668,6 +668,7 @@ void KScheduler::Unload(KThread* thread) {
         } else {
             prev_thread = nullptr;
         }
+        thread->context_guard.unlock();
     }
 }
 
@@ -700,15 +701,23 @@ void KScheduler::SwitchContextStep2() {
 
 void KScheduler::ScheduleImpl() {
     KThread* previous_thread = current_thread;
-    current_thread = state.highest_priority_thread;
+    KThread* next_thread = state.highest_priority_thread;
 
     state.needs_scheduling = false;
 
-    if (current_thread == previous_thread) {
+    // 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;
+    }
+
+    // If we're not actually switching thread, there's nothing to do.
+    if (next_thread == current_thread) {
         guard.unlock();
         return;
     }
 
+    current_thread = next_thread;
+
     Process* const previous_process = system.Kernel().CurrentProcess();
 
     UpdateLastContextSwitchTime(previous_thread, previous_process);
@@ -748,10 +757,13 @@ void KScheduler::SwitchToCurrent() {
         };
         do {
             if (current_thread != nullptr) {
+                current_thread->context_guard.lock();
                 if (current_thread->GetRawState() != ThreadState::Runnable) {
+                    current_thread->context_guard.unlock();
                     break;
                 }
-                if (static_cast<u32>(current_thread->GetActiveCore()) != core_id) {
+                if (current_thread->GetActiveCore() != core_id) {
+                    current_thread->context_guard.unlock();
                     break;
                 }
             }
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index 7845821ba..eeddf5a65 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -712,6 +712,7 @@ private:
     s8 priority_inheritance_count{};
     bool resource_limit_release_hint{};
     StackParameters stack_parameters{};
+    Common::SpinLock context_guard{};
 
     // For emulation
     std::shared_ptr<Common::Fiber> host_context{};

From 89a5ae92bdeb451943665868f59e364259368f11 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Wed, 20 Jan 2021 17:18:04 -0800
Subject: [PATCH 20/34] core: cpu_manager: Remove unused variable.

---
 src/core/cpu_manager.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index 9bbb82b97..8f04fb8f5 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -208,7 +208,6 @@ void CpuManager::SingleCoreRunGuestThread() {
 
 void CpuManager::SingleCoreRunGuestLoop() {
     auto& kernel = system.Kernel();
-    auto* thread = kernel.CurrentScheduler()->GetCurrentThread();
     while (true) {
         auto* physical_core = &kernel.CurrentPhysicalCore();
         system.EnterDynarmicProfile();

From 0a1449e04b99b2fe49b047f50174a60c2abb568c Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Wed, 20 Jan 2021 18:10:07 -0800
Subject: [PATCH 21/34] kernel: Fix build errors.

---
 src/core/hle/kernel/k_thread.cpp | 9 +++++++--
 src/core/hle/kernel/kernel.cpp   | 4 ++--
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index f021b0550..62ce2fbd5 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -1015,8 +1015,13 @@ ResultVal<std::shared_ptr<KThread>> KThread::Create(Core::System& system, Thread
 
     std::shared_ptr<KThread> thread = std::make_shared<KThread>(kernel);
 
-    thread->InitializeThread(thread.get(), entry_point, arg, stack_top, priority, processor_id,
-                             owner_process, type_flags);
+    if (const auto result =
+            thread->InitializeThread(thread.get(), entry_point, arg, stack_top, priority,
+                                     processor_id, owner_process, type_flags);
+        result.IsError()) {
+        return result;
+    }
+
     thread->name = name;
 
     auto& scheduler = kernel.GlobalSchedulerContext();
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index d61659453..6142496b6 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -117,14 +117,14 @@ struct KernelCore::Impl {
     void InitializePhysicalCores() {
         exclusive_monitor =
             Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES);
-        for (s32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
+        for (u32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
             schedulers[i] = std::make_unique<Kernel::KScheduler>(system, i);
             cores.emplace_back(i, system, *schedulers[i], interrupts);
         }
     }
 
     void InitializeSchedulers() {
-        for (s32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
+        for (u32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
             cores[i].Scheduler().Initialize();
         }
     }

From f6b10fad6365be68e9c93b1396249c66910e785f Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Wed, 20 Jan 2021 22:27:38 -0800
Subject: [PATCH 22/34] hle: kernel: k_scheduler: Fix for single core mode.

---
 src/core/hle/kernel/k_scheduler.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index e99122f4c..e8e3b3dc5 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -38,7 +38,8 @@ void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedul
     bool must_context_switch{};
     if (scheduler) {
         current_core = scheduler->core_id;
-        must_context_switch = true;
+        // TODO(bunnei): Should be set to true when we deprecate single core
+        must_context_switch = !kernel.IsPhantomModeForSingleCore();
     }
 
     while (cores_pending_reschedule != 0) {

From 37f74d87417c8cb491fee1681cc05fb7baa5e516 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Thu, 21 Jan 2021 11:26:00 -0800
Subject: [PATCH 23/34] hle: kernel: k_scheduler: Use atomics for
 current_thread, etc.

---
 src/core/hle/kernel/k_scheduler.cpp | 47 +++++++++++++++--------------
 src/core/hle/kernel/k_scheduler.h   |  7 +++--
 2 files changed, 28 insertions(+), 26 deletions(-)

diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index e8e3b3dc5..fbdc061df 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -80,7 +80,7 @@ u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) {
         }
 
         state.highest_priority_thread = highest_thread;
-        state.needs_scheduling = true;
+        state.needs_scheduling.store(true);
         return (1ULL << core_id);
     } else {
         return 0;
@@ -609,7 +609,7 @@ void KScheduler::YieldToAnyThread(KernelCore& kernel) {
 
 KScheduler::KScheduler(Core::System& system, s32 core_id) : system(system), core_id(core_id) {
     switch_fiber = std::make_shared<Common::Fiber>(OnSwitch, this);
-    state.needs_scheduling = true;
+    state.needs_scheduling.store(true);
     state.interrupt_task_thread_runnable = false;
     state.should_count_idle = false;
     state.idle_count = 0;
@@ -620,10 +620,10 @@ KScheduler::KScheduler(Core::System& system, s32 core_id) : system(system), core
 KScheduler::~KScheduler() = default;
 
 KThread* KScheduler::GetCurrentThread() const {
-    if (current_thread) {
-        return current_thread;
+    if (auto result = current_thread.load(); result) {
+        return result;
     }
-    return idle_thread;
+    return idle_thread.get();
 }
 
 u64 KScheduler::GetLastContextSwitchTicks() const {
@@ -638,7 +638,7 @@ void KScheduler::RescheduleCurrentCore() {
         phys_core.ClearInterrupt();
     }
     guard.lock();
-    if (state.needs_scheduling) {
+    if (state.needs_scheduling.load()) {
         Schedule();
     } else {
         guard.unlock();
@@ -695,29 +695,29 @@ void KScheduler::Reload(KThread* thread) {
 
 void KScheduler::SwitchContextStep2() {
     // Load context of new thread
-    Reload(current_thread);
+    Reload(current_thread.load());
 
     RescheduleCurrentCore();
 }
 
 void KScheduler::ScheduleImpl() {
-    KThread* previous_thread = current_thread;
+    KThread* previous_thread = current_thread.load();
     KThread* next_thread = state.highest_priority_thread;
 
     state.needs_scheduling = false;
 
     // 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;
+        next_thread = idle_thread.get();
     }
 
     // If we're not actually switching thread, there's nothing to do.
-    if (next_thread == current_thread) {
+    if (next_thread == current_thread.load()) {
         guard.unlock();
         return;
     }
 
-    current_thread = next_thread;
+    current_thread.store(next_thread);
 
     Process* const previous_process = system.Kernel().CurrentProcess();
 
@@ -749,28 +749,29 @@ void KScheduler::SwitchToCurrent() {
     while (true) {
         {
             std::scoped_lock lock{guard};
-            current_thread = state.highest_priority_thread;
-            state.needs_scheduling = false;
+            current_thread.store(state.highest_priority_thread);
+            state.needs_scheduling.store(false);
         }
         const auto is_switch_pending = [this] {
             std::scoped_lock lock{guard};
-            return state.needs_scheduling.load(std::memory_order_relaxed);
+            return state.needs_scheduling.load();
         };
         do {
-            if (current_thread != nullptr) {
-                current_thread->context_guard.lock();
-                if (current_thread->GetRawState() != ThreadState::Runnable) {
-                    current_thread->context_guard.unlock();
+            auto next_thread = current_thread.load();
+            if (next_thread != nullptr) {
+                next_thread->context_guard.lock();
+                if (next_thread->GetRawState() != ThreadState::Runnable) {
+                    next_thread->context_guard.unlock();
                     break;
                 }
-                if (current_thread->GetActiveCore() != core_id) {
-                    current_thread->context_guard.unlock();
+                if (next_thread->GetActiveCore() != core_id) {
+                    next_thread->context_guard.unlock();
                     break;
                 }
             }
             std::shared_ptr<Common::Fiber>* next_context;
-            if (current_thread != nullptr) {
-                next_context = &current_thread->GetHostContext();
+            if (next_thread != nullptr) {
+                next_context = &next_thread->GetHostContext();
             } else {
                 next_context = &idle_thread->GetHostContext();
             }
@@ -802,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().get();
+    idle_thread = thread_res.Unwrap();
 }
 
 KScopedSchedulerLock::KScopedSchedulerLock(KernelCore& kernel)
diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h
index 2308a55be..e0d052593 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;
+        return GetCurrentThread() == idle_thread.get();
     }
 
     /// Gets the timestamp for the last context switch in ticks.
@@ -174,8 +174,9 @@ private:
     void SwitchToCurrent();
 
     KThread* prev_thread{};
-    KThread* current_thread{};
-    KThread* idle_thread{};
+    std::atomic<KThread*> current_thread{};
+
+    std::shared_ptr<KThread> idle_thread;
 
     std::shared_ptr<Common::Fiber> switch_fiber{};
 

From 6e953f7f0294d945ba9d6f08350d5dccb0d76075 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Thu, 21 Jan 2021 13:00:16 -0800
Subject: [PATCH 24/34] 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 1d54ba5df..08fa65fd5 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<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.
     {
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index fbdc061df..bb5f43b53 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<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)
diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h
index e0d052593..f595b9a5c 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<KThread*> current_thread{};
 
-    std::shared_ptr<KThread> idle_thread;
+    KThread* idle_thread;
 
     std::shared_ptr<Common::Fiber> switch_fiber{};
 
diff --git a/src/core/hle/kernel/k_scheduler_lock.h b/src/core/hle/kernel/k_scheduler_lock.h
index 5d48dcf38..3b38f8f3e 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 62ce2fbd5..f57e98047 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/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) {
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 6142496b6..093886b7c 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::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() {
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index b92c017f6..e7c77727b 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 e76141125..886e6e9d2 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<QtWebBrowser>(*this),         // Web Browser
     });
 
-    system.RegisterHostThread();
-
     const Core::System::ResultStatus result{
         system.Load(*render_window, filename.toStdString(), program_index)};
 

From 091e9e8c4100308c3c8d367f7fd32290cd053f40 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Sun, 24 Jan 2021 22:50:36 -0800
Subject: [PATCH 25/34] common: common_funcs: Log error on R_UNLESS.

---
 src/common/common_funcs.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index 842d62ca7..71d136d4a 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -97,6 +97,9 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
 #define R_UNLESS(expr, res)                                                                        \
     {                                                                                              \
         if (!(expr)) {                                                                             \
+            if (res.IsError()) {                                                                   \
+                LOG_CRITICAL(Kernel, "Failed with error {}", res.raw);                             \
+            }                                                                                      \
             return res;                                                                            \
         }                                                                                          \
     }

From 055194d2ab69ca68687eb2ec49d1f98d78937a2c Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Sun, 24 Jan 2021 22:51:12 -0800
Subject: [PATCH 26/34] core: arm: Remove unnecessary JIT checks.

---
 src/core/arm/dynarmic/arm_dynarmic_32.cpp | 12 ------------
 src/core/arm/dynarmic/arm_dynarmic_64.cpp | 12 ------------
 2 files changed, 24 deletions(-)

diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index 7d7e191ea..6c4c8e9e4 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -251,16 +251,10 @@ void ARM_Dynarmic_32::SetTPIDR_EL0(u64 value) {
 }
 
 void ARM_Dynarmic_32::ChangeProcessorID(std::size_t new_core_id) {
-    if (!jit) {
-        return;
-    }
     jit->ChangeProcessorID(new_core_id);
 }
 
 void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
-    if (!jit) {
-        return;
-    }
     Dynarmic::A32::Context context;
     jit->SaveContext(context);
     ctx.cpu_registers = context.Regs();
@@ -270,9 +264,6 @@ void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
 }
 
 void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) {
-    if (!jit) {
-        return;
-    }
     Dynarmic::A32::Context context;
     context.Regs() = ctx.cpu_registers;
     context.ExtRegs() = ctx.extension_registers;
@@ -282,9 +273,6 @@ void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) {
 }
 
 void ARM_Dynarmic_32::PrepareReschedule() {
-    if (!jit) {
-        return;
-    }
     jit->HaltExecution();
 }
 
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index f755a39cf..4c5ebca22 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -290,16 +290,10 @@ void ARM_Dynarmic_64::SetTPIDR_EL0(u64 value) {
 }
 
 void ARM_Dynarmic_64::ChangeProcessorID(std::size_t new_core_id) {
-    if (!jit) {
-        return;
-    }
     jit->ChangeProcessorID(new_core_id);
 }
 
 void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) {
-    if (!jit) {
-        return;
-    }
     ctx.cpu_registers = jit->GetRegisters();
     ctx.sp = jit->GetSP();
     ctx.pc = jit->GetPC();
@@ -311,9 +305,6 @@ void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) {
 }
 
 void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) {
-    if (!jit) {
-        return;
-    }
     jit->SetRegisters(ctx.cpu_registers);
     jit->SetSP(ctx.sp);
     jit->SetPC(ctx.pc);
@@ -325,9 +316,6 @@ void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) {
 }
 
 void ARM_Dynarmic_64::PrepareReschedule() {
-    if (!jit) {
-        return;
-    }
     jit->HaltExecution();
 }
 

From 6ee8340a6b0fed897b6282690a8e3ceeab76f748 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Sun, 24 Jan 2021 22:53:01 -0800
Subject: [PATCH 27/34] hle: kernel: k_scheduler_lock: Cleanup.

---
 src/core/hle/kernel/k_scheduler_lock.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/core/hle/kernel/k_scheduler_lock.h b/src/core/hle/kernel/k_scheduler_lock.h
index 3b38f8f3e..169455d18 100644
--- a/src/core/hle/kernel/k_scheduler_lock.h
+++ b/src/core/hle/kernel/k_scheduler_lock.h
@@ -23,11 +23,11 @@ public:
     explicit KAbstractSchedulerLock(KernelCore& kernel_) : kernel{kernel_} {}
 
     bool IsLockedByCurrentThread() const {
-        return this->owner_thread == GetCurrentThreadPointer(kernel);
+        return owner_thread == GetCurrentThreadPointer(kernel);
     }
 
     void Lock() {
-        if (this->IsLockedByCurrentThread()) {
+        if (IsLockedByCurrentThread()) {
             // If we already own the lock, we can just increment the count.
             ASSERT(lock_count > 0);
             lock_count++;
@@ -47,7 +47,7 @@ public:
     }
 
     void Unlock() {
-        ASSERT(this->IsLockedByCurrentThread());
+        ASSERT(IsLockedByCurrentThread());
         ASSERT(lock_count > 0);
 
         // Release an instance of the lock.

From ff46ef7ea36632129a2b013ebb62016d6f59f22e Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Sun, 24 Jan 2021 22:53:43 -0800
Subject: [PATCH 28/34] hle: kernel: threading: Fix bug with host thread
 naming.

---
 src/core/hle/kernel/kernel.cpp | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 093886b7c..df309d523 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -211,9 +211,8 @@ struct KernelCore::Impl {
     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,
+                system, ThreadType::Main, fmt::format("DummyThread:{}", GetHostThreadId()), 0,
+                KThread::DefaultThreadPriority, 0, static_cast<u32>(3), 0, nullptr,
                 []([[maybe_unused]] void* arg) { UNREACHABLE(); }, nullptr)
                 .Unwrap();
         return thread.get();

From 3856564727e3efcf85fb0c1e5431cab22d818370 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Sun, 24 Jan 2021 22:54:37 -0800
Subject: [PATCH 29/34] hle: kernel: process: Add state lock.

---
 src/core/hle/kernel/process.cpp |  4 ++--
 src/core/hle/kernel/process.h   |  6 ++++++
 src/core/hle/kernel/svc.cpp     | 11 +++++++----
 3 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 9f4583b49..0edbfc4cc 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -138,7 +138,7 @@ std::shared_ptr<ResourceLimit> Process::GetResourceLimit() const {
 
 void Process::IncrementThreadCount() {
     ASSERT(num_threads >= 0);
-    ++num_created_threads;
+    num_created_threads++;
 
     if (const auto count = ++num_threads; count > peak_num_threads) {
         peak_num_threads = count;
@@ -443,7 +443,7 @@ bool Process::IsSignaled() const {
 Process::Process(Core::System& system)
     : KSynchronizationObject{system.Kernel()},
       page_table{std::make_unique<Memory::PageTable>(system)}, handle_table{system.Kernel()},
-      address_arbiter{system}, condition_var{system}, system{system} {}
+      address_arbiter{system}, condition_var{system}, state_lock{system.Kernel()}, system{system} {}
 
 Process::~Process() = default;
 
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 11d78f3a8..26e647743 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -348,6 +348,10 @@ public:
     void PinCurrentThread();
     void UnpinCurrentThread();
 
+    KLightLock& GetStateLock() {
+        return state_lock;
+    }
+
     ///////////////////////////////////////////////////////////////////////////////////////////////
     // Thread-local storage management
 
@@ -472,6 +476,8 @@ private:
 
     KThread* exception_thread{};
 
+    KLightLock state_lock;
+
     /// System context
     Core::System& system;
 };
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index dbef854f8..7fd514e9d 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1450,11 +1450,14 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
              Svc::ResultInvalidPriority);
     R_UNLESS(process.CheckThreadPriority(priority), Svc::ResultInvalidPriority);
 
-    ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(ResourceType::Threads, 1));
+    ASSERT(process.GetResourceLimit()->Reserve(ResourceType::Threads, 1));
 
-    CASCADE_RESULT(std::shared_ptr<KThread> thread,
-                   KThread::Create(system, ThreadType::User, "", entry_point, priority, arg,
-                                   core_id, stack_bottom, &process));
+    std::shared_ptr<KThread> thread;
+    {
+        KScopedLightLock lk{process.GetStateLock()};
+        CASCADE_RESULT(thread, KThread::Create(system, ThreadType::User, "", entry_point, priority,
+                                               arg, core_id, stack_bottom, &process));
+    }
 
     const auto new_thread_handle = process.GetHandleTable().Create(thread);
     if (new_thread_handle.Failed()) {

From 10738839ad7b9abbcf8ac64c6e58de63a9fbae76 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Sun, 24 Jan 2021 22:55:08 -0800
Subject: [PATCH 30/34] yuzu: debugger: Ignore HLE threads.

---
 src/core/hle/kernel/k_thread.cpp | 15 ++++++++-------
 src/core/hle/kernel/k_thread.h   |  5 +++++
 src/yuzu/debugger/wait_tree.cpp  | 10 ++++++++--
 3 files changed, 21 insertions(+), 9 deletions(-)

diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index f57e98047..45ad589d9 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -101,11 +101,12 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s
         UNREACHABLE_MSG("KThread::Initialize: Unknown ThreadType {}", static_cast<u32>(type));
         break;
     }
+    thread_type_for_debugging = type;
 
     // Set the ideal core ID and affinity mask.
     virtual_ideal_core_id = virt_core;
     physical_ideal_core_id = phys_core;
-    virtual_affinity_mask = (static_cast<u64>(1) << virt_core);
+    virtual_affinity_mask = 1ULL << virt_core;
     physical_affinity_mask.SetAffinity(phys_core, true);
 
     // Set the thread state.
@@ -353,7 +354,7 @@ void KThread::Unpin() {
     // Enable core migration.
     ASSERT(num_core_migration_disables == 1);
     {
-        --num_core_migration_disables;
+        num_core_migration_disables--;
 
         // Restore our original state.
         const KAffinityMask old_mask = physical_affinity_mask;
@@ -494,8 +495,8 @@ ResultCode KThread::SetCoreMask(s32 core_id, u64 v_affinity_mask) {
 
     // Update the pinned waiter list.
     {
-        bool retry_update = false;
-        bool thread_is_pinned = false;
+        bool retry_update{};
+        bool thread_is_pinned{};
         do {
             // Lock the scheduler.
             KScopedSchedulerLock sl{kernel};
@@ -507,7 +508,7 @@ ResultCode KThread::SetCoreMask(s32 core_id, u64 v_affinity_mask) {
             retry_update = false;
 
             // Check if the thread is currently running.
-            bool thread_is_current = false;
+            bool thread_is_current{};
             s32 thread_core;
             for (thread_core = 0; thread_core < static_cast<s32>(Core::Hardware::NUM_CPU_CORES);
                  ++thread_core) {
@@ -683,8 +684,8 @@ ResultCode KThread::SetActivity(Svc::ThreadActivity activity) {
 
     // If the thread is now paused, update the pinned waiter list.
     if (activity == Svc::ThreadActivity::Paused) {
-        bool thread_is_pinned = false;
-        bool thread_is_current;
+        bool thread_is_pinned{};
+        bool thread_is_current{};
         do {
             // Lock the scheduler.
             KScopedSchedulerLock sl{kernel};
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index eeddf5a65..c8ac656a4 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -534,6 +534,10 @@ public:
         return wait_reason_for_debugging;
     }
 
+    [[nodiscard]] ThreadType GetThreadTypeForDebugging() const {
+        return thread_type_for_debugging;
+    }
+
     void SetWaitObjectsForDebugging(const std::span<KSynchronizationObject*>& objects) {
         wait_objects_for_debugging.clear();
         wait_objects_for_debugging.reserve(objects.size());
@@ -721,6 +725,7 @@ private:
     std::vector<KSynchronizationObject*> wait_objects_for_debugging;
     VAddr mutex_wait_address_for_debugging{};
     ThreadWaitReasonForDebugging wait_reason_for_debugging{};
+    ThreadType thread_type_for_debugging{};
     std::string name;
 
 public:
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp
index cbec692f9..0e5156dcc 100644
--- a/src/yuzu/debugger/wait_tree.cpp
+++ b/src/yuzu/debugger/wait_tree.cpp
@@ -93,8 +93,10 @@ std::vector<std::unique_ptr<WaitTreeThread>> WaitTreeItem::MakeThreadItemList()
     std::size_t row = 0;
     auto add_threads = [&](const std::vector<std::shared_ptr<Kernel::KThread>>& threads) {
         for (std::size_t i = 0; i < threads.size(); ++i) {
-            item_list.push_back(std::make_unique<WaitTreeThread>(*threads[i]));
-            item_list.back()->row = row;
+            if (threads[i]->GetThreadTypeForDebugging() == Kernel::ThreadType::User) {
+                item_list.push_back(std::make_unique<WaitTreeThread>(*threads[i]));
+                item_list.back()->row = row;
+            }
             ++row;
         }
     };
@@ -148,6 +150,10 @@ QString WaitTreeCallstack::GetText() const {
 std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() const {
     std::vector<std::unique_ptr<WaitTreeItem>> list;
 
+    if (thread.GetThreadTypeForDebugging() != Kernel::ThreadType::User) {
+        return list;
+    }
+
     if (thread.GetOwnerProcess() == nullptr || !thread.GetOwnerProcess()->Is64BitProcess()) {
         return list;
     }

From e24c6dab93d00676dfb22743534825bb6aa90d7c Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Thu, 28 Jan 2021 21:49:47 -0800
Subject: [PATCH 31/34] hle: kernel: KThread: Release thread resource on thread
 exit.

---
 src/core/hle/kernel/k_thread.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index 45ad589d9..aa100e139 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -247,6 +247,7 @@ void KThread::Finalize() {
     // Decrement the parent process's thread count.
     if (parent != nullptr) {
         parent->DecrementThreadCount();
+        parent->GetResourceLimit()->Release(ResourceType::Threads, 1);
     }
 }
 

From c8fe8247ee8a8e236680f033dac132c76a15a319 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Thu, 28 Jan 2021 21:50:39 -0800
Subject: [PATCH 32/34] arm: dynarmic: Reintroduce JIT checks on
 SaveContext/LoadContext.

---
 src/core/arm/dynarmic/arm_dynarmic_32.cpp | 6 ++++++
 src/core/arm/dynarmic/arm_dynarmic_64.cpp | 6 ++++++
 2 files changed, 12 insertions(+)

diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index 6c4c8e9e4..c650a4dfb 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -255,6 +255,9 @@ void ARM_Dynarmic_32::ChangeProcessorID(std::size_t new_core_id) {
 }
 
 void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
+    if (!jit) {
+        return;
+    }
     Dynarmic::A32::Context context;
     jit->SaveContext(context);
     ctx.cpu_registers = context.Regs();
@@ -264,6 +267,9 @@ void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
 }
 
 void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) {
+    if (!jit) {
+        return;
+    }
     Dynarmic::A32::Context context;
     context.Regs() = ctx.cpu_registers;
     context.ExtRegs() = ctx.extension_registers;
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index 4c5ebca22..ae5566ab8 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -294,6 +294,9 @@ void ARM_Dynarmic_64::ChangeProcessorID(std::size_t new_core_id) {
 }
 
 void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) {
+    if (!jit) {
+        return;
+    }
     ctx.cpu_registers = jit->GetRegisters();
     ctx.sp = jit->GetSP();
     ctx.pc = jit->GetPC();
@@ -305,6 +308,9 @@ void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) {
 }
 
 void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) {
+    if (!jit) {
+        return;
+    }
     jit->SetRegisters(ctx.cpu_registers);
     jit->SetSP(ctx.sp);
     jit->SetPC(ctx.pc);

From 8d1afcb90f59e000467466cd03e42f1488f5e44a Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Thu, 28 Jan 2021 21:51:16 -0800
Subject: [PATCH 33/34] common: common_funcs: Change R_UNLESS to LOG_ERROR.

---
 src/common/common_funcs.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index 71d136d4a..71b64e32a 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -98,7 +98,7 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
     {                                                                                              \
         if (!(expr)) {                                                                             \
             if (res.IsError()) {                                                                   \
-                LOG_CRITICAL(Kernel, "Failed with error {}", res.raw);                             \
+                LOG_ERROR(Kernel, "Failed with result: {}", res.raw);                              \
             }                                                                                      \
             return res;                                                                            \
         }                                                                                          \

From 543e2125541aa3c3399dd471cd170153ce67c369 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Thu, 28 Jan 2021 21:53:21 -0800
Subject: [PATCH 34/34] hle: kernel: KLightLock: Fix several bugs.

---
 src/core/hle/kernel/k_light_lock.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/core/hle/kernel/k_light_lock.cpp b/src/core/hle/kernel/k_light_lock.cpp
index 08fa65fd5..f974022e8 100644
--- a/src/core/hle/kernel/k_light_lock.cpp
+++ b/src/core/hle/kernel/k_light_lock.cpp
@@ -54,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 = reinterpret_cast<KThread*>(_owner & ~1ul);
+        KThread* owner_thread = reinterpret_cast<KThread*>(_owner & ~1ULL);
         cur_thread->SetAddressKey(reinterpret_cast<uintptr_t>(std::addressof(tag)));
         owner_thread->AddWaiter(cur_thread);
 
@@ -67,7 +67,6 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {
 
         if (owner_thread->IsSuspended()) {
             owner_thread->ContinueIfHasKernelWaiters();
-            KScheduler::SetSchedulerUpdateNeeded(kernel);
         }
     }
 
@@ -77,6 +76,7 @@ void KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {
         KThread* owner_thread = cur_thread->GetLockOwner();
         if (owner_thread) {
             owner_thread->RemoveWaiter(cur_thread);
+            KScheduler::SetSchedulerUpdateNeeded(kernel);
         }
     }
 }
@@ -124,7 +124,7 @@ void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) {
 }
 
 bool KLightLock::IsLockedByCurrentThread() const {
-    return (tag | 0x1ul) == (reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel)) | 0x1ul);
+    return (tag | 1ULL) == (reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel)) | 1ULL);
 }
 
 } // namespace Kernel