mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-11-04 00:49:02 -06:00 
			
		
		
		
	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,39 +1204,48 @@ 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) {
 | 
				
			||||||
 | 
					                if (Scheduler(i).GetSchedulerCurrentThread()->GetOwnerProcess() ==
 | 
				
			||||||
        for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) {
 | 
					                    process.GetPointerUnsafe()) {
 | 
				
			||||||
            if (Scheduler(i).GetSchedulerCurrentThread()->GetOwnerProcess() ==
 | 
					                    // A thread has not finished running yet.
 | 
				
			||||||
                process.GetPointerUnsafe()) {
 | 
					                    // Continue waiting.
 | 
				
			||||||
                // A thread has not finished running yet.
 | 
					                    return false;
 | 
				
			||||||
                // Continue waiting.
 | 
					                }
 | 
				
			||||||
                must_wait = true;
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (!TryWait()) {
 | 
				
			||||||
 | 
					        // ...
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -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