From cc9e0b702e5ec0010cd917c3df76c6f872c17e21 Mon Sep 17 00:00:00 2001 From: pineappleEA Date: Wed, 6 Jul 2022 03:26:28 +0200 Subject: [PATCH] early-access version 2817 --- README.md | 2 +- src/core/core.cpp | 6 ++- src/core/cpu_manager.cpp | 75 ++++++++++++++++++++++++-------- src/core/cpu_manager.h | 14 ++++-- src/core/hle/kernel/k_thread.cpp | 15 +------ src/core/hle/kernel/k_thread.h | 2 - src/core/hle/kernel/kernel.cpp | 41 +++++++---------- src/core/hle/kernel/kernel.h | 3 -- 8 files changed, 89 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index 861e84808..6861f9958 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 2816. +This is the source code for early-access 2817. ## Legal Notice diff --git a/src/core/core.cpp b/src/core/core.cpp index a0fcd2a4d..bad7c6dcf 100755 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -138,6 +138,7 @@ struct System::Impl { kernel.Suspend(false); core_timing.SyncPause(false); + cpu_manager.Pause(false); is_paused = false; return status; @@ -149,6 +150,7 @@ struct System::Impl { core_timing.SyncPause(true); kernel.Suspend(true); + cpu_manager.Pause(true); is_paused = true; return status; @@ -158,6 +160,7 @@ struct System::Impl { std::unique_lock lk(suspend_guard); kernel.Suspend(true); core_timing.SyncPause(true); + cpu_manager.Pause(true); return lk; } @@ -165,6 +168,7 @@ struct System::Impl { if (!is_paused) { core_timing.SyncPause(false); kernel.Suspend(false); + cpu_manager.Pause(false); } } @@ -330,8 +334,6 @@ struct System::Impl { gpu_core->NotifyShutdown(); } - kernel.ShutdownCores(); - cpu_manager.Shutdown(); debugger.reset(); services.reset(); service_manager.reset(); diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 37d3d83b9..d3d5cc009 100755 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp @@ -25,8 +25,10 @@ void CpuManager::ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager } void CpuManager::Initialize() { + running_mode = true; num_cores = is_multicore ? Core::Hardware::NUM_CPU_CORES : 1; gpu_barrier = std::make_unique(num_cores + 1); + pause_barrier = std::make_unique(num_cores + 1); for (std::size_t core = 0; core < num_cores; core++) { core_data[core].host_thread = std::jthread(ThreadStart, std::ref(*this), core); @@ -34,11 +36,8 @@ void CpuManager::Initialize() { } void CpuManager::Shutdown() { - for (std::size_t core = 0; core < num_cores; core++) { - if (core_data[core].host_thread.joinable()) { - core_data[core].host_thread.join(); - } - } + running_mode = false; + Pause(false); } void CpuManager::GuestThreadFunction() { @@ -65,10 +64,6 @@ void CpuManager::IdleThreadFunction() { } } -void CpuManager::ShutdownThreadFunction() { - ShutdownThread(); -} - /////////////////////////////////////////////////////////////////////////////// /// MultiCore /// /////////////////////////////////////////////////////////////////////////////// @@ -181,13 +176,41 @@ void CpuManager::PreemptSingleCore(bool from_running_enviroment) { } } -void CpuManager::ShutdownThread() { +void CpuManager::SuspendThread() { auto& kernel = system.Kernel(); - auto core = is_multicore ? kernel.CurrentPhysicalCoreIndex() : 0; - auto* current_thread = kernel.GetCurrentEmuThread(); + kernel.CurrentScheduler()->OnThreadStart(); - Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[core].host_context); - UNREACHABLE(); + while (true) { + auto core = is_multicore ? kernel.CurrentPhysicalCoreIndex() : 0; + auto& scheduler = *kernel.CurrentScheduler(); + Kernel::KThread* current_thread = scheduler.GetSchedulerCurrentThread(); + Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[core].host_context); + + // This shouldn't be here. This is here because the scheduler needs the current + // thread to have dispatch disabled before explicitly rescheduling. Ideally in the + // future this will be called by RequestScheduleOnInterrupt and explicitly disabling + // dispatch outside the scheduler will not be necessary. + current_thread->DisableDispatch(); + + scheduler.RescheduleCurrentCore(); + } +} + +void CpuManager::Pause(bool paused) { + std::scoped_lock lk{pause_lock}; + + 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(); } void CpuManager::RunThread(std::size_t core) { @@ -218,9 +241,27 @@ void CpuManager::RunThread(std::size_t core) { system.GPU().ObtainContext(); } - auto* current_thread = system.Kernel().CurrentScheduler()->GetIdleThread(); - Kernel::SetCurrentThread(system.Kernel(), current_thread); - Common::Fiber::YieldTo(data.host_context, *current_thread->GetHostContext()); + { + // Set the current thread on entry + auto* current_thread = system.Kernel().CurrentScheduler()->GetIdleThread(); + Kernel::SetCurrentThread(system.Kernel(), current_thread); + } + + 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(); + } + + auto current_thread = system.Kernel().CurrentScheduler()->GetSchedulerCurrentThread(); + 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 76dc58ee1..033a1f3d6 100755 --- a/src/core/cpu_manager.h +++ b/src/core/cpu_manager.h @@ -50,14 +50,16 @@ public: void Initialize(); void Shutdown(); + void Pause(bool paused); + std::function GetGuestThreadStartFunc() { return [this] { GuestThreadFunction(); }; } std::function GetIdleThreadStartFunc() { return [this] { IdleThreadFunction(); }; } - std::function GetShutdownThreadStartFunc() { - return [this] { ShutdownThreadFunction(); }; + std::function GetSuspendThreadStartFunc() { + return [this] { SuspendThread(); }; } void PreemptSingleCore(bool from_running_enviroment = true); @@ -70,7 +72,6 @@ private: void GuestThreadFunction(); void GuestRewindFunction(); void IdleThreadFunction(); - void ShutdownThreadFunction(); void MultiCoreRunGuestThread(); void MultiCoreRunGuestLoop(); @@ -82,7 +83,7 @@ private: static void ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager, std::size_t core); - void ShutdownThread(); + void SuspendThread(); void RunThread(std::size_t core); struct CoreData { @@ -90,7 +91,12 @@ private: std::jthread host_thread; }; + std::atomic running_mode{}; + std::atomic pause_state{}; + std::unique_ptr pause_barrier{}; std::unique_ptr gpu_barrier{}; + std::mutex pause_lock{}; + std::array core_data{}; bool is_async_gpu{}; diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 50cb5fc90..9e294e81f 100755 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -269,7 +269,7 @@ Result KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 Result 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, - system.GetCpuManager().GetShutdownThreadStartFunc()); + system.GetCpuManager().GetSuspendThreadStartFunc()); } Result KThread::InitializeUserThread(Core::System& system, KThread* thread, KThreadFunction func, @@ -739,19 +739,6 @@ void KThread::Continue() { KScheduler::OnThreadStateChanged(kernel, this, old_state); } -void KThread::WaitUntilSuspended() { - // Make sure we have a suspend requested. - ASSERT(IsSuspendRequested()); - - // Loop until the thread is not executing on any core. - for (std::size_t i = 0; i < static_cast(Core::Hardware::NUM_CPU_CORES); ++i) { - KThread* core_thread{}; - do { - core_thread = kernel.Scheduler(i).GetSchedulerCurrentThread(); - } while (core_thread == this); - } -} - Result KThread::SetActivity(Svc::ThreadActivity activity) { // Lock ourselves. KScopedLightLock lk(activity_pause_lock); diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index 28cd7ecb0..d2bc38518 100755 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -208,8 +208,6 @@ public: void Continue(); - void WaitUntilSuspended(); - constexpr void SetSyncedIndex(s32 index) { synced_index = index; } diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 0009193be..0eb0b98b5 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(); - InitializeShutdownThreads(); + InitializeSuspendThreads(); 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 (shutdown_threads[core_id]) { - shutdown_threads[core_id]->Close(); - shutdown_threads[core_id] = nullptr; + if (suspend_threads[core_id]) { + suspend_threads[core_id]->Close(); + suspend_threads[core_id] = nullptr; } schedulers[core_id]->Finalize(); @@ -247,13 +247,13 @@ struct KernelCore::Impl { system.CoreTiming().ScheduleEvent(time_interval, preemption_event); } - void InitializeShutdownThreads() { + void InitializeSuspendThreads() { for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { - shutdown_threads[core_id] = KThread::Create(system.Kernel()); - ASSERT(KThread::InitializeHighPriorityThread(system, shutdown_threads[core_id], {}, {}, + suspend_threads[core_id] = KThread::Create(system.Kernel()); + ASSERT(KThread::InitializeHighPriorityThread(system, suspend_threads[core_id], {}, {}, core_id) .IsSuccess()); - shutdown_threads[core_id]->SetName(fmt::format("SuspendThread:{}", core_id)); + suspend_threads[core_id]->SetName(fmt::format("SuspendThread:{}", core_id)); } } @@ -775,7 +775,7 @@ struct KernelCore::Impl { std::weak_ptr default_service_thread; Common::ThreadWorker service_threads_manager; - std::array shutdown_threads; + std::array suspend_threads; std::array interrupts{}; std::array, Core::Hardware::NUM_CPU_CORES> schedulers{}; @@ -1085,27 +1085,16 @@ const Kernel::KSharedMemory& KernelCore::GetHidBusSharedMem() const { 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); - - if (should_suspend) { - // Wait for execution to stop - for (auto* thread : process->GetThreadList()) { - thread->WaitUntilSuspended(); - } + const auto state{should_suspend ? ThreadState::Runnable : ThreadState::Waiting}; + { + KScopedSchedulerLock lk{*this}; + for (auto* thread : impl->suspend_threads) { + thread->SetState(state); + thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Suspended); } } } -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 aa0ebaa02..cae98e2d8 100755 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -280,9 +280,6 @@ public: /// Exceptional exit all processes. void ExceptionalExit(); - /// Notify emulated CPU cores to shut down. - void ShutdownCores(); - bool IsMulticore() const; bool IsShuttingDown() const;