Merge pull request #13017 from liamwhite/suspension
kernel: add and enable system suspend type
This commit is contained in:
		| @@ -242,7 +242,7 @@ struct System::Impl { | |||||||
|     void Run() { |     void Run() { | ||||||
|         std::unique_lock<std::mutex> lk(suspend_guard); |         std::unique_lock<std::mutex> lk(suspend_guard); | ||||||
|  |  | ||||||
|         kernel.SuspendApplication(false); |         kernel.SuspendEmulation(false); | ||||||
|         core_timing.SyncPause(false); |         core_timing.SyncPause(false); | ||||||
|         is_paused.store(false, std::memory_order_relaxed); |         is_paused.store(false, std::memory_order_relaxed); | ||||||
|     } |     } | ||||||
| @@ -251,7 +251,7 @@ struct System::Impl { | |||||||
|         std::unique_lock<std::mutex> lk(suspend_guard); |         std::unique_lock<std::mutex> lk(suspend_guard); | ||||||
|  |  | ||||||
|         core_timing.SyncPause(true); |         core_timing.SyncPause(true); | ||||||
|         kernel.SuspendApplication(true); |         kernel.SuspendEmulation(true); | ||||||
|         is_paused.store(true, std::memory_order_relaxed); |         is_paused.store(true, std::memory_order_relaxed); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -261,7 +261,7 @@ struct System::Impl { | |||||||
|  |  | ||||||
|     std::unique_lock<std::mutex> StallApplication() { |     std::unique_lock<std::mutex> StallApplication() { | ||||||
|         std::unique_lock<std::mutex> lk(suspend_guard); |         std::unique_lock<std::mutex> lk(suspend_guard); | ||||||
|         kernel.SuspendApplication(true); |         kernel.SuspendEmulation(true); | ||||||
|         core_timing.SyncPause(true); |         core_timing.SyncPause(true); | ||||||
|         return lk; |         return lk; | ||||||
|     } |     } | ||||||
| @@ -269,7 +269,7 @@ struct System::Impl { | |||||||
|     void UnstallApplication() { |     void UnstallApplication() { | ||||||
|         if (!IsPaused()) { |         if (!IsPaused()) { | ||||||
|             core_timing.SyncPause(false); |             core_timing.SyncPause(false); | ||||||
|             kernel.SuspendApplication(false); |             kernel.SuspendEmulation(false); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -459,7 +459,7 @@ struct System::Impl { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         Network::CancelPendingSocketOperations(); |         Network::CancelPendingSocketOperations(); | ||||||
|         kernel.SuspendApplication(true); |         kernel.SuspendEmulation(true); | ||||||
|         if (services) { |         if (services) { | ||||||
|             services->KillNVNFlinger(); |             services->KillNVNFlinger(); | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -66,6 +66,7 @@ enum class SuspendType : u32 { | |||||||
|     Debug = 2, |     Debug = 2, | ||||||
|     Backtrace = 3, |     Backtrace = 3, | ||||||
|     Init = 4, |     Init = 4, | ||||||
|  |     System = 5, | ||||||
|  |  | ||||||
|     Count, |     Count, | ||||||
| }; | }; | ||||||
| @@ -84,8 +85,9 @@ enum class ThreadState : u16 { | |||||||
|     DebugSuspended = (1 << (2 + SuspendShift)), |     DebugSuspended = (1 << (2 + SuspendShift)), | ||||||
|     BacktraceSuspended = (1 << (3 + SuspendShift)), |     BacktraceSuspended = (1 << (3 + SuspendShift)), | ||||||
|     InitSuspended = (1 << (4 + SuspendShift)), |     InitSuspended = (1 << (4 + SuspendShift)), | ||||||
|  |     SystemSuspended = (1 << (5 + SuspendShift)), | ||||||
|  |  | ||||||
|     SuspendFlagMask = ((1 << 5) - 1) << SuspendShift, |     SuspendFlagMask = ((1 << 6) - 1) << SuspendShift, | ||||||
| }; | }; | ||||||
| DECLARE_ENUM_FLAG_OPERATORS(ThreadState); | DECLARE_ENUM_FLAG_OPERATORS(ThreadState); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1204,40 +1204,49 @@ const Kernel::KSharedMemory& KernelCore::GetHidBusSharedMem() const { | |||||||
|     return *impl->hidbus_shared_mem; |     return *impl->hidbus_shared_mem; | ||||||
| } | } | ||||||
|  |  | ||||||
| void KernelCore::SuspendApplication(bool suspended) { | void KernelCore::SuspendEmulation(bool suspended) { | ||||||
|     const bool should_suspend{exception_exited || suspended}; |     const bool should_suspend{exception_exited || suspended}; | ||||||
|     const auto activity = |     auto processes = GetProcessList(); | ||||||
|         should_suspend ? Svc::ProcessActivity::Paused : Svc::ProcessActivity::Runnable; |  | ||||||
|  |  | ||||||
|     // Get the application process. |     for (auto& process : processes) { | ||||||
|     KScopedAutoObject<KProcess> process = ApplicationProcess(); |         KScopedLightLock ll{process->GetListLock()}; | ||||||
|     if (process.IsNull()) { |  | ||||||
|  |         for (auto& thread : process->GetThreadList()) { | ||||||
|  |             if (should_suspend) { | ||||||
|  |                 thread.RequestSuspend(SuspendType::System); | ||||||
|  |             } else { | ||||||
|  |                 thread.Resume(SuspendType::System); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (!should_suspend) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Set the new activity. |  | ||||||
|     process->SetActivity(activity); |  | ||||||
|  |  | ||||||
|     // Wait for process execution to stop. |     // Wait for process execution to stop. | ||||||
|     bool must_wait{should_suspend}; |     // KernelCore::SuspendEmulation must be called from locked context, | ||||||
|  |     // or we could race another call, interfering with waiting. | ||||||
|     // KernelCore::SuspendApplication must be called from locked context, |     const auto TryWait = [&]() { | ||||||
|     // or we could race another call to SetActivity, interfering with waiting. |  | ||||||
|     while (must_wait) { |  | ||||||
|         KScopedSchedulerLock sl{*this}; |         KScopedSchedulerLock sl{*this}; | ||||||
|  |  | ||||||
|         // Assume that all threads have finished running. |         for (auto& process : processes) { | ||||||
|         must_wait = false; |  | ||||||
|  |  | ||||||
|             for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) { |             for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) { | ||||||
|                 if (Scheduler(i).GetSchedulerCurrentThread()->GetOwnerProcess() == |                 if (Scheduler(i).GetSchedulerCurrentThread()->GetOwnerProcess() == | ||||||
|                     process.GetPointerUnsafe()) { |                     process.GetPointerUnsafe()) { | ||||||
|                     // A thread has not finished running yet. |                     // A thread has not finished running yet. | ||||||
|                     // Continue waiting. |                     // Continue waiting. | ||||||
|                 must_wait = true; |                     return false; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     while (!TryWait()) { | ||||||
|  |         // ... | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| void KernelCore::ShutdownCores() { | void KernelCore::ShutdownCores() { | ||||||
| @@ -1260,7 +1269,7 @@ bool KernelCore::IsShuttingDown() const { | |||||||
|  |  | ||||||
| void KernelCore::ExceptionalExitApplication() { | void KernelCore::ExceptionalExitApplication() { | ||||||
|     exception_exited = true; |     exception_exited = true; | ||||||
|     SuspendApplication(true); |     SuspendEmulation(true); | ||||||
| } | } | ||||||
|  |  | ||||||
| void KernelCore::EnterSVCProfile() { | void KernelCore::EnterSVCProfile() { | ||||||
|   | |||||||
| @@ -258,8 +258,8 @@ public: | |||||||
|     /// Gets the shared memory object for HIDBus services. |     /// Gets the shared memory object for HIDBus services. | ||||||
|     const Kernel::KSharedMemory& GetHidBusSharedMem() const; |     const Kernel::KSharedMemory& GetHidBusSharedMem() const; | ||||||
|  |  | ||||||
|     /// Suspend/unsuspend application process. |     /// Suspend/unsuspend emulated processes. | ||||||
|     void SuspendApplication(bool suspend); |     void SuspendEmulation(bool suspend); | ||||||
|  |  | ||||||
|     /// Exceptional exit application process. |     /// Exceptional exit application process. | ||||||
|     void ExceptionalExitApplication(); |     void ExceptionalExitApplication(); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Narr the Reg
					Narr the Reg