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