From be59a9b258dda89e7bacca9caed906a72a4a5574 Mon Sep 17 00:00:00 2001
From: pineappleEA <pineaea@gmail.com>
Date: Tue, 14 Jun 2022 03:25:44 +0200
Subject: [PATCH] early-access version 2779

---
 README.md                                     |   2 +-
 src/core/core.cpp                             |  18 ++-
 src/core/core.h                               |   4 +-
 src/core/cpu_manager.cpp                      | 127 +++++-------------
 src/core/cpu_manager.h                        |  19 +--
 src/core/debugger/debugger.cpp                |  60 +++------
 src/core/hle/kernel/k_process.cpp             |  59 +++++++-
 src/core/hle/kernel/k_process.h               |  16 ++-
 src/core/hle/kernel/k_thread.cpp              |   8 +-
 src/core/hle/kernel/kernel.cpp                |  49 ++++---
 src/core/hle/kernel/kernel.h                  |  11 +-
 src/core/hle/kernel/svc.cpp                   |   2 +-
 .../hle/service/nvdrv/devices/nvhost_ctrl.cpp |   4 +-
 .../maxwell/structured_control_flow.cpp       |   1 -
 14 files changed, 176 insertions(+), 204 deletions(-)

diff --git a/README.md b/README.md
index 2ff12f74b..9532653b4 100755
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 yuzu emulator early access
 =============
 
-This is the source code for early-access 2778.
+This is the source code for early-access 2779.
 
 ## Legal Notice
 
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 954136adb..7723d9782 100755
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -138,7 +138,6 @@ struct System::Impl {
 
         kernel.Suspend(false);
         core_timing.SyncPause(false);
-        cpu_manager.Pause(false);
         is_paused = false;
 
         return status;
@@ -150,25 +149,22 @@ struct System::Impl {
 
         core_timing.SyncPause(true);
         kernel.Suspend(true);
-        cpu_manager.Pause(true);
         is_paused = true;
 
         return status;
     }
 
-    std::unique_lock<std::mutex> StallCPU() {
+    std::unique_lock<std::mutex> StallProcesses() {
         std::unique_lock<std::mutex> lk(suspend_guard);
         kernel.Suspend(true);
         core_timing.SyncPause(true);
-        cpu_manager.Pause(true);
         return lk;
     }
 
-    void UnstallCPU() {
+    void UnstallProcesses() {
         if (!is_paused) {
             core_timing.SyncPause(false);
             kernel.Suspend(false);
-            cpu_manager.Pause(false);
         }
     }
 
@@ -334,6 +330,8 @@ struct System::Impl {
             gpu_core->NotifyShutdown();
         }
 
+        kernel.ShutdownCores();
+        cpu_manager.Shutdown();
         debugger.reset();
         services.reset();
         service_manager.reset();
@@ -499,12 +497,12 @@ void System::DetachDebugger() {
     }
 }
 
-std::unique_lock<std::mutex> System::StallCPU() {
-    return impl->StallCPU();
+std::unique_lock<std::mutex> System::StallProcesses() {
+    return impl->StallProcesses();
 }
 
-void System::UnstallCPU() {
-    impl->UnstallCPU();
+void System::UnstallProcesses() {
+    impl->UnstallProcesses();
 }
 
 void System::InitializeDebugger() {
diff --git a/src/core/core.h b/src/core/core.h
index 5c367349e..60efe4410 100755
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -163,8 +163,8 @@ public:
     /// Forcibly detach the debugger if it is running.
     void DetachDebugger();
 
-    std::unique_lock<std::mutex> StallCPU();
-    void UnstallCPU();
+    std::unique_lock<std::mutex> StallProcesses();
+    void UnstallProcesses();
 
     /**
      * Initialize the debugger.
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index b4718fbbe..271e1ba04 100755
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -16,31 +16,28 @@
 
 namespace Core {
 
-CpuManager::CpuManager(System& system_)
-    : pause_barrier{std::make_unique<Common::Barrier>(1)}, system{system_} {}
+CpuManager::CpuManager(System& system_) : system{system_} {}
 CpuManager::~CpuManager() = default;
 
 void CpuManager::ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager,
                              std::size_t core) {
-    cpu_manager.RunThread(stop_token, core);
+    cpu_manager.RunThread(core);
 }
 
 void CpuManager::Initialize() {
-    running_mode = true;
-    if (is_multicore) {
-        for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
-            core_data[core].host_thread = std::jthread(ThreadStart, std::ref(*this), core);
-        }
-        pause_barrier = std::make_unique<Common::Barrier>(Core::Hardware::NUM_CPU_CORES + 1);
-    } else {
-        core_data[0].host_thread = std::jthread(ThreadStart, std::ref(*this), 0);
-        pause_barrier = std::make_unique<Common::Barrier>(2);
+    num_cores = is_multicore ? Core::Hardware::NUM_CPU_CORES : 1;
+
+    for (std::size_t core = 0; core < num_cores; core++) {
+        core_data[core].host_thread = std::jthread(ThreadStart, std::ref(*this), core);
     }
 }
 
 void CpuManager::Shutdown() {
-    running_mode = false;
-    Pause(false);
+    for (std::size_t core = 0; core < num_cores; core++) {
+        if (core_data[core].host_thread.joinable()) {
+            core_data[core].host_thread.join();
+        }
+    }
 }
 
 std::function<void(void*)> CpuManager::GetGuestThreadStartFunc() {
@@ -51,8 +48,8 @@ std::function<void(void*)> CpuManager::GetIdleThreadStartFunc() {
     return IdleThreadFunction;
 }
 
-std::function<void(void*)> CpuManager::GetSuspendThreadStartFunc() {
-    return SuspendThreadFunction;
+std::function<void(void*)> CpuManager::GetShutdownThreadStartFunc() {
+    return ShutdownThreadFunction;
 }
 
 void CpuManager::GuestThreadFunction(void* cpu_manager_) {
@@ -82,17 +79,12 @@ void CpuManager::IdleThreadFunction(void* cpu_manager_) {
     }
 }
 
-void CpuManager::SuspendThreadFunction(void* cpu_manager_) {
-    CpuManager* cpu_manager = static_cast<CpuManager*>(cpu_manager_);
-    if (cpu_manager->is_multicore) {
-        cpu_manager->MultiCoreRunSuspendThread();
-    } else {
-        cpu_manager->SingleCoreRunSuspendThread();
-    }
+void CpuManager::ShutdownThreadFunction(void* cpu_manager) {
+    static_cast<CpuManager*>(cpu_manager)->ShutdownThread();
 }
 
-void* CpuManager::GetStartFuncParamater() {
-    return static_cast<void*>(this);
+void* CpuManager::GetStartFuncParameter() {
+    return this;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -134,21 +126,6 @@ void CpuManager::MultiCoreRunIdleThread() {
     }
 }
 
-void CpuManager::MultiCoreRunSuspendThread() {
-    auto& kernel = system.Kernel();
-    kernel.CurrentScheduler()->OnThreadStart();
-    while (true) {
-        auto core = kernel.CurrentPhysicalCoreIndex();
-        auto& scheduler = *kernel.CurrentScheduler();
-        Kernel::KThread* current_thread = scheduler.GetCurrentThread();
-        current_thread->DisableDispatch();
-
-        Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[core].host_context);
-        ASSERT(core == kernel.CurrentPhysicalCoreIndex());
-        scheduler.RescheduleCurrentCore();
-    }
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 ///                             SingleCore                                   ///
 ///////////////////////////////////////////////////////////////////////////////
@@ -194,21 +171,6 @@ void CpuManager::SingleCoreRunIdleThread() {
     }
 }
 
-void CpuManager::SingleCoreRunSuspendThread() {
-    auto& kernel = system.Kernel();
-    kernel.CurrentScheduler()->OnThreadStart();
-    while (true) {
-        auto core = kernel.GetCurrentHostThreadID();
-        auto& scheduler = *kernel.CurrentScheduler();
-        Kernel::KThread* current_thread = scheduler.GetCurrentThread();
-        current_thread->DisableDispatch();
-
-        Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[0].host_context);
-        ASSERT(core == kernel.GetCurrentHostThreadID());
-        scheduler.RescheduleCurrentCore();
-    }
-}
-
 void CpuManager::PreemptSingleCore(bool from_running_enviroment) {
     {
         auto& kernel = system.Kernel();
@@ -241,24 +203,16 @@ void CpuManager::PreemptSingleCore(bool from_running_enviroment) {
     }
 }
 
-void CpuManager::Pause(bool paused) {
-    std::scoped_lock lk{pause_lock};
+void CpuManager::ShutdownThread() {
+    auto& kernel = system.Kernel();
+    auto core = is_multicore ? kernel.CurrentPhysicalCoreIndex() : 0;
+    auto* current_thread = kernel.GetCurrentEmuThread();
 
-    if (pause_state == paused) {
-        return;
-    }
-
-    // Set the new state
-    pause_state.store(paused);
-
-    // Wake up any waiting threads
-    pause_state.notify_all();
-
-    // Wait for all threads to successfully change state before returning
-    pause_barrier->Sync();
+    Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[core].host_context);
+    UNREACHABLE();
 }
 
-void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) {
+void CpuManager::RunThread(std::size_t core) {
     /// Initialization
     system.RegisterCoreThread(core);
     std::string name;
@@ -272,8 +226,6 @@ void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) {
     Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
     auto& data = core_data[core];
     data.host_context = Common::Fiber::ThreadToFiber();
-    const bool sc_sync = !is_async_gpu && !is_multicore;
-    bool sc_sync_first_use = sc_sync;
 
     // Cleanup
     SCOPE_EXIT({
@@ -281,32 +233,13 @@ void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) {
         MicroProfileOnThreadExit();
     });
 
-    /// Running
-    while (running_mode) {
-        if (pause_state.load(std::memory_order_relaxed)) {
-            // Wait for caller to acknowledge pausing
-            pause_barrier->Sync();
-
-            // Wait until unpaused
-            pause_state.wait(true, std::memory_order_relaxed);
-
-            // Wait for caller to acknowledge unpausing
-            pause_barrier->Sync();
-        }
-
-        if (sc_sync_first_use) {
-            system.GPU().ObtainContext();
-            sc_sync_first_use = false;
-        }
-
-        // Emulation was stopped
-        if (stop_token.stop_requested()) {
-            return;
-        }
-
-        auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread();
-        Common::Fiber::YieldTo(data.host_context, *current_thread->GetHostContext());
+    // Running
+    if (!is_async_gpu && !is_multicore) {
+        system.GPU().ObtainContext();
     }
+
+    auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread();
+    Common::Fiber::YieldTo(data.host_context, *current_thread->GetHostContext());
 }
 
 } // namespace Core
diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h
index ddd9691ca..681bdaf19 100755
--- a/src/core/cpu_manager.h
+++ b/src/core/cpu_manager.h
@@ -46,12 +46,10 @@ public:
     void Initialize();
     void Shutdown();
 
-    void Pause(bool paused);
-
     static std::function<void(void*)> GetGuestThreadStartFunc();
     static std::function<void(void*)> GetIdleThreadStartFunc();
-    static std::function<void(void*)> GetSuspendThreadStartFunc();
-    void* GetStartFuncParamater();
+    static std::function<void(void*)> GetShutdownThreadStartFunc();
+    void* GetStartFuncParameter();
 
     void PreemptSingleCore(bool from_running_enviroment = true);
 
@@ -63,38 +61,33 @@ private:
     static void GuestThreadFunction(void* cpu_manager);
     static void GuestRewindFunction(void* cpu_manager);
     static void IdleThreadFunction(void* cpu_manager);
-    static void SuspendThreadFunction(void* cpu_manager);
+    static void ShutdownThreadFunction(void* cpu_manager);
 
     void MultiCoreRunGuestThread();
     void MultiCoreRunGuestLoop();
     void MultiCoreRunIdleThread();
-    void MultiCoreRunSuspendThread();
 
     void SingleCoreRunGuestThread();
     void SingleCoreRunGuestLoop();
     void SingleCoreRunIdleThread();
-    void SingleCoreRunSuspendThread();
 
     static void ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager, std::size_t core);
 
-    void RunThread(std::stop_token stop_token, std::size_t core);
+    void ShutdownThread();
+    void RunThread(std::size_t core);
 
     struct CoreData {
         std::shared_ptr<Common::Fiber> host_context;
         std::jthread host_thread;
     };
 
-    std::atomic<bool> running_mode{};
-    std::atomic<bool> pause_state{};
-    std::unique_ptr<Common::Barrier> pause_barrier{};
-    std::mutex pause_lock{};
-
     std::array<CoreData, Core::Hardware::NUM_CPU_CORES> core_data{};
 
     bool is_async_gpu{};
     bool is_multicore{};
     std::atomic<std::size_t> current_core{};
     std::size_t idle_count{};
+    std::size_t num_cores{};
     static constexpr std::size_t max_cycle_runs = 5;
 
     System& system;
diff --git a/src/core/debugger/debugger.cpp b/src/core/debugger/debugger.cpp
index edf991d71..6f01558f9 100755
--- a/src/core/debugger/debugger.cpp
+++ b/src/core/debugger/debugger.cpp
@@ -141,9 +141,6 @@ private:
         AsyncReceiveInto(signal_pipe, pipe_data, [&](auto d) { PipeData(d); });
         AsyncReceiveInto(client_socket, client_data, [&](auto d) { ClientData(d); });
 
-        // Stop the emulated CPU.
-        AllCoreStop();
-
         // Set the active thread.
         UpdateActiveThread();
 
@@ -159,7 +156,7 @@ private:
         switch (info.type) {
         case SignalType::Stopped:
             // Stop emulation.
-            AllCoreStop();
+            PauseEmulation();
 
             // Notify the client.
             active_thread = info.thread;
@@ -171,7 +168,6 @@ private:
             frontend->ShuttingDown();
 
             // Wait for emulation to shut down gracefully now.
-            suspend.reset();
             signal_pipe.close();
             client_socket.shutdown(boost::asio::socket_base::shutdown_both);
             LOG_INFO(Debug_GDBStub, "Shut down server");
@@ -189,32 +185,24 @@ private:
                     std::scoped_lock lk{connection_lock};
                     stopped = true;
                 }
-                AllCoreStop();
+                PauseEmulation();
                 UpdateActiveThread();
                 frontend->Stopped(active_thread);
                 break;
             }
             case DebuggerAction::Continue:
-                active_thread->SetStepState(Kernel::StepState::NotStepping);
-                ResumeInactiveThreads();
-                AllCoreResume();
+                ResumeEmulation();
                 break;
             case DebuggerAction::StepThreadUnlocked:
                 active_thread->SetStepState(Kernel::StepState::StepPending);
-                ResumeInactiveThreads();
-                AllCoreResume();
+                active_thread->Resume(Kernel::SuspendType::Debug);
+                ResumeEmulation(active_thread);
                 break;
             case DebuggerAction::StepThreadLocked:
                 active_thread->SetStepState(Kernel::StepState::StepPending);
-                SuspendInactiveThreads();
-                AllCoreResume();
+                active_thread->Resume(Kernel::SuspendType::Debug);
                 break;
             case DebuggerAction::ShutdownEmulation: {
-                // Suspend all threads and release any locks held
-                active_thread->RequestSuspend(Kernel::SuspendType::Debug);
-                SuspendInactiveThreads();
-                AllCoreResume();
-
                 // Spawn another thread that will exit after shutdown,
                 // to avoid a deadlock
                 Core::System* system_ref{&system};
@@ -226,32 +214,25 @@ private:
         }
     }
 
-    void AllCoreStop() {
-        if (!suspend) {
-            suspend = system.StallCPU();
-        }
-    }
-
-    void AllCoreResume() {
-        stopped = false;
-        system.UnstallCPU();
-        suspend.reset();
-    }
-
-    void SuspendInactiveThreads() {
+    void PauseEmulation() {
+        // Put all threads to sleep on next scheduler round.
         for (auto* thread : ThreadList()) {
-            if (thread != active_thread) {
-                thread->RequestSuspend(Kernel::SuspendType::Debug);
-            }
+            thread->RequestSuspend(Kernel::SuspendType::Debug);
         }
+
+        // Signal an interrupt so that scheduler will fire.
+        system.Kernel().InterruptAllPhysicalCores();
     }
 
-    void ResumeInactiveThreads() {
+    void ResumeEmulation(Kernel::KThread* except = nullptr) {
+        // Wake up all threads.
         for (auto* thread : ThreadList()) {
-            if (thread != active_thread) {
-                thread->Resume(Kernel::SuspendType::Debug);
-                thread->SetStepState(Kernel::StepState::NotStepping);
+            if (thread == except) {
+                continue;
             }
+
+            thread->Resume(Kernel::SuspendType::Debug);
+            thread->SetStepState(Kernel::StepState::NotStepping);
         }
     }
 
@@ -260,8 +241,6 @@ private:
         if (std::find(threads.begin(), threads.end(), active_thread) == threads.end()) {
             active_thread = threads[0];
         }
-        active_thread->Resume(Kernel::SuspendType::Debug);
-        active_thread->SetStepState(Kernel::StepState::NotStepping);
     }
 
     const std::vector<Kernel::KThread*>& ThreadList() {
@@ -277,7 +256,6 @@ private:
     boost::asio::io_context io_context;
     boost::process::async_pipe signal_pipe;
     boost::asio::ip::tcp::socket client_socket;
-    std::optional<std::unique_lock<std::mutex>> suspend;
 
     SignalInfo info;
     Kernel::KThread* active_thread;
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index 8c79b4f0f..cd863e715 100755
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -275,11 +275,15 @@ void KProcess::RemoveSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr a
     shmem->Close();
 }
 
-void KProcess::RegisterThread(const KThread* thread) {
+void KProcess::RegisterThread(KThread* thread) {
+    KScopedLightLock lk{list_lock};
+
     thread_list.push_back(thread);
 }
 
-void KProcess::UnregisterThread(const KThread* thread) {
+void KProcess::UnregisterThread(KThread* thread) {
+    KScopedLightLock lk{list_lock};
+
     thread_list.remove(thread);
 }
 
@@ -297,6 +301,50 @@ ResultCode KProcess::Reset() {
     return ResultSuccess;
 }
 
+ResultCode KProcess::SetActivity(ProcessActivity activity) {
+    // Lock ourselves and the scheduler.
+    KScopedLightLock lk{state_lock};
+    KScopedLightLock list_lk{list_lock};
+    KScopedSchedulerLock sl{kernel};
+
+    // Validate our state.
+    R_UNLESS(status != ProcessStatus::Exiting, ResultInvalidState);
+    R_UNLESS(status != ProcessStatus::Exited, ResultInvalidState);
+
+    // Either pause or resume.
+    if (activity == ProcessActivity::Paused) {
+        // Verify that we're not suspended.
+        if (is_suspended) {
+            return ResultInvalidState;
+        }
+
+        // Suspend all threads.
+        for (auto* thread : GetThreadList()) {
+            thread->RequestSuspend(SuspendType::Process);
+        }
+
+        // Set ourselves as suspended.
+        SetSuspended(true);
+    } else {
+        ASSERT(activity == ProcessActivity::Runnable);
+
+        // Verify that we're suspended.
+        if (!is_suspended) {
+            return ResultInvalidState;
+        }
+
+        // Resume all threads.
+        for (auto* thread : GetThreadList()) {
+            thread->Resume(SuspendType::Process);
+        }
+
+        // Set ourselves as resumed.
+        SetSuspended(false);
+    }
+
+    return ResultSuccess;
+}
+
 ResultCode KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
                                       std::size_t code_size) {
     program_id = metadata.GetTitleID();
@@ -556,9 +604,10 @@ bool KProcess::IsSignaled() const {
 }
 
 KProcess::KProcess(KernelCore& kernel_)
-    : KAutoObjectWithSlabHeapAndContainer{kernel_},
-      page_table{std::make_unique<KPageTable>(kernel_.System())}, handle_table{kernel_},
-      address_arbiter{kernel_.System()}, condition_var{kernel_.System()}, state_lock{kernel_} {}
+    : KAutoObjectWithSlabHeapAndContainer{kernel_}, page_table{std::make_unique<KPageTable>(
+                                                        kernel_.System())},
+      handle_table{kernel_}, address_arbiter{kernel_.System()}, condition_var{kernel_.System()},
+      state_lock{kernel_}, list_lock{kernel_} {}
 
 KProcess::~KProcess() = default;
 
diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h
index 9f171e3da..e562a79b8 100755
--- a/src/core/hle/kernel/k_process.h
+++ b/src/core/hle/kernel/k_process.h
@@ -63,6 +63,11 @@ enum class ProcessStatus {
     DebugBreak,
 };
 
+enum class ProcessActivity : u32 {
+    Runnable,
+    Paused,
+};
+
 class KProcess final : public KAutoObjectWithSlabHeapAndContainer<KProcess, KWorkerTask> {
     KERNEL_AUTOOBJECT_TRAITS(KProcess, KSynchronizationObject);
 
@@ -282,17 +287,17 @@ public:
     u64 GetTotalPhysicalMemoryUsedWithoutSystemResource() const;
 
     /// Gets the list of all threads created with this process as their owner.
-    const std::list<const KThread*>& GetThreadList() const {
+    std::list<KThread*>& GetThreadList() {
         return thread_list;
     }
 
     /// Registers a thread as being created under this process,
     /// adding it to this process' thread list.
-    void RegisterThread(const KThread* thread);
+    void RegisterThread(KThread* thread);
 
     /// Unregisters a thread from this process, removing it
     /// from this process' thread list.
-    void UnregisterThread(const KThread* thread);
+    void UnregisterThread(KThread* thread);
 
     /// Clears the signaled state of the process if and only if it's signaled.
     ///
@@ -347,6 +352,8 @@ public:
 
     void DoWorkerTaskImpl();
 
+    ResultCode SetActivity(ProcessActivity activity);
+
     void PinCurrentThread(s32 core_id);
     void UnpinCurrentThread(s32 core_id);
     void UnpinThread(KThread* thread);
@@ -442,7 +449,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 KThread*> thread_list;
+    std::list<KThread*> thread_list;
 
     /// List of shared memory that are running with this process as their owner.
     std::list<KSharedMemoryInfo*> shared_memory_list;
@@ -475,6 +482,7 @@ private:
     KThread* exception_thread{};
 
     KLightLock state_lock;
+    KLightLock list_lock;
 
     using TLPTree =
         Common::IntrusiveRedBlackTreeBaseTraits<KThreadLocalPage>::TreeType<KThreadLocalPage>;
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index ea2160099..8d48a7901 100755
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -267,15 +267,15 @@ ResultCode KThread::InitializeDummyThread(KThread* thread) {
 ResultCode KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) {
     return InitializeThread(thread, {}, {}, {}, IdleThreadPriority, virt_core, {}, ThreadType::Main,
                             Core::CpuManager::GetIdleThreadStartFunc(),
-                            system.GetCpuManager().GetStartFuncParamater());
+                            system.GetCpuManager().GetStartFuncParameter());
 }
 
 ResultCode KThread::InitializeHighPriorityThread(Core::System& system, KThread* thread,
                                                  KThreadFunction func, uintptr_t arg,
                                                  s32 virt_core) {
     return InitializeThread(thread, func, arg, {}, {}, virt_core, nullptr, ThreadType::HighPriority,
-                            Core::CpuManager::GetSuspendThreadStartFunc(),
-                            system.GetCpuManager().GetStartFuncParamater());
+                            Core::CpuManager::GetShutdownThreadStartFunc(),
+                            system.GetCpuManager().GetStartFuncParameter());
 }
 
 ResultCode KThread::InitializeUserThread(Core::System& system, KThread* thread,
@@ -284,7 +284,7 @@ ResultCode KThread::InitializeUserThread(Core::System& system, KThread* thread,
     system.Kernel().GlobalSchedulerContext().AddThread(thread);
     return InitializeThread(thread, func, arg, user_stack_top, prio, virt_core, owner,
                             ThreadType::User, Core::CpuManager::GetGuestThreadStartFunc(),
-                            system.GetCpuManager().GetStartFuncParamater());
+                            system.GetCpuManager().GetStartFuncParameter());
 }
 
 void KThread::PostDestroy(uintptr_t arg) {
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index b2c4f12b4..73593c7a0 100755
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -76,7 +76,7 @@ struct KernelCore::Impl {
         InitializeMemoryLayout();
         Init::InitializeKPageBufferSlabHeap(system);
         InitializeSchedulers();
-        InitializeSuspendThreads();
+        InitializeShutdownThreads();
         InitializePreemption(kernel);
 
         RegisterHostThread();
@@ -143,9 +143,9 @@ struct KernelCore::Impl {
         CleanupObject(system_resource_limit);
 
         for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
-            if (suspend_threads[core_id]) {
-                suspend_threads[core_id]->Close();
-                suspend_threads[core_id] = nullptr;
+            if (shutdown_threads[core_id]) {
+                shutdown_threads[core_id]->Close();
+                shutdown_threads[core_id] = nullptr;
             }
 
             schedulers[core_id]->Finalize();
@@ -247,14 +247,14 @@ struct KernelCore::Impl {
         system.CoreTiming().ScheduleEvent(time_interval, preemption_event);
     }
 
-    void InitializeSuspendThreads() {
+    void InitializeShutdownThreads() {
         for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
-            suspend_threads[core_id] = KThread::Create(system.Kernel());
-            ASSERT(KThread::InitializeHighPriorityThread(system, suspend_threads[core_id], {}, {},
+            shutdown_threads[core_id] = KThread::Create(system.Kernel());
+            ASSERT(KThread::InitializeHighPriorityThread(system, shutdown_threads[core_id], {}, {},
                                                          core_id)
                        .IsSuccess());
-            suspend_threads[core_id]->SetName(fmt::format("SuspendThread:{}", core_id));
-            suspend_threads[core_id]->DisableDispatch();
+            shutdown_threads[core_id]->SetName(fmt::format("SuspendThread:{}", core_id));
+            shutdown_threads[core_id]->DisableDispatch();
         }
     }
 
@@ -769,7 +769,7 @@ struct KernelCore::Impl {
     std::weak_ptr<ServiceThread> default_service_thread;
     Common::ThreadWorker service_threads_manager;
 
-    std::array<KThread*, Core::Hardware::NUM_CPU_CORES> suspend_threads;
+    std::array<KThread*, Core::Hardware::NUM_CPU_CORES> shutdown_threads;
     std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
     std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
 
@@ -920,6 +920,12 @@ const KAutoObjectWithListContainer& KernelCore::ObjectListContainer() const {
     return *impl->global_object_list_container;
 }
 
+void KernelCore::InterruptAllPhysicalCores() {
+    for (auto& physical_core : impl->cores) {
+        physical_core.Interrupt();
+    }
+}
+
 void KernelCore::InvalidateAllInstructionCaches() {
     for (auto& physical_core : impl->cores) {
         physical_core.ArmInterface().ClearInstructionCache();
@@ -1067,19 +1073,22 @@ const Kernel::KSharedMemory& KernelCore::GetHidBusSharedMem() const {
     return *impl->hidbus_shared_mem;
 }
 
-void KernelCore::Suspend(bool in_suspention) {
-    const bool should_suspend = exception_exited || in_suspention;
-    {
-        KScopedSchedulerLock lock(*this);
-        const auto state = should_suspend ? ThreadState::Runnable : ThreadState::Waiting;
-        for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
-            impl->suspend_threads[core_id]->SetState(state);
-            impl->suspend_threads[core_id]->SetWaitReasonForDebugging(
-                ThreadWaitReasonForDebugging::Suspended);
-        }
+void KernelCore::Suspend(bool suspended) {
+    const bool should_suspend{exception_exited || suspended};
+    const auto activity = should_suspend ? ProcessActivity::Paused : ProcessActivity::Runnable;
+
+    for (auto* process : GetProcessList()) {
+        process->SetActivity(activity);
     }
 }
 
+void KernelCore::ShutdownCores() {
+    for (auto* thread : impl->shutdown_threads) {
+        void(thread->Run());
+    }
+    InterruptAllPhysicalCores();
+}
+
 bool KernelCore::IsMulticore() const {
     return impl->is_multicore;
 }
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 926e14c6f..4e7beab0e 100755
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -184,6 +184,8 @@ public:
 
     const std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& Interrupts() const;
 
+    void InterruptAllPhysicalCores();
+
     void InvalidateAllInstructionCaches();
 
     void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size);
@@ -269,12 +271,15 @@ public:
     /// Gets the shared memory object for HIDBus services.
     const Kernel::KSharedMemory& GetHidBusSharedMem() const;
 
-    /// Suspend/unsuspend the OS.
-    void Suspend(bool in_suspention);
+    /// Suspend/unsuspend all processes.
+    void Suspend(bool suspend);
 
-    /// Exceptional exit the OS.
+    /// Exceptional exit all processes.
     void ExceptionalExit();
 
+    /// Notify emulated CPU cores to shut down.
+    void ShutdownCores();
+
     bool IsMulticore() const;
 
     bool IsShuttingDown() const;
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 584fa5b1c..a1c09dd78 100755
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -2530,7 +2530,7 @@ static ResultCode GetThreadList(Core::System& system, u32* out_num_threads, VAdd
         return ResultOutOfRange;
     }
 
-    const auto* const current_process = system.Kernel().CurrentProcess();
+    auto* const current_process = system.Kernel().CurrentProcess();
     const auto total_copy_size = out_thread_ids_size * sizeof(u64);
 
     if (out_thread_ids_size > 0 &&
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index 705fefc83..527531f29 100755
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -150,9 +150,9 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector
     event.event->GetWritableEvent().Clear();
     if (events_interface.failed[event_id]) {
         {
-            auto lk = system.StallCPU();
+            auto lk = system.StallProcesses();
             gpu.WaitFence(params.syncpt_id, target_value);
-            system.UnstallCPU();
+            system.UnstallProcesses();
         }
         std::memcpy(output.data(), &params, sizeof(params));
         events_interface.failed[event_id] = false;
diff --git a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
index 8886cbd3c..578bc8c1b 100755
--- a/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
+++ b/src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
@@ -975,7 +975,6 @@ private:
     Environment& env;
     IR::AbstractSyntaxList& syntax_list;
     bool uses_demote_to_helper{};
-
     const Flow::Block dummy_flow_block;
 };
 } // Anonymous namespace