From 0728dfef84ded5e68bdb3b0781ea00ca7cc85659 Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow <fsahmkow27@gmail.com>
Date: Thu, 13 Feb 2020 22:04:10 -0400
Subject: [PATCH 1/8] Kernel: Make global scheduler depend on KernelCore

---
 src/core/hle/kernel/kernel.cpp    | 14 +++++++++++---
 src/core/hle/kernel/kernel.h      |  7 +++++++
 src/core/hle/kernel/scheduler.cpp |  6 +++---
 src/core/hle/kernel/scheduler.h   |  5 +++--
 4 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 4eb1d87035..d312ae31ee 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -97,8 +97,8 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_
 }
 
 struct KernelCore::Impl {
-    explicit Impl(Core::System& system)
-        : system{system}, global_scheduler{system}, synchronization{system} {}
+    explicit Impl(Core::System& system, KernelCore& kernel)
+        : system{system}, global_scheduler{kernel}, synchronization{system} {}
 
     void Initialize(KernelCore& kernel) {
         Shutdown();
@@ -215,7 +215,7 @@ struct KernelCore::Impl {
     Core::System& system;
 };
 
-KernelCore::KernelCore(Core::System& system) : impl{std::make_unique<Impl>(system)} {}
+KernelCore::KernelCore(Core::System& system) : impl{std::make_unique<Impl>(system, *this)} {}
 KernelCore::~KernelCore() {
     Shutdown();
 }
@@ -265,6 +265,14 @@ const Kernel::GlobalScheduler& KernelCore::GlobalScheduler() const {
     return impl->global_scheduler;
 }
 
+Kernel::Scheduler& KernelCore::Scheduler(std::size_t id) {
+    return impl->cores[id].Scheduler();
+}
+
+const Kernel::Scheduler& KernelCore::Scheduler(std::size_t id) const {
+    return impl->cores[id].Scheduler();
+}
+
 Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) {
     return impl->cores[id];
 }
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 1eede30637..0dfc559e94 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -29,6 +29,7 @@ class HandleTable;
 class PhysicalCore;
 class Process;
 class ResourceLimit;
+class Scheduler;
 class Synchronization;
 class Thread;
 
@@ -87,6 +88,12 @@ public:
     /// Gets the sole instance of the global scheduler
     const Kernel::GlobalScheduler& GlobalScheduler() const;
 
+    /// Gets the sole instance of the Scheduler assoviated with cpu core 'id'
+    Kernel::Scheduler& Scheduler(std::size_t id);
+
+    /// Gets the sole instance of the Scheduler assoviated with cpu core 'id'
+    const Kernel::Scheduler& Scheduler(std::size_t id) const;
+
     /// Gets the an instance of the respective physical CPU core.
     Kernel::PhysicalCore& PhysicalCore(std::size_t id);
 
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index 86f1421bfd..118c1aa950 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -21,7 +21,7 @@
 
 namespace Kernel {
 
-GlobalScheduler::GlobalScheduler(Core::System& system) : system{system} {}
+GlobalScheduler::GlobalScheduler(KernelCore& kernel) : kernel{kernel} {}
 
 GlobalScheduler::~GlobalScheduler() = default;
 
@@ -35,7 +35,7 @@ void GlobalScheduler::RemoveThread(std::shared_ptr<Thread> thread) {
 }
 
 void GlobalScheduler::UnloadThread(std::size_t core) {
-    Scheduler& sched = system.Scheduler(core);
+    Scheduler& sched = kernel.Scheduler(core);
     sched.UnloadThread();
 }
 
@@ -50,7 +50,7 @@ void GlobalScheduler::SelectThread(std::size_t core) {
         sched.is_context_switch_pending = sched.selected_thread != sched.current_thread;
         std::atomic_thread_fence(std::memory_order_seq_cst);
     };
-    Scheduler& sched = system.Scheduler(core);
+    Scheduler& sched = kernel.Scheduler(core);
     Thread* current_thread = nullptr;
     // Step 1: Get top thread in schedule queue.
     current_thread = scheduled_queue[core].empty() ? nullptr : scheduled_queue[core].front();
diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h
index 96db049cbf..283236d4c5 100644
--- a/src/core/hle/kernel/scheduler.h
+++ b/src/core/hle/kernel/scheduler.h
@@ -20,11 +20,12 @@ class System;
 
 namespace Kernel {
 
+class KernelCore;
 class Process;
 
 class GlobalScheduler final {
 public:
-    explicit GlobalScheduler(Core::System& system);
+    explicit GlobalScheduler(KernelCore& kernel);
     ~GlobalScheduler();
 
     /// Adds a new thread to the scheduler
@@ -160,7 +161,7 @@ private:
 
     /// Lists all thread ids that aren't deleted/etc.
     std::vector<std::shared_ptr<Thread>> thread_list;
-    Core::System& system;
+    KernelCore& kernel;
 };
 
 class Scheduler final {

From 179bafa7cb1efae5405d38ea9b98dc6b3e1ec756 Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow <fsahmkow27@gmail.com>
Date: Fri, 14 Feb 2020 09:30:53 -0400
Subject: [PATCH 2/8] Kernel: Rename ThreadCallbackHandleTable and Setup Thread
 Ids on Kernel.

---
 src/core/hardware_properties.h |  2 +
 src/core/hle/kernel/kernel.cpp | 88 +++++++++++++++++++++++++++++-----
 src/core/hle/kernel/kernel.h   | 23 +++++++--
 src/core/hle/kernel/thread.cpp | 12 ++---
 src/core/hle/kernel/thread.h   |  6 ++-
 5 files changed, 107 insertions(+), 24 deletions(-)

diff --git a/src/core/hardware_properties.h b/src/core/hardware_properties.h
index 213461b6a0..b04e046ed3 100644
--- a/src/core/hardware_properties.h
+++ b/src/core/hardware_properties.h
@@ -20,6 +20,8 @@ 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;
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index d312ae31ee..b3a5d75052 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -6,6 +6,8 @@
 #include <functional>
 #include <memory>
 #include <mutex>
+#include <thread>
+#include <unordered_map>
 #include <utility>
 
 #include "common/assert.h"
@@ -44,7 +46,7 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_
     std::lock_guard lock{HLE::g_hle_lock};
 
     std::shared_ptr<Thread> thread =
-        system.Kernel().RetrieveThreadFromWakeupCallbackHandleTable(proper_handle);
+        system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle);
     if (thread == nullptr) {
         LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle);
         return;
@@ -120,7 +122,7 @@ struct KernelCore::Impl {
 
         system_resource_limit = nullptr;
 
-        thread_wakeup_callback_handle_table.Clear();
+        global_handle_table.Clear();
         thread_wakeup_event_type = nullptr;
         preemption_event = nullptr;
 
@@ -138,8 +140,8 @@ struct KernelCore::Impl {
 
     void InitializePhysicalCores() {
         exclusive_monitor =
-            Core::MakeExclusiveMonitor(system.Memory(), global_scheduler.CpuCoresCount());
-        for (std::size_t i = 0; i < global_scheduler.CpuCoresCount(); i++) {
+            Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES);
+        for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
             cores.emplace_back(system, i, *exclusive_monitor);
         }
     }
@@ -184,6 +186,48 @@ struct KernelCore::Impl {
         system.Memory().SetCurrentPageTable(*process);
     }
 
+    void RegisterCoreThread(std::size_t core_id) {
+        const std::thread::id this_id = std::this_thread::get_id();
+        const auto it = host_thread_ids.find(this_id);
+        ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
+        ASSERT(it == host_thread_ids.end());
+        ASSERT(!registered_core_threads[core_id]);
+        host_thread_ids[this_id] = static_cast<u32>(core_id);
+        registered_core_threads.set(core_id);
+    }
+
+    void RegisterHostThread() {
+        const std::thread::id this_id = std::this_thread::get_id();
+        const auto it = host_thread_ids.find(this_id);
+        ASSERT(it == host_thread_ids.end());
+        host_thread_ids[this_id] = registered_thread_ids++;
+    }
+
+    u32 GetCurrentHostThreadId() const {
+        const std::thread::id this_id = std::this_thread::get_id();
+        const auto it = host_thread_ids.find(this_id);
+        if (it == host_thread_ids.end()) {
+            return Core::INVALID_HOST_THREAD_ID;
+        }
+        return it->second;
+    }
+
+    Core::EmuThreadHandle GetCurrentEmuThreadId() const {
+        Core::EmuThreadHandle result = Core::EmuThreadHandle::InvalidHandle();
+        result.host_handle = GetCurrentHostThreadId();
+        if (result.host_handle >= Core::Hardware::NUM_CPU_CORES) {
+            return result;
+        }
+        const Kernel::Scheduler& sched = cores[result.host_handle].Scheduler();
+        const Kernel::Thread* current = sched.GetCurrentThread();
+        if (current != nullptr) {
+            result.guest_handle = current->GetGlobalHandle();
+        } else {
+            result.guest_handle = InvalidHandle;
+        }
+        return result;
+    }
+
     std::atomic<u32> next_object_id{0};
     std::atomic<u64> next_kernel_process_id{Process::InitialKIPIDMin};
     std::atomic<u64> next_user_process_id{Process::ProcessIDMin};
@@ -202,7 +246,7 @@ struct KernelCore::Impl {
 
     // TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future,
     // allowing us to simply use a pool index or similar.
-    Kernel::HandleTable thread_wakeup_callback_handle_table;
+    Kernel::HandleTable global_handle_table;
 
     /// Map of named ports managed by the kernel, which can be retrieved using
     /// the ConnectToPort SVC.
@@ -211,6 +255,11 @@ struct KernelCore::Impl {
     std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
     std::vector<Kernel::PhysicalCore> cores;
 
+    // 0-3 Ids represent core threads, >3 represent others
+    std::unordered_map<std::thread::id, u32> host_thread_ids;
+    u32 registered_thread_ids{Core::Hardware::NUM_CPU_CORES};
+    std::bitset<Core::Hardware::NUM_CPU_CORES> registered_core_threads{};
+
     // System context
     Core::System& system;
 };
@@ -232,9 +281,8 @@ std::shared_ptr<ResourceLimit> KernelCore::GetSystemResourceLimit() const {
     return impl->system_resource_limit;
 }
 
-std::shared_ptr<Thread> KernelCore::RetrieveThreadFromWakeupCallbackHandleTable(
-    Handle handle) const {
-    return impl->thread_wakeup_callback_handle_table.Get<Thread>(handle);
+std::shared_ptr<Thread> KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const {
+    return impl->global_handle_table.Get<Thread>(handle);
 }
 
 void KernelCore::AppendNewProcess(std::shared_ptr<Process> process) {
@@ -346,12 +394,28 @@ const std::shared_ptr<Core::Timing::EventType>& KernelCore::ThreadWakeupCallback
     return impl->thread_wakeup_event_type;
 }
 
-Kernel::HandleTable& KernelCore::ThreadWakeupCallbackHandleTable() {
-    return impl->thread_wakeup_callback_handle_table;
+Kernel::HandleTable& KernelCore::GlobalHandleTable() {
+    return impl->global_handle_table;
 }
 
-const Kernel::HandleTable& KernelCore::ThreadWakeupCallbackHandleTable() const {
-    return impl->thread_wakeup_callback_handle_table;
+const Kernel::HandleTable& KernelCore::GlobalHandleTable() const {
+    return impl->global_handle_table;
+}
+
+void KernelCore::RegisterCoreThread(std::size_t core_id) {
+    impl->RegisterCoreThread(core_id);
+}
+
+void KernelCore::RegisterHostThread() {
+    impl->RegisterHostThread();
+}
+
+u32 KernelCore::GetCurrentHostThreadId() const {
+    return impl->GetCurrentHostThreadId();
+}
+
+Core::EmuThreadHandle KernelCore::GetCurrentEmuThreadId() const {
+    return impl->GetCurrentEmuThreadId();
 }
 
 } // namespace Kernel
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 0dfc559e94..c5e05f7b6a 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -8,6 +8,7 @@
 #include <string>
 #include <unordered_map>
 #include <vector>
+#include "core/hardware_properties.h"
 #include "core/hle/kernel/object.h"
 
 namespace Core {
@@ -65,7 +66,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> RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const;
+    std::shared_ptr<Thread> RetrieveThreadFromGlobalHandleTable(Handle handle) const;
 
     /// Adds the given shared pointer to an internal list of active processes.
     void AppendNewProcess(std::shared_ptr<Process> process);
@@ -127,6 +128,18 @@ 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.
+    Core::EmuThreadHandle GetCurrentEmuThreadId() const;
+
+    /// Gets the current host_thread handle.
+    u32 GetCurrentHostThreadId() const;
+
+    /// Register the current thread as a CPU Core Thread.
+    void RegisterCoreThread(std::size_t core_id);
+
+    /// Register the current thread as a non CPU core thread.
+    void RegisterHostThread();
+
 private:
     friend class Object;
     friend class Process;
@@ -147,11 +160,11 @@ private:
     /// Retrieves the event type used for thread wakeup callbacks.
     const std::shared_ptr<Core::Timing::EventType>& ThreadWakeupCallbackEventType() const;
 
-    /// Provides a reference to the thread wakeup callback handle table.
-    Kernel::HandleTable& ThreadWakeupCallbackHandleTable();
+    /// Provides a reference to the global handle table.
+    Kernel::HandleTable& GlobalHandleTable();
 
-    /// Provides a const reference to the thread wakeup callback handle table.
-    const Kernel::HandleTable& ThreadWakeupCallbackHandleTable() const;
+    /// Provides a const reference to the global handle table.
+    const Kernel::HandleTable& GlobalHandleTable() const;
 
     struct Impl;
     std::unique_ptr<Impl> impl;
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index ae5f2c8bd8..bf850e0b23 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -46,9 +46,9 @@ Thread::~Thread() = default;
 void Thread::Stop() {
     // Cancel any outstanding wakeup events for this thread
     Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(),
-                                                             callback_handle);
-    kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle);
-    callback_handle = 0;
+                                                             global_handle);
+    kernel.GlobalHandleTable().Close(global_handle);
+    global_handle = 0;
     SetStatus(ThreadStatus::Dead);
     Signal();
 
@@ -73,12 +73,12 @@ void Thread::WakeAfterDelay(s64 nanoseconds) {
     // thread-safe version of ScheduleEvent.
     const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds});
     Core::System::GetInstance().CoreTiming().ScheduleEvent(
-        cycles, kernel.ThreadWakeupCallbackEventType(), callback_handle);
+        cycles, kernel.ThreadWakeupCallbackEventType(), global_handle);
 }
 
 void Thread::CancelWakeupTimer() {
     Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(),
-                                                             callback_handle);
+                                                             global_handle);
 }
 
 void Thread::ResumeFromWait() {
@@ -190,7 +190,7 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(KernelCore& kernel, std::strin
     thread->condvar_wait_address = 0;
     thread->wait_handle = 0;
     thread->name = std::move(name);
-    thread->callback_handle = kernel.ThreadWakeupCallbackHandleTable().Create(thread).Unwrap();
+    thread->global_handle = kernel.GlobalHandleTable().Create(thread).Unwrap();
     thread->owner_process = &owner_process;
     auto& scheduler = kernel.GlobalScheduler();
     scheduler.AddThread(thread);
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 7a49163187..129e7858af 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -453,6 +453,10 @@ public:
         is_sync_cancelled = value;
     }
 
+    Handle GetGlobalHandle() const {
+        return global_handle;
+    }
+
 private:
     void SetSchedulingStatus(ThreadSchedStatus new_status);
     void SetCurrentPriority(u32 new_priority);
@@ -514,7 +518,7 @@ private:
     VAddr arb_wait_address{0};
 
     /// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
-    Handle callback_handle = 0;
+    Handle global_handle = 0;
 
     /// Callback that will be invoked when the thread is resumed from a waiting state. If the thread
     /// was waiting via WaitSynchronization then the object will be the last object that became

From 5c90d22f3d92b9be818b19e03dd57eb217eb6567 Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow <fsahmkow27@gmail.com>
Date: Fri, 14 Feb 2020 10:56:27 -0400
Subject: [PATCH 3/8] Kernel: Implement Time Manager.

---
 src/core/CMakeLists.txt              |  2 ++
 src/core/hle/kernel/kernel.cpp       | 12 +++++++-
 src/core/hle/kernel/kernel.h         |  7 +++++
 src/core/hle/kernel/time_manager.cpp | 42 ++++++++++++++++++++++++++++
 src/core/hle/kernel/time_manager.h   | 36 ++++++++++++++++++++++++
 5 files changed, 98 insertions(+), 1 deletion(-)
 create mode 100644 src/core/hle/kernel/time_manager.cpp
 create mode 100644 src/core/hle/kernel/time_manager.h

diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 26612e692d..88c06b2ceb 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -187,6 +187,8 @@ add_library(core STATIC
     hle/kernel/synchronization.h
     hle/kernel/thread.cpp
     hle/kernel/thread.h
+    hle/kernel/time_manager.cpp
+    hle/kernel/time_manager.h
     hle/kernel/transfer_memory.cpp
     hle/kernel/transfer_memory.h
     hle/kernel/vm_manager.cpp
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index b3a5d75052..de14e19360 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -27,6 +27,7 @@
 #include "core/hle/kernel/scheduler.h"
 #include "core/hle/kernel/synchronization.h"
 #include "core/hle/kernel/thread.h"
+#include "core/hle/kernel/time_manager.h"
 #include "core/hle/lock.h"
 #include "core/hle/result.h"
 #include "core/memory.h"
@@ -100,7 +101,7 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_
 
 struct KernelCore::Impl {
     explicit Impl(Core::System& system, KernelCore& kernel)
-        : system{system}, global_scheduler{kernel}, synchronization{system} {}
+        : system{system}, global_scheduler{kernel}, synchronization{system}, time_manager{system} {}
 
     void Initialize(KernelCore& kernel) {
         Shutdown();
@@ -238,6 +239,7 @@ struct KernelCore::Impl {
     Process* current_process = nullptr;
     Kernel::GlobalScheduler global_scheduler;
     Kernel::Synchronization synchronization;
+    Kernel::TimeManager time_manager;
 
     std::shared_ptr<ResourceLimit> system_resource_limit;
 
@@ -337,6 +339,14 @@ const Kernel::Synchronization& KernelCore::Synchronization() const {
     return impl->synchronization;
 }
 
+Kernel::TimeManager& KernelCore::TimeManager() {
+    return impl->time_manager;
+}
+
+const Kernel::TimeManager& KernelCore::TimeManager() const {
+    return impl->time_manager;
+}
+
 Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() {
     return *impl->exclusive_monitor;
 }
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index c5e05f7b6a..76fd12ace2 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -33,6 +33,7 @@ class ResourceLimit;
 class Scheduler;
 class Synchronization;
 class Thread;
+class TimeManager;
 
 /// Represents a single instance of the kernel.
 class KernelCore {
@@ -107,6 +108,12 @@ public:
     /// Gets the an instance of the Synchronization Interface.
     const Kernel::Synchronization& Synchronization() const;
 
+    /// Gets the an instance of the TimeManager Interface.
+    Kernel::TimeManager& TimeManager();
+
+    /// Gets the an instance of the TimeManager Interface.
+    const Kernel::TimeManager& TimeManager() const;
+
     /// Stops execution of 'id' core, in order to reschedule a new thread.
     void PrepareReschedule(std::size_t id);
 
diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp
new file mode 100644
index 0000000000..0b3e464d0e
--- /dev/null
+++ b/src/core/hle/kernel/time_manager.cpp
@@ -0,0 +1,42 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/core.h"
+#include "core/core_timing.h"
+#include "core/core_timing_util.h"
+#include "core/hle/kernel/handle_table.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/thread.h"
+#include "core/hle/kernel/time_manager.h"
+
+namespace Kernel {
+
+TimeManager::TimeManager(Core::System& system) : system{system} {
+    time_manager_event_type = Core::Timing::CreateEvent(
+        "Kernel::TimeManagerCallback", [this](u64 thread_handle, [[maybe_unused]] s64 cycles_late) {
+            Handle proper_handle = static_cast<Handle>(thread_handle);
+            std::shared_ptr<Thread> thread =
+                this->system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle);
+            thread->ResumeFromWait();
+        });
+}
+
+void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds) {
+    if (nanoseconds > 0) {
+        ASSERT(timetask);
+        event_handle = timetask->GetGlobalHandle();
+        const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds});
+        system.CoreTiming().ScheduleEvent(cycles, time_manager_event_type, event_handle);
+    } else {
+        event_handle = InvalidHandle;
+    }
+}
+
+void TimeManager::UnscheduleTimeEvent(Handle event_handle) {
+    if (event_handle != InvalidHandle) {
+        system.CoreTiming().UnscheduleEvent(time_manager_event_type, event_handle);
+    }
+}
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/time_manager.h b/src/core/hle/kernel/time_manager.h
new file mode 100644
index 0000000000..b760311f1f
--- /dev/null
+++ b/src/core/hle/kernel/time_manager.h
@@ -0,0 +1,36 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+
+#include "core/hle/kernel/object.h"
+
+namespace Core {
+class System;
+} // namespace Core
+
+namespace Core::Timing {
+struct EventType;
+} // namespace Core::Timing
+
+namespace Kernel {
+
+class Thread;
+
+class TimeManager {
+public:
+    TimeManager(Core::System& system);
+
+    void ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds);
+
+    void UnscheduleTimeEvent(Handle event_handle);
+
+private:
+    Core::System& system;
+    std::shared_ptr<Core::Timing::EventType> time_manager_event_type;
+};
+
+} // namespace Kernel

From ea956c823e5e6b7f6fd16780b613263d6fadd5da Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow <fsahmkow27@gmail.com>
Date: Fri, 14 Feb 2020 11:44:31 -0400
Subject: [PATCH 4/8] Kernel: Implement Scheduler locks

---
 src/core/hle/kernel/scheduler.cpp | 48 +++++++++++++++++++++++++++++++
 src/core/hle/kernel/scheduler.h   | 41 ++++++++++++++++++++++++++
 2 files changed, 89 insertions(+)

diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index 118c1aa950..9556df9513 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -18,6 +18,7 @@
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/scheduler.h"
+#include "core/hle/kernel/time_manager.h"
 
 namespace Kernel {
 
@@ -356,6 +357,29 @@ void GlobalScheduler::Shutdown() {
     thread_list.clear();
 }
 
+void GlobalScheduler::Lock() {
+    Core::EmuThreadHandle current_thread = kernel.GetCurrentEmuThreadId();
+    if (current_thread == current_owner) {
+        ++scope_lock;
+    } else {
+        inner_lock.lock();
+        current_owner = current_thread;
+        scope_lock = 1;
+    }
+}
+
+void GlobalScheduler::Unlock() {
+    if (--scope_lock == 0) {
+        for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
+            SelectThread(i);
+        }
+        current_owner = Core::EmuThreadHandle::InvalidHandle();
+        scope_lock = 1;
+        inner_lock.unlock();
+        // TODO(Blinkhawk): Setup the interrupts and change context on current core.
+    }
+}
+
 Scheduler::Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, std::size_t core_id)
     : system(system), cpu_core(cpu_core), core_id(core_id) {}
 
@@ -485,4 +509,28 @@ void Scheduler::Shutdown() {
     selected_thread = nullptr;
 }
 
+SchedulerLock::SchedulerLock(KernelCore& kernel) : kernel{kernel} {
+    auto& global_scheduler = kernel.GlobalScheduler();
+    global_scheduler.Lock();
+}
+
+SchedulerLock::~SchedulerLock() {
+    auto& global_scheduler = kernel.GlobalScheduler();
+    global_scheduler.Unlock();
+}
+
+SchedulerLockAndSleep::SchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle,
+                                             Thread* time_task, s64 nanoseconds)
+    : SchedulerLock{kernel}, event_handle{event_handle}, time_task{time_task}, nanoseconds{
+                                                                                   nanoseconds} {
+    event_handle = InvalidHandle;
+}
+
+SchedulerLockAndSleep::~SchedulerLockAndSleep() {
+    if (!sleep_cancelled) {
+        auto& time_manager = kernel.TimeManager();
+        time_manager.ScheduleTimeEvent(event_handle, time_task, nanoseconds);
+    }
+}
+
 } // namespace Kernel
diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h
index 283236d4c5..a779bb70fa 100644
--- a/src/core/hle/kernel/scheduler.h
+++ b/src/core/hle/kernel/scheduler.h
@@ -6,6 +6,7 @@
 
 #include <atomic>
 #include <memory>
+#include <mutex>
 #include <vector>
 
 #include "common/common_types.h"
@@ -22,6 +23,7 @@ namespace Kernel {
 
 class KernelCore;
 class Process;
+class SchedulerLock;
 
 class GlobalScheduler final {
 public:
@@ -139,6 +141,14 @@ public:
     void Shutdown();
 
 private:
+    friend class SchedulerLock;
+
+    /// Lock the scheduler to the current thread.
+    void Lock();
+
+    /// Unlocks the scheduler, reselects threads, interrupts cores for rescheduling
+    /// and reschedules current core if needed.
+    void Unlock();
     /**
      * Transfers a thread into an specific core. If the destination_core is -1
      * it will be unscheduled from its source code and added into its suggested
@@ -159,6 +169,11 @@ private:
     // ordered from Core 0 to Core 3.
     std::array<u32, Core::Hardware::NUM_CPU_CORES> preemption_priorities = {59, 59, 59, 62};
 
+    /// Scheduler lock mechanisms.
+    std::mutex inner_lock{}; // TODO(Blinkhawk): Replace for a SpinLock
+    std::atomic<std::size_t> scope_lock{};
+    Core::EmuThreadHandle current_owner{Core::EmuThreadHandle::InvalidHandle()};
+
     /// Lists all thread ids that aren't deleted/etc.
     std::vector<std::shared_ptr<Thread>> thread_list;
     KernelCore& kernel;
@@ -228,4 +243,30 @@ private:
     bool is_context_switch_pending = false;
 };
 
+class SchedulerLock {
+public:
+    SchedulerLock(KernelCore& kernel);
+    ~SchedulerLock();
+
+protected:
+    KernelCore& kernel;
+};
+
+class SchedulerLockAndSleep : public SchedulerLock {
+public:
+    SchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, Thread* time_task,
+                          s64 nanoseconds);
+    ~SchedulerLockAndSleep();
+
+    void CancelSleep() {
+        sleep_cancelled = true;
+    }
+
+private:
+    Handle& event_handle;
+    Thread* time_task;
+    s64 nanoseconds;
+    bool sleep_cancelled{};
+};
+
 } // namespace Kernel

From d219a96cc828d17932beebead209ba696b92a911 Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow <fsahmkow27@gmail.com>
Date: Sat, 22 Feb 2020 10:27:40 -0400
Subject: [PATCH 5/8] Kernel: Address Feedback.

---
 src/core/hle/kernel/kernel.cpp       | 27 ++++++++++++++++-----------
 src/core/hle/kernel/kernel.h         |  6 +++---
 src/core/hle/kernel/scheduler.cpp    | 21 ++++++++++++---------
 src/core/hle/kernel/scheduler.h      |  8 ++++----
 src/core/hle/kernel/time_manager.cpp |  6 ++++--
 src/core/hle/kernel/time_manager.h   |  9 ++++++++-
 6 files changed, 47 insertions(+), 30 deletions(-)

diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index de14e19360..9232f4d7e3 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <atomic>
+#include <bitset>
 #include <functional>
 #include <memory>
 #include <mutex>
@@ -17,6 +18,7 @@
 #include "core/core.h"
 #include "core/core_timing.h"
 #include "core/core_timing_util.h"
+#include "core/hardware_properties.h"
 #include "core/hle/kernel/client_port.h"
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/handle_table.h"
@@ -188,6 +190,7 @@ struct KernelCore::Impl {
     }
 
     void RegisterCoreThread(std::size_t core_id) {
+        std::unique_lock lock{register_thread_mutex};
         const std::thread::id this_id = std::this_thread::get_id();
         const auto it = host_thread_ids.find(this_id);
         ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
@@ -198,13 +201,14 @@ struct KernelCore::Impl {
     }
 
     void RegisterHostThread() {
+        std::unique_lock lock{register_thread_mutex};
         const std::thread::id this_id = std::this_thread::get_id();
         const auto it = host_thread_ids.find(this_id);
         ASSERT(it == host_thread_ids.end());
         host_thread_ids[this_id] = registered_thread_ids++;
     }
 
-    u32 GetCurrentHostThreadId() const {
+    u32 GetCurrentHostThreadID() const {
         const std::thread::id this_id = std::this_thread::get_id();
         const auto it = host_thread_ids.find(this_id);
         if (it == host_thread_ids.end()) {
@@ -213,9 +217,9 @@ struct KernelCore::Impl {
         return it->second;
     }
 
-    Core::EmuThreadHandle GetCurrentEmuThreadId() const {
+    Core::EmuThreadHandle GetCurrentEmuThreadID() const {
         Core::EmuThreadHandle result = Core::EmuThreadHandle::InvalidHandle();
-        result.host_handle = GetCurrentHostThreadId();
+        result.host_handle = GetCurrentHostThreadID();
         if (result.host_handle >= Core::Hardware::NUM_CPU_CORES) {
             return result;
         }
@@ -246,8 +250,8 @@ struct KernelCore::Impl {
     std::shared_ptr<Core::Timing::EventType> thread_wakeup_event_type;
     std::shared_ptr<Core::Timing::EventType> preemption_event;
 
-    // TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future,
-    // allowing us to simply use a pool index or similar.
+    // This is the kernel's handle table or supervisor handle table which
+    // stores all the objects in place.
     Kernel::HandleTable global_handle_table;
 
     /// Map of named ports managed by the kernel, which can be retrieved using
@@ -257,10 +261,11 @@ struct KernelCore::Impl {
     std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
     std::vector<Kernel::PhysicalCore> cores;
 
-    // 0-3 Ids represent core threads, >3 represent others
+    // 0-3 IDs represent core threads, >3 represent others
     std::unordered_map<std::thread::id, u32> host_thread_ids;
     u32 registered_thread_ids{Core::Hardware::NUM_CPU_CORES};
-    std::bitset<Core::Hardware::NUM_CPU_CORES> registered_core_threads{};
+    std::bitset<Core::Hardware::NUM_CPU_CORES> registered_core_threads;
+    std::mutex register_thread_mutex;
 
     // System context
     Core::System& system;
@@ -420,12 +425,12 @@ void KernelCore::RegisterHostThread() {
     impl->RegisterHostThread();
 }
 
-u32 KernelCore::GetCurrentHostThreadId() const {
-    return impl->GetCurrentHostThreadId();
+u32 KernelCore::GetCurrentHostThreadID() const {
+    return impl->GetCurrentHostThreadID();
 }
 
-Core::EmuThreadHandle KernelCore::GetCurrentEmuThreadId() const {
-    return impl->GetCurrentEmuThreadId();
+Core::EmuThreadHandle KernelCore::GetCurrentEmuThreadID() const {
+    return impl->GetCurrentEmuThreadID();
 }
 
 } // namespace Kernel
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 76fd12ace2..c4f78ab71e 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -8,10 +8,10 @@
 #include <string>
 #include <unordered_map>
 #include <vector>
-#include "core/hardware_properties.h"
 #include "core/hle/kernel/object.h"
 
 namespace Core {
+struct EmuThreadHandle;
 class ExclusiveMonitor;
 class System;
 } // namespace Core
@@ -136,10 +136,10 @@ public:
     bool IsValidNamedPort(NamedPortTable::const_iterator port) const;
 
     /// Gets the current host_thread/guest_thread handle.
-    Core::EmuThreadHandle GetCurrentEmuThreadId() const;
+    Core::EmuThreadHandle GetCurrentEmuThreadID() const;
 
     /// Gets the current host_thread handle.
-    u32 GetCurrentHostThreadId() const;
+    u32 GetCurrentHostThreadID() const;
 
     /// Register the current thread as a CPU Core Thread.
     void RegisterCoreThread(std::size_t core_id);
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index 9556df9513..e5892727e9 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -358,26 +358,29 @@ void GlobalScheduler::Shutdown() {
 }
 
 void GlobalScheduler::Lock() {
-    Core::EmuThreadHandle current_thread = kernel.GetCurrentEmuThreadId();
+    Core::EmuThreadHandle current_thread = kernel.GetCurrentEmuThreadID();
     if (current_thread == current_owner) {
         ++scope_lock;
     } else {
         inner_lock.lock();
         current_owner = current_thread;
+        ASSERT(current_owner != Core::EmuThreadHandle::InvalidHandle());
         scope_lock = 1;
     }
 }
 
 void GlobalScheduler::Unlock() {
-    if (--scope_lock == 0) {
-        for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
-            SelectThread(i);
-        }
-        current_owner = Core::EmuThreadHandle::InvalidHandle();
-        scope_lock = 1;
-        inner_lock.unlock();
-        // TODO(Blinkhawk): Setup the interrupts and change context on current core.
+    if (--scope_lock != 0) {
+        ASSERT(scope_lock > 0);
+        return;
     }
+    for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
+        SelectThread(i);
+    }
+    current_owner = Core::EmuThreadHandle::InvalidHandle();
+    scope_lock = 1;
+    inner_lock.unlock();
+    // TODO(Blinkhawk): Setup the interrupts and change context on current core.
 }
 
 Scheduler::Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, std::size_t core_id)
diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h
index a779bb70fa..1c93a838c5 100644
--- a/src/core/hle/kernel/scheduler.h
+++ b/src/core/hle/kernel/scheduler.h
@@ -171,7 +171,7 @@ private:
 
     /// Scheduler lock mechanisms.
     std::mutex inner_lock{}; // TODO(Blinkhawk): Replace for a SpinLock
-    std::atomic<std::size_t> scope_lock{};
+    std::atomic<s64> scope_lock{};
     Core::EmuThreadHandle current_owner{Core::EmuThreadHandle::InvalidHandle()};
 
     /// Lists all thread ids that aren't deleted/etc.
@@ -245,7 +245,7 @@ private:
 
 class SchedulerLock {
 public:
-    SchedulerLock(KernelCore& kernel);
+    explicit SchedulerLock(KernelCore& kernel);
     ~SchedulerLock();
 
 protected:
@@ -254,8 +254,8 @@ protected:
 
 class SchedulerLockAndSleep : public SchedulerLock {
 public:
-    SchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, Thread* time_task,
-                          s64 nanoseconds);
+    explicit SchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, Thread* time_task,
+                                   s64 nanoseconds);
     ~SchedulerLockAndSleep();
 
     void CancelSleep() {
diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp
index 0b3e464d0e..21b2904689 100644
--- a/src/core/hle/kernel/time_manager.cpp
+++ b/src/core/hle/kernel/time_manager.cpp
@@ -2,6 +2,7 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/assert.h"
 #include "core/core.h"
 #include "core/core_timing.h"
 #include "core/core_timing_util.h"
@@ -34,9 +35,10 @@ void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64
 }
 
 void TimeManager::UnscheduleTimeEvent(Handle event_handle) {
-    if (event_handle != InvalidHandle) {
-        system.CoreTiming().UnscheduleEvent(time_manager_event_type, event_handle);
+    if (event_handle == InvalidHandle) {
+        return;
     }
+    system.CoreTiming().UnscheduleEvent(time_manager_event_type, event_handle);
 }
 
 } // namespace Kernel
diff --git a/src/core/hle/kernel/time_manager.h b/src/core/hle/kernel/time_manager.h
index b760311f1f..eaec486d1a 100644
--- a/src/core/hle/kernel/time_manager.h
+++ b/src/core/hle/kernel/time_manager.h
@@ -20,12 +20,19 @@ namespace Kernel {
 
 class Thread;
 
+/**
+ * The `TimeManager` takes care of scheduling time events on threads and executes their TimeUp
+ * method when the event is triggered.
+ */
 class TimeManager {
 public:
-    TimeManager(Core::System& system);
+    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, Thread* timetask, s64 nanoseconds);
 
+    /// Unschedule an existing time event
     void UnscheduleTimeEvent(Handle event_handle);
 
 private:

From b9472eae440145042e504352472ba3a781b52f01 Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow <fsahmkow27@gmail.com>
Date: Sat, 22 Feb 2020 11:13:07 -0400
Subject: [PATCH 6/8] System: Expose Host thread registering routines from
 kernel.

---
 src/core/core.cpp | 8 ++++++++
 src/core/core.h   | 6 ++++++
 2 files changed, 14 insertions(+)

diff --git a/src/core/core.cpp b/src/core/core.cpp
index 0eb0c0dca1..86e314c946 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -707,4 +707,12 @@ const Service::SM::ServiceManager& System::ServiceManager() const {
     return *impl->service_manager;
 }
 
+void System::RegisterCoreThread(std::size_t id) {
+    impl->kernel.RegisterCoreThread(id);
+}
+
+void System::RegisterHostThread() {
+    impl->kernel.RegisterHostThread();
+}
+
 } // namespace Core
diff --git a/src/core/core.h b/src/core/core.h
index e69d68fcf9..8d862a8e64 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -360,6 +360,12 @@ public:
 
     const CurrentBuildProcessID& GetCurrentProcessBuildID() const;
 
+    /// Register a host thread as an emulated CPU Core.
+    void RegisterCoreThread(std::size_t id);
+
+    /// Register a host thread as an auxiliary thread.
+    void RegisterHostThread();
+
 private:
     System();
 

From a1bf353780254b8cb03ea0f820917d104ce9ca66 Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow <fsahmkow27@gmail.com>
Date: Sat, 22 Feb 2020 11:51:03 -0400
Subject: [PATCH 7/8] Kernel: Correct pending feedback.

---
 src/core/hle/kernel/scheduler.cpp | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index e5892727e9..f2664ce65f 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -530,10 +530,11 @@ SchedulerLockAndSleep::SchedulerLockAndSleep(KernelCore& kernel, Handle& event_h
 }
 
 SchedulerLockAndSleep::~SchedulerLockAndSleep() {
-    if (!sleep_cancelled) {
-        auto& time_manager = kernel.TimeManager();
-        time_manager.ScheduleTimeEvent(event_handle, time_task, nanoseconds);
+    if (sleep_cancelled) {
+        return;
     }
+    auto& time_manager = kernel.TimeManager();
+    time_manager.ScheduleTimeEvent(event_handle, time_task, nanoseconds);
 }
 
 } // namespace Kernel

From 3d0a2375ca73ae73d2ed4ee382aa0bb0378242d0 Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow <fsahmkow27@gmail.com>
Date: Sat, 22 Feb 2020 12:39:17 -0400
Subject: [PATCH 8/8] Scheduler: Inline global scheduler in Scheduler Lock.

---
 src/core/hle/kernel/scheduler.cpp | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index f2664ce65f..c65f82fb7c 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -513,13 +513,11 @@ void Scheduler::Shutdown() {
 }
 
 SchedulerLock::SchedulerLock(KernelCore& kernel) : kernel{kernel} {
-    auto& global_scheduler = kernel.GlobalScheduler();
-    global_scheduler.Lock();
+    kernel.GlobalScheduler().Lock();
 }
 
 SchedulerLock::~SchedulerLock() {
-    auto& global_scheduler = kernel.GlobalScheduler();
-    global_scheduler.Unlock();
+    kernel.GlobalScheduler().Unlock();
 }
 
 SchedulerLockAndSleep::SchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle,