Merge pull request #13017 from liamwhite/suspension

kernel: add and enable system suspend type
This commit is contained in:
Narr the Reg 2024-02-17 17:00:07 -06:00 committed by GitHub
commit 53f8383354
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 43 additions and 32 deletions

View file

@ -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();
} }

View file

@ -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);

View file

@ -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() {

View file

@ -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();