mirror of
https://git.ryujinx.app/projects/Kenji-NX.git
synced 2026-10-01 00:07:56 +02:00
Fix ProcessLoader stale PID validation against kernel process table
This PR adresses the following issue : `ProcessLoader.ActiveApplication` could return invalid results when `_latestPid` pointed to a process that no longer existed in the kernel's process table. The original exception path was commented out and bypassed (by sh0inx?) with `GetValueOrDefault` to prevent UI lockups, but this only resolved the symptoms without fixing the root cause. This was due to sevral factors : - `_latestPid` was never reset or validated against the actual process state - ProcessLoader maintained its own `_processesByPid` dictionary separate from the kernel's `KernelContext.Processes` - No cleanups happened when processes exited or were terminated - ProcessLoader state could drift out of sync with the kernel process table **Solution/Fixes** - Validate` _latestPid` against the kernel process table before returning `ActiveApplication` - Check process state (Exited/Exiting) and automatically clear stale references - Add thread-safe cleanup methods (`ClearProcess`, `ClearAllProcesses`) - Integrate `ClearAllProcesses` into Switch.Dispose for proper shutdown cleanup - Add warning logs when stale PID is detected and cleared for debugging **Code Changes**: - `ProcessLoader.cs`: Add `_pidLock`, update `ActiveApplication` with validation, add cleanup methods - `Switch.cs`: Call `Processes.ClearAllProcesses()` in Dispose()
This commit is contained in:
@@ -7,6 +7,7 @@ using LibHac.Tools.Fs;
|
|||||||
using LibHac.Tools.FsSystem;
|
using LibHac.Tools.FsSystem;
|
||||||
using LibHac.Tools.FsSystem.NcaUtils;
|
using LibHac.Tools.FsSystem.NcaUtils;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.Graphics.Gpu;
|
||||||
using Ryujinx.HLE.Loaders.Executables;
|
using Ryujinx.HLE.Loaders.Executables;
|
||||||
using Ryujinx.HLE.Loaders.Processes.Extensions;
|
using Ryujinx.HLE.Loaders.Processes.Extensions;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
@@ -23,16 +24,62 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
|
|
||||||
private ulong _latestPid;
|
private ulong _latestPid;
|
||||||
|
|
||||||
public ProcessResult ActiveApplication
|
private readonly object _pidLock = new();
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
public ProcessResult? ActiveApplication
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (_latestPid != 0 && _processesByPid.TryGetValue(_latestPid, out ProcessResult process))
|
lock (_pidLock)
|
||||||
return process;
|
{
|
||||||
|
// Check if _latestPid is still valid
|
||||||
|
if (_latestPid == 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
// Verify process still exists in kernel (authoritative source)
|
||||||
|
if (!_device.System.KernelContext.Processes.TryGetValue(_latestPid, out HOS.Kernel.Process.KProcess? kernelProcess))
|
||||||
|
{
|
||||||
|
// Process no longer exists in kernel, clear stale state
|
||||||
|
Logger.Warning?.Print(LogClass.Loader,
|
||||||
|
$"ActiveApplication PID {_latestPid} no longer exists in kernel, clearing stale state");
|
||||||
|
|
||||||
|
_processesByPid.TryRemove(_latestPid, out _);
|
||||||
|
_latestPid = 0;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify process still exists in ProcessLoader's dictionary
|
||||||
|
if (_processesByPid.TryGetValue(_latestPid, out ProcessResult? processResult))
|
||||||
|
{
|
||||||
|
// Additional check: verify process state
|
||||||
|
if (kernelProcess.State == HOS.Kernel.Process.ProcessState.Exited ||
|
||||||
|
kernelProcess.State == HOS.Kernel.Process.ProcessState.Exiting)
|
||||||
|
{
|
||||||
|
Logger.Warning?.Print(LogClass.Loader,
|
||||||
|
$"ActiveApplication PID {_latestPid} is in state {kernelProcess.State}, clearing");
|
||||||
|
|
||||||
|
_processesByPid.TryRemove(_latestPid, out _);
|
||||||
|
_latestPid = 0;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return processResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: clear stale PID if not in our dictionary
|
||||||
|
Logger.Warning?.Print(LogClass.Loader,
|
||||||
|
$"ActiveApplication PID {_latestPid} not in ProcessLoader dictionary, clearing");
|
||||||
|
_latestPid = 0;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
public ProcessLoader(Switch device)
|
public ProcessLoader(Switch device)
|
||||||
{
|
{
|
||||||
@@ -235,7 +282,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Explicitly null TitleId to disable the shader cache.
|
// Explicitly null TitleId to disable the shader cache.
|
||||||
Graphics.Gpu.GraphicsConfig.TitleId = null;
|
GraphicsConfig.TitleId = null;
|
||||||
_device.Gpu.HostInitalized.Set();
|
_device.Gpu.HostInitalized.Set();
|
||||||
|
|
||||||
ProcessResult processResult = ProcessLoaderHelper.LoadNsos(_device,
|
ProcessResult processResult = ProcessLoaderHelper.LoadNsos(_device,
|
||||||
@@ -274,5 +321,37 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clears a specific process from the ProcessLoader's tracking.
|
||||||
|
/// This should be called when a process exits or is terminated.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pid">The process ID to clear</param>
|
||||||
|
public void ClearProcess(ulong pid)
|
||||||
|
{
|
||||||
|
lock (_pidLock)
|
||||||
|
{
|
||||||
|
if (_processesByPid.TryRemove(pid, out _))
|
||||||
|
{
|
||||||
|
if (_latestPid == pid)
|
||||||
|
{
|
||||||
|
_latestPid = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clears all processes from the ProcessLoader's tracking.
|
||||||
|
/// This should be called during system shutdown.
|
||||||
|
/// </summary>
|
||||||
|
public void ClearAllProcesses()
|
||||||
|
{
|
||||||
|
lock (_pidLock)
|
||||||
|
{
|
||||||
|
_processesByPid.Clear();
|
||||||
|
_latestPid = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -208,6 +208,7 @@ namespace Ryujinx.HLE
|
|||||||
{
|
{
|
||||||
if (disposing)
|
if (disposing)
|
||||||
{
|
{
|
||||||
|
Processes.ClearAllProcesses();
|
||||||
System.Dispose();
|
System.Dispose();
|
||||||
AudioDeviceDriver.Dispose();
|
AudioDeviceDriver.Dispose();
|
||||||
FileSystem.Dispose();
|
FileSystem.Dispose();
|
||||||
|
|||||||
Reference in New Issue
Block a user