From 888f499188cb869dc8f8f1597c46add65c005324 Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 13 Jun 2022 18:36:30 -0400 Subject: kernel: implement KProcess suspension --- 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 | 94 +++++++-------- 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 +- src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp | 4 +- 12 files changed, 199 insertions(+), 212 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index 954136adb..7723d9782 100644 --- 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 StallCPU() { + std::unique_lock StallProcesses() { std::unique_lock 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 System::StallCPU() { - return impl->StallCPU(); +std::unique_lock 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 100644 --- 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 StallCPU(); - void UnstallCPU(); + std::unique_lock StallProcesses(); + void UnstallProcesses(); /** * Initialize the debugger. diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index b4718fbbe..271e1ba04 100644 --- 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(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(Core::Hardware::NUM_CPU_CORES + 1); - } else { - core_data[0].host_thread = std::jthread(ThreadStart, std::ref(*this), 0); - pause_barrier = std::make_unique(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 CpuManager::GetGuestThreadStartFunc() { @@ -51,8 +48,8 @@ std::function CpuManager::GetIdleThreadStartFunc() { return IdleThreadFunction; } -std::function CpuManager::GetSuspendThreadStartFunc() { - return SuspendThreadFunction; +std::function 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(cpu_manager_); - if (cpu_manager->is_multicore) { - cpu_manager->MultiCoreRunSuspendThread(); - } else { - cpu_manager->SingleCoreRunSuspendThread(); - } +void CpuManager::ShutdownThreadFunction(void* cpu_manager) { + static_cast(cpu_manager)->ShutdownThread(); } -void* CpuManager::GetStartFuncParamater() { - return static_cast(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}; - - if (pause_state == paused) { - return; - } - - // Set the new state - pause_state.store(paused); - - // Wake up any waiting threads - pause_state.notify_all(); +void CpuManager::ShutdownThread() { + auto& kernel = system.Kernel(); + auto core = is_multicore ? kernel.CurrentPhysicalCoreIndex() : 0; + auto* current_thread = kernel.GetCurrentEmuThread(); - // 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 100644 --- 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 GetGuestThreadStartFunc(); static std::function GetIdleThreadStartFunc(); - static std::function GetSuspendThreadStartFunc(); - void* GetStartFuncParamater(); + static std::function 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 host_context; std::jthread host_thread; }; - std::atomic running_mode{}; - std::atomic pause_state{}; - std::unique_ptr pause_barrier{}; - std::mutex pause_lock{}; - std::array core_data{}; bool is_async_gpu{}; bool is_multicore{}; std::atomic 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..ab3940922 100644 --- a/src/core/debugger/debugger.cpp +++ b/src/core/debugger/debugger.cpp @@ -67,17 +67,19 @@ public: } bool SignalDebugger(SignalInfo signal_info) { - std::scoped_lock lk{connection_lock}; + { + std::scoped_lock lk{connection_lock}; - if (stopped) { - // Do not notify the debugger about another event. - // It should be ignored. - return false; - } + if (stopped) { + // Do not notify the debugger about another event. + // It should be ignored. + return false; + } - // Set up the state. - stopped = true; - info = signal_info; + // Set up the state. + stopped = true; + info = signal_info; + } // Write a single byte into the pipe to wake up the debug interface. boost::asio::write(signal_pipe, boost::asio::buffer(&stopped, sizeof(stopped))); @@ -141,9 +143,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 +158,7 @@ private: switch (info.type) { case SignalType::Stopped: // Stop emulation. - AllCoreStop(); + PauseEmulation(); // Notify the client. active_thread = info.thread; @@ -171,7 +170,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 +187,29 @@ 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(); + MarkResumed([&] { ResumeEmulation(); }); break; case DebuggerAction::StepThreadUnlocked: - active_thread->SetStepState(Kernel::StepState::StepPending); - ResumeInactiveThreads(); - AllCoreResume(); + MarkResumed([&] { + active_thread->SetStepState(Kernel::StepState::StepPending); + active_thread->Resume(Kernel::SuspendType::Debug); + ResumeEmulation(active_thread); + }); break; - case DebuggerAction::StepThreadLocked: - active_thread->SetStepState(Kernel::StepState::StepPending); - SuspendInactiveThreads(); - AllCoreResume(); + case DebuggerAction::StepThreadLocked: { + MarkResumed([&] { + active_thread->SetStepState(Kernel::StepState::StepPending); + 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,33 +221,33 @@ private: } } - void AllCoreStop() { - if (!suspend) { - suspend = system.StallCPU(); + void PauseEmulation() { + // Put all threads to sleep on next scheduler round. + for (auto* thread : ThreadList()) { + thread->RequestSuspend(Kernel::SuspendType::Debug); } - } - void AllCoreResume() { - stopped = false; - system.UnstallCPU(); - suspend.reset(); + // Signal an interrupt so that scheduler will fire. + system.Kernel().InterruptAllPhysicalCores(); } - void SuspendInactiveThreads() { + void ResumeEmulation(Kernel::KThread* except = nullptr) { + // Wake up all threads. for (auto* thread : ThreadList()) { - if (thread != active_thread) { - thread->RequestSuspend(Kernel::SuspendType::Debug); + if (thread == except) { + continue; } + + thread->SetStepState(Kernel::StepState::NotStepping); + thread->Resume(Kernel::SuspendType::Debug); } } - void ResumeInactiveThreads() { - for (auto* thread : ThreadList()) { - if (thread != active_thread) { - thread->Resume(Kernel::SuspendType::Debug); - thread->SetStepState(Kernel::StepState::NotStepping); - } - } + template + void MarkResumed(Callback&& cb) { + std::scoped_lock lk{connection_lock}; + stopped = false; + cb(); } void UpdateActiveThread() { @@ -260,8 +255,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& ThreadList() { @@ -277,7 +270,6 @@ private: boost::asio::io_context io_context; boost::process::async_pipe signal_pipe; boost::asio::ip::tcp::socket client_socket; - std::optional> 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 100644 --- 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(kernel_.System())}, handle_table{kernel_}, - address_arbiter{kernel_.System()}, condition_var{kernel_.System()}, state_lock{kernel_} {} + : KAutoObjectWithSlabHeapAndContainer{kernel_}, page_table{std::make_unique( + 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 100644 --- 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 { 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& GetThreadList() const { + std::list& 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 random_entropy{}; /// List of threads that are running with this process as their owner. - std::list thread_list; + std::list thread_list; /// List of shared memory that are running with this process as their owner. std::list shared_memory_list; @@ -475,6 +482,7 @@ private: KThread* exception_thread{}; KLightLock state_lock; + KLightLock list_lock; using TLPTree = Common::IntrusiveRedBlackTreeBaseTraits::TreeType; diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index ea2160099..8d48a7901 100644 --- 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 100644 --- 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 default_service_thread; Common::ThreadWorker service_threads_manager; - std::array suspend_threads; + std::array shutdown_threads; std::array interrupts{}; std::array, 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,17 +1073,20 @@ 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 { diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 926e14c6f..4e7beab0e 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -184,6 +184,8 @@ public: const std::array& 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 100644 --- 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 100644 --- 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& 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(), ¶ms, sizeof(params)); events_interface.failed[event_id] = false; -- cgit v1.2.3