aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
diff options
context:
space:
mode:
authorThog <me@thog.eu>2019-12-26 02:50:17 +0100
committerAc_K <Acoustik666@gmail.com>2019-12-26 02:50:17 +0100
commit55c956e2ec83b2b7f414688c4fe4ed9f1f316935 (patch)
treea543fffefd7b014d6f4a7c5688040e68edcbe018 /Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
parent87bfe681ef65ed692aa1e46e3f5f8229013cf46a (diff)
Make HLE disposable safely (#850)
* Make HLE disposable safely This fix the oldest issue with the HLE code: the kernel side disposability. Changelog: - Implement KProcess::UnpauseAndTerminateAllThreadsExcept, KThread::Terminate, KThread::TerminateCurrentProcess, KThread::PrepareForTermiation and the svc post handler accurately. - Implement svcTerminateProcess and svcExitProcess. (both untested) - Fix KHandleTable::Destroy not decrementing refcount of all objects stored in the table. - Spawn a custom KProcess with the maximum priority to terminate every guest KProcess. (terminating kernel emulation safely) - General system stability improvements to enhance the user's experience. * Fix a typo in a comment in KProcess.cs * Address gdk's comments
Diffstat (limited to 'Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs')
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs127
1 files changed, 108 insertions, 19 deletions
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
index 1b16d79a..c74f6fca 100644
--- a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
@@ -38,7 +38,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
public ulong PersonalMmHeapPagesCount { get; private set; }
- private ProcessState _state;
+ public ProcessState State { get; private set; }
private object _processLock;
private object _threadingLock;
@@ -383,7 +383,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
Name = creationInfo.Name;
- _state = ProcessState.Created;
+ State = ProcessState.Created;
_creationTimestamp = PerformanceCounter.ElapsedMilliseconds;
@@ -579,7 +579,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{
lock (_processLock)
{
- if (_state > ProcessState.CreatedAttached)
+ if (State > ProcessState.CreatedAttached)
{
return KernelResult.InvalidState;
}
@@ -733,8 +733,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
mainThread.SetEntryArguments(0, mainThreadHandle);
- ProcessState oldState = _state;
- ProcessState newState = _state != ProcessState.Created
+ ProcessState oldState = State;
+ ProcessState newState = State != ProcessState.Created
? ProcessState.Attached
: ProcessState.Started;
@@ -768,9 +768,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
private void SetState(ProcessState newState)
{
- if (_state != newState)
+ if (State != newState)
{
- _state = newState;
+ State = newState;
_signaled = true;
Signal();
@@ -820,6 +820,20 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
}
}
+ public void DecrementToZeroWhileTerminatingCurrent()
+ {
+ System.ThreadCounter.Signal();
+
+ while (Interlocked.Decrement(ref _threadCount) != 0)
+ {
+ Destroy();
+ TerminateCurrentProcess();
+ }
+
+ // Nintendo panic here because if it reaches this point, the current thread should be already dead.
+ // As we handle the death of the thread in the post SVC handler and inside the CPU emulator, we don't panic here.
+ }
+
public ulong GetMemoryCapacity()
{
ulong totalCapacity = (ulong)ResourceLimit.GetRemainingValue(LimitableResource.Memory);
@@ -909,12 +923,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
lock (_processLock)
{
- if (_state >= ProcessState.Started)
+ if (State >= ProcessState.Started)
{
- if (_state == ProcessState.Started ||
- _state == ProcessState.Crashed ||
- _state == ProcessState.Attached ||
- _state == ProcessState.DebugSuspended)
+ if (State == ProcessState.Started ||
+ State == ProcessState.Crashed ||
+ State == ProcessState.Attached ||
+ State == ProcessState.DebugSuspended)
{
SetState(ProcessState.Exiting);
@@ -933,23 +947,98 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
if (shallTerminate)
{
- // UnpauseAndTerminateAllThreadsExcept(System.Scheduler.GetCurrentThread());
+ UnpauseAndTerminateAllThreadsExcept(System.Scheduler.GetCurrentThread());
HandleTable.Destroy();
- SignalExitForDebugEvent();
+ SignalExitToDebugTerminated();
SignalExit();
}
return result;
}
- private void UnpauseAndTerminateAllThreadsExcept(KThread thread)
+ public void TerminateCurrentProcess()
{
- // TODO.
+ bool shallTerminate = false;
+
+ System.CriticalSection.Enter();
+
+ lock (_processLock)
+ {
+ if (State >= ProcessState.Started)
+ {
+ if (State == ProcessState.Started ||
+ State == ProcessState.Attached ||
+ State == ProcessState.DebugSuspended)
+ {
+ SetState(ProcessState.Exiting);
+
+ shallTerminate = true;
+ }
+ }
+ }
+
+ System.CriticalSection.Leave();
+
+ if (shallTerminate)
+ {
+ UnpauseAndTerminateAllThreadsExcept(System.Scheduler.GetCurrentThread());
+
+ HandleTable.Destroy();
+
+ // NOTE: this is supposed to be called in receiving of the mailbox.
+ SignalExitToDebugExited();
+ SignalExit();
+ }
+ }
+
+ private void UnpauseAndTerminateAllThreadsExcept(KThread currentThread)
+ {
+ lock (_threadingLock)
+ {
+ System.CriticalSection.Enter();
+
+ foreach (KThread thread in _threads)
+ {
+ if ((thread.SchedFlags & ThreadSchedState.LowMask) != ThreadSchedState.TerminationPending)
+ {
+ thread.PrepareForTermination();
+ }
+ }
+
+ System.CriticalSection.Leave();
+ }
+
+ KThread blockedThread = null;
+
+ lock (_threadingLock)
+ {
+ foreach (KThread thread in _threads)
+ {
+ if (thread != currentThread && (thread.SchedFlags & ThreadSchedState.LowMask) != ThreadSchedState.TerminationPending)
+ {
+ thread.IncrementReferenceCount();
+
+ blockedThread = thread;
+ break;
+ }
+ }
+ }
+
+ if (blockedThread != null)
+ {
+ blockedThread.Terminate();
+ blockedThread.DecrementReferenceCount();
+ }
+ }
+
+ private void SignalExitToDebugTerminated()
+ {
+ // TODO: Debug events.
}
- private void SignalExitForDebugEvent()
+ private void SignalExitToDebugExited()
{
// TODO: Debug events.
}
@@ -976,7 +1065,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
lock (_processLock)
{
- if (_state != ProcessState.Exited && _signaled)
+ if (State != ProcessState.Exited && _signaled)
{
_signaled = false;
@@ -999,7 +1088,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{
foreach (KThread thread in _threads)
{
- thread.Context.Running = false;
+ System.Scheduler.ExitThread(thread);
System.Scheduler.CoreManager.Set(thread.HostThread);
}