Merge pull request #13017 from liamwhite/suspension
kernel: add and enable system suspend type
This commit is contained in:
commit
53f8383354
|
@ -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