From 0c065b24869974addc4b641ae70f44dc2e34a7d6 Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Wed, 1 Apr 2026 21:08:05 +0200 Subject: [PATCH 1/5] Process.Linux/OSX: avoid loading full ProcessInfo for ProcessName and ToString. --- .../src/System/Diagnostics/Process.Unix.cs | 9 -- .../src/System/Diagnostics/Process.Windows.cs | 36 ----- .../src/System/Diagnostics/Process.cs | 137 +++++++++--------- .../Diagnostics/ProcessManager.FreeBSD.cs | 15 ++ .../Diagnostics/ProcessManager.Linux.cs | 20 +++ .../System/Diagnostics/ProcessManager.OSX.cs | 50 +++++-- .../Diagnostics/ProcessManager.SunOS.cs | 15 ++ .../Diagnostics/ProcessManager.Windows.cs | 29 ++-- .../System/Diagnostics/ProcessManager.iOS.cs | 7 + 9 files changed, 172 insertions(+), 146 deletions(-) diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Unix.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Unix.cs index 41025a9cadf42f..286a786fa00405 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Unix.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Unix.cs @@ -434,14 +434,5 @@ private SafeWaitHandle GetSafeWaitHandle() private static bool WaitForInputIdleCore(int _ /*milliseconds*/) => throw new InvalidOperationException(SR.InputIdleUnknownError); - /// Gets the friendly name of the process. - public string ProcessName - { - get - { - EnsureState(State.HaveProcessInfo); - return _processInfo!.ProcessName; - } - } } } diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs index 925f52551cf835..fc69fa1018d0d1 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs @@ -16,8 +16,6 @@ namespace System.Diagnostics { public partial class Process : IDisposable { - private string? _processName; - /// /// Creates an array of components that are associated with process resources on a /// remote computer. These process resources share the specified process name. @@ -104,7 +102,6 @@ private void RefreshCore() _haveMainWindow = false; _mainWindowTitle = null; _haveResponding = false; - _processName = null; } /// Additional logic invoked when the Process is closed. @@ -526,38 +523,5 @@ private SafeProcessHandle GetProcessHandle(int access, bool throwIfExited = true private static ConsoleEncoding GetStandardInputEncoding() => GetEncoding((int)Interop.Kernel32.GetConsoleCP()); private static ConsoleEncoding GetStandardOutputEncoding() => GetEncoding((int)Interop.Kernel32.GetConsoleOutputCP()); - - /// Gets the friendly name of the process. - public string ProcessName - { - get - { - if (_processName == null) - { - // If we already have the name via a populated ProcessInfo - // then use that one. - if (_processInfo?.ProcessName != null) - { - _processName = _processInfo!.ProcessName; - } - else - { - // Ensure that the process is not yet exited - EnsureState(State.HaveNonExitedId); - _processName = ProcessManager.GetProcessName(_processId, _machineName); - - // Fallback to slower ProcessInfo implementation if optimized way did not return a - // process name (e.g. in case of missing permissions for Non-Admin users) - if (_processName == null) - { - EnsureState(State.HaveProcessInfo); - _processName = _processInfo!.ProcessName; - } - } - } - - return _processName; - } - } } } diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs index a093dac7ceacb8..f49e22d7b80c75 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Runtime.Serialization; @@ -31,6 +32,7 @@ public partial class Process : Component private bool _isRemoteMachine; private string _machineName; private ProcessInfo? _processInfo; + private string? _processName; private ProcessThreadCollection? _threads; private ProcessModuleCollection? _modules; @@ -146,8 +148,7 @@ public int BasePriority { get { - EnsureState(State.HaveProcessInfo); - return _processInfo!.BasePriority; + return GetProcessInfo().BasePriority; } } @@ -255,6 +256,21 @@ public string MachineName } } + /// Gets the friendly name of the process. + public string ProcessName + { + get + { + EnsureState(State.HaveNonExitedId); + string? processName = _processName ??= ProcessManager.GetProcessName(_processId, _machineName, ref _processInfo); + if (processName is null) + { + ThrowNoProcessInfo(); + } + return processName; + } + } + /// /// Gets or sets the maximum allowable working set for the associated process. /// @@ -320,8 +336,7 @@ public long NonpagedSystemMemorySize64 { get { - EnsureState(State.HaveProcessInfo); - return _processInfo!.PoolNonPagedBytes; + return GetProcessInfo().PoolNonPagedBytes; } } @@ -330,8 +345,7 @@ public int NonpagedSystemMemorySize { get { - EnsureState(State.HaveProcessInfo); - return unchecked((int)_processInfo!.PoolNonPagedBytes); + return unchecked((int)GetProcessInfo().PoolNonPagedBytes); } } @@ -340,8 +354,7 @@ public long PagedMemorySize64 { get { - EnsureState(State.HaveProcessInfo); - return _processInfo!.PageFileBytes; + return GetProcessInfo().PageFileBytes; } } @@ -350,8 +363,7 @@ public int PagedMemorySize { get { - EnsureState(State.HaveProcessInfo); - return unchecked((int)_processInfo!.PageFileBytes); + return unchecked((int)GetProcessInfo().PageFileBytes); } } @@ -360,8 +372,7 @@ public long PagedSystemMemorySize64 { get { - EnsureState(State.HaveProcessInfo); - return _processInfo!.PoolPagedBytes; + return GetProcessInfo().PoolPagedBytes; } } @@ -370,8 +381,7 @@ public int PagedSystemMemorySize { get { - EnsureState(State.HaveProcessInfo); - return unchecked((int)_processInfo!.PoolPagedBytes); + return unchecked((int)GetProcessInfo().PoolPagedBytes); } } @@ -380,8 +390,7 @@ public long PeakPagedMemorySize64 { get { - EnsureState(State.HaveProcessInfo); - return _processInfo!.PageFileBytesPeak; + return GetProcessInfo().PageFileBytesPeak; } } @@ -390,8 +399,7 @@ public int PeakPagedMemorySize { get { - EnsureState(State.HaveProcessInfo); - return unchecked((int)_processInfo!.PageFileBytesPeak); + return unchecked((int)GetProcessInfo().PageFileBytesPeak); } } @@ -399,8 +407,7 @@ public long PeakWorkingSet64 { get { - EnsureState(State.HaveProcessInfo); - return _processInfo!.WorkingSetPeak; + return GetProcessInfo().WorkingSetPeak; } } @@ -409,8 +416,7 @@ public int PeakWorkingSet { get { - EnsureState(State.HaveProcessInfo); - return unchecked((int)_processInfo!.WorkingSetPeak); + return unchecked((int)GetProcessInfo().WorkingSetPeak); } } @@ -418,8 +424,7 @@ public long PeakVirtualMemorySize64 { get { - EnsureState(State.HaveProcessInfo); - return _processInfo!.VirtualBytesPeak; + return GetProcessInfo().VirtualBytesPeak; } } @@ -428,8 +433,7 @@ public int PeakVirtualMemorySize { get { - EnsureState(State.HaveProcessInfo); - return unchecked((int)_processInfo!.VirtualBytesPeak); + return unchecked((int)GetProcessInfo().VirtualBytesPeak); } } @@ -493,8 +497,7 @@ public long PrivateMemorySize64 { get { - EnsureState(State.HaveProcessInfo); - return _processInfo!.PrivateBytes; + return GetProcessInfo().PrivateBytes; } } @@ -503,8 +506,7 @@ public int PrivateMemorySize { get { - EnsureState(State.HaveProcessInfo); - return unchecked((int)_processInfo!.PrivateBytes); + return unchecked((int)GetProcessInfo().PrivateBytes); } } @@ -539,8 +541,7 @@ public int SessionId { get { - EnsureState(State.HaveProcessInfo); - return _processInfo!.SessionId; + return GetProcessInfo().SessionId; } } @@ -589,12 +590,12 @@ public ProcessThreadCollection Threads { if (_threads == null) { - EnsureState(State.HaveProcessInfo); - int count = _processInfo!._threadInfoList.Count; + ProcessInfo processInfo = GetProcessInfo(); + int count = processInfo._threadInfoList.Count; ProcessThread[] newThreadsArray = new ProcessThread[count]; for (int i = 0; i < count; i++) { - newThreadsArray[i] = new ProcessThread(_isRemoteMachine, _processId, (ThreadInfo)_processInfo._threadInfoList[i]); + newThreadsArray[i] = new ProcessThread(_isRemoteMachine, _processId, (ThreadInfo)processInfo._threadInfoList[i]); } ProcessThreadCollection newThreads = new ProcessThreadCollection(newThreadsArray); @@ -608,9 +609,9 @@ public int HandleCount { get { - EnsureState(State.HaveProcessInfo); + ProcessInfo processInfo = GetProcessInfo(); EnsureHandleCountPopulated(); - return _processInfo!.HandleCount; + return processInfo.HandleCount; } } @@ -620,8 +621,7 @@ public long VirtualMemorySize64 { get { - EnsureState(State.HaveProcessInfo); - return _processInfo!.VirtualBytes; + return GetProcessInfo().VirtualBytes; } } @@ -630,8 +630,7 @@ public int VirtualMemorySize { get { - EnsureState(State.HaveProcessInfo); - return unchecked((int)_processInfo!.VirtualBytes); + return unchecked((int)GetProcessInfo().VirtualBytes); } } @@ -743,8 +742,7 @@ public long WorkingSet64 { get { - EnsureState(State.HaveProcessInfo); - return _processInfo!.WorkingSet; + return GetProcessInfo().WorkingSet; } } @@ -753,8 +751,7 @@ public int WorkingSet { get { - EnsureState(State.HaveProcessInfo); - return unchecked((int)_processInfo!.WorkingSet); + return unchecked((int)GetProcessInfo().WorkingSet); } } @@ -971,22 +968,6 @@ private void EnsureState(State state) throw new NotSupportedException(SR.NotSupportedRemote); } - if ((state & State.HaveProcessInfo) != (State)0) - { - if (_processInfo == null) - { - if ((state & State.HaveNonExitedId) != State.HaveNonExitedId) - { - EnsureState(State.HaveNonExitedId); - } - _processInfo = ProcessManager.GetProcessInfo(_processId, _machineName); - if (_processInfo == null) - { - throw new InvalidOperationException(SR.NoProcessInfo); - } - } - } - if ((state & State.Exited) != (State)0) { if (!HasExited) @@ -1178,6 +1159,7 @@ public void Refresh() _havePriorityClass = false; _haveExitTime = false; _havePriorityBoostEnabled = false; + _processName = null; RefreshCore(); } @@ -1490,16 +1472,13 @@ public override string ToString() try { - if (Associated) + // Avoid calling GetProcessName on platforms where it throws PlatformNotSupportedException. + if (Associated && ProcessManager.IsProcessNameSupported) { - _processInfo ??= ProcessManager.GetProcessInfo(_processId, _machineName); - if (_processInfo is not null) + string? processName = _processName ?? ProcessManager.GetProcessName(_processId, _machineName, ref _processInfo); + if (processName is { Length: > 0 }) { - string processName = _processInfo.ProcessName; - if (processName.Length != 0) - { - result = $"{result} ({processName})"; - } + result = $"{result} ({processName})"; } } } @@ -1857,9 +1836,27 @@ private enum State HaveId = 0x1, IsLocal = 0x2, HaveNonExitedId = HaveId | 0x4, - HaveProcessInfo = 0x8, Exited = 0x10, Associated = 0x20, } + + private ProcessInfo GetProcessInfo() + { + ProcessInfo? processInfo = _processInfo; + if (processInfo == null) + { + EnsureState(State.HaveNonExitedId); + _processInfo = processInfo = ProcessManager.GetProcessInfo(_processId, _machineName); + if (processInfo == null) + { + ThrowNoProcessInfo(); + } + } + return processInfo; + } + + [DoesNotReturn] + private static void ThrowNoProcessInfo() => + throw new InvalidOperationException(SR.NoProcessInfo); } } diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.FreeBSD.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.FreeBSD.cs index a1b9583cebc41e..072f18fe1aa91e 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.FreeBSD.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.FreeBSD.cs @@ -20,6 +20,21 @@ internal static string GetProcPath(int processId) return Interop.Process.GetProcPath(processId); } + internal static bool IsProcessNameSupported => true; + + internal static string? GetProcessName(int processId, string machineName, ref ProcessInfo? processInfo) + { + ThrowIfRemoteMachine(machineName); + + if (processInfo is not null) + { + return processInfo.ProcessName; + } + + processInfo = CreateProcessInfo(processId); + return processInfo?.ProcessName; + } + internal static ProcessInfo? CreateProcessInfo(int pid, string? processNameFilter = null) { // Negative PIDs aren't valid diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Linux.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Linux.cs index 14ead91751253a..a220d8e1339005 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Linux.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Linux.cs @@ -38,6 +38,26 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string ma return processes.ToArray(); } + internal static bool IsProcessNameSupported => true; + + internal static string? GetProcessName(int processId, string machineName, ref ProcessInfo? processInfo) + { + ThrowIfRemoteMachine(machineName); + + if (processInfo is not null) + { + return processInfo.ProcessName; + } + + if (TryGetProcPid(processId, out Interop.procfs.ProcPid procPid) && + Interop.procfs.TryReadStatFile(procPid, out Interop.procfs.ParsedStat stat)) + { + return Process.GetUntruncatedProcessName(procPid, ref stat); + } + + return null; + } + /// Gets an array of module infos for the specified process. /// The ID of the process whose modules should be enumerated. /// The array of modules. diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.OSX.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.OSX.cs index d09790a4230fa6..a65030cf1a9200 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.OSX.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.OSX.cs @@ -21,7 +21,25 @@ private static string GetProcPath(int processId) return Interop.libproc.proc_pidpath(processId); } - internal static ProcessInfo? CreateProcessInfo(int pid, string? processNameFilter = null) + internal static bool IsProcessNameSupported => true; + + internal static string? GetProcessName(int processId, string machineName, ref ProcessInfo? processInfo) + { + ThrowIfRemoteMachine(machineName); + + if (processInfo is not null) + { + return processInfo.ProcessName; + } + // Return empty string rather than null when the process name can't be determined + // to preserve existing macOS behavior where the name defaults to "". + return GetProcessName(processId) ?? ""; + } + + internal static string? GetProcessName(int pid) + => GetProcessName(pid, out _); + + private static string? GetProcessName(int pid, out Interop.libproc.proc_taskallinfo? taskInfo, bool getInfo = false) { // Negative PIDs aren't valid ArgumentOutOfRangeException.ThrowIfNegative(pid); @@ -40,20 +58,30 @@ private static string GetProcPath(int processId) // Ignored } - // Try to get the task info. This can fail if the user permissions don't permit - // this user context to query the specified process - Interop.libproc.proc_taskallinfo? info = Interop.libproc.GetProcessInfoById(pid); + if (string.IsNullOrEmpty(processName) || getInfo) + { + // Try to get the task info. This can fail if the user permissions don't permit + // this user context to query the specified process + taskInfo = Interop.libproc.GetProcessInfoById(pid); - // If we could not get the process name from its path, attempt to use the old 15-char - // limited process name - if (string.IsNullOrEmpty(processName) && info != null) + if (taskInfo.HasValue && string.IsNullOrEmpty(processName)) + { + Interop.libproc.proc_taskallinfo temp = taskInfo.Value; + unsafe { processName = Utf8StringMarshaller.ConvertToManaged(temp.pbsd.pbi_comm); } + } + } + else { - Interop.libproc.proc_taskallinfo temp = info.Value; - unsafe { processName = Utf8StringMarshaller.ConvertToManaged(temp.pbsd.pbi_comm); } + taskInfo = default; } - // Fallback to empty string if the process name could not be retrieved in any way - processName ??= ""; + return processName; + } + + internal static ProcessInfo? CreateProcessInfo(int pid, string? processNameFilter = null) + { + Interop.libproc.proc_taskallinfo? info; + string processName = GetProcessName(pid, out info, getInfo: true) ?? ""; if (!string.IsNullOrEmpty(processNameFilter) && !string.Equals(processName, processNameFilter, StringComparison.OrdinalIgnoreCase)) { diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.SunOS.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.SunOS.cs index 9b8cc20ac57335..7c1af9a9cfca6a 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.SunOS.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.SunOS.cs @@ -71,6 +71,21 @@ internal static ProcessModuleCollection GetModules(int processId) return new ProcessModuleCollection(0); } + internal static bool IsProcessNameSupported => true; + + internal static string? GetProcessName(int processId, string machineName, ref ProcessInfo? processInfo) + { + ThrowIfRemoteMachine(machineName); + + if (processInfo is not null) + { + return processInfo.ProcessName; + } + + processInfo = CreateProcessInfo(processId); + return processInfo?.ProcessName; + } + /// /// Creates a ProcessInfo from the specified process ID. /// diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Windows.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Windows.cs index 102ba0be16367d..1b67095c08ea1b 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Windows.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Windows.cs @@ -116,28 +116,17 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string ma return null; } - /// Gets the process name for the specified process ID on the specified machine. - /// The process ID. - /// The machine name. - /// The process name for the process if it could be found; otherwise, null. - public static string? GetProcessName(int processId, string machineName) + internal static bool IsProcessNameSupported => true; + + internal static string? GetProcessName(int processId, string machineName, ref ProcessInfo? processInfo) { - if (IsRemoteMachine(machineName)) + if (processInfo is not null) { - // remote case: we take the hit of looping through all results - ProcessInfo[] processInfos = NtProcessManager.GetProcessInfos(machineName, isRemoteMachine: true); - foreach (ProcessInfo processInfo in processInfos) - { - if (processInfo.ProcessId == processId) - { - return processInfo.ProcessName; - } - } + return processInfo.ProcessName; } - else - { - // local case: do not use performance counter and also attempt to get the matching (by pid) process only + if (!IsRemoteMachine(machineName)) + { string? processName = Interop.Kernel32.GetProcessName((uint)processId); if (processName is not null) { @@ -148,10 +137,10 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string ma } } - return null; + processInfo = GetProcessInfo(processId, machineName); + return processInfo?.ProcessName; } - /// Gets the IDs of all processes on the specified machine. /// The machine to examine. /// An array of process IDs from the specified machine. diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.iOS.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.iOS.cs index 766c2dae22bd7c..87f263c95169a6 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.iOS.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.iOS.cs @@ -33,6 +33,13 @@ internal static ProcessModuleCollection GetModules(int processId) return new ProcessModuleCollection(0); } + internal static bool IsProcessNameSupported => false; + + internal static string? GetProcessName(int processId, string machineName, ref ProcessInfo? processInfo) + { + throw new PlatformNotSupportedException(); + } + private static ProcessInfo CreateProcessInfo(int pid) { throw new PlatformNotSupportedException(); From acd9842ee6f9b9185524edda52ca81ab146fdca8 Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Thu, 2 Apr 2026 16:51:44 +0200 Subject: [PATCH 2/5] Use expression-body syntax. --- .../src/System/Diagnostics/Process.cs | 140 +++--------------- 1 file changed, 20 insertions(+), 120 deletions(-) diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs index f49e22d7b80c75..9c83a4c491a824 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -145,12 +145,7 @@ private bool Associated /// /// public int BasePriority - { - get - { - return GetProcessInfo().BasePriority; - } - } + => GetProcessInfo().BasePriority; /// /// @@ -333,109 +328,49 @@ public ProcessModuleCollection Modules } public long NonpagedSystemMemorySize64 - { - get - { - return GetProcessInfo().PoolNonPagedBytes; - } - } + => GetProcessInfo().PoolNonPagedBytes; [Obsolete("Process.NonpagedSystemMemorySize has been deprecated because the type of the property can't represent all valid results. Use System.Diagnostics.Process.NonpagedSystemMemorySize64 instead.")] public int NonpagedSystemMemorySize - { - get - { - return unchecked((int)GetProcessInfo().PoolNonPagedBytes); - } - } + => unchecked((int)GetProcessInfo().PoolNonPagedBytes); public long PagedMemorySize64 - { - get - { - return GetProcessInfo().PageFileBytes; - } - } + => GetProcessInfo().PageFileBytes; [Obsolete("Process.PagedMemorySize has been deprecated because the type of the property can't represent all valid results. Use System.Diagnostics.Process.PagedMemorySize64 instead.")] public int PagedMemorySize - { - get - { - return unchecked((int)GetProcessInfo().PageFileBytes); - } - } + => unchecked((int)GetProcessInfo().PageFileBytes); public long PagedSystemMemorySize64 - { - get - { - return GetProcessInfo().PoolPagedBytes; - } - } + => GetProcessInfo().PoolPagedBytes; [Obsolete("Process.PagedSystemMemorySize has been deprecated because the type of the property can't represent all valid results. Use System.Diagnostics.Process.PagedSystemMemorySize64 instead.")] public int PagedSystemMemorySize - { - get - { - return unchecked((int)GetProcessInfo().PoolPagedBytes); - } - } + => unchecked((int)GetProcessInfo().PoolPagedBytes); public long PeakPagedMemorySize64 - { - get - { - return GetProcessInfo().PageFileBytesPeak; - } - } + => GetProcessInfo().PageFileBytesPeak; [Obsolete("Process.PeakPagedMemorySize has been deprecated because the type of the property can't represent all valid results. Use System.Diagnostics.Process.PeakPagedMemorySize64 instead.")] public int PeakPagedMemorySize - { - get - { - return unchecked((int)GetProcessInfo().PageFileBytesPeak); - } - } + => unchecked((int)GetProcessInfo().PageFileBytesPeak); public long PeakWorkingSet64 - { - get - { - return GetProcessInfo().WorkingSetPeak; - } - } + => GetProcessInfo().WorkingSetPeak; [Obsolete("Process.PeakWorkingSet has been deprecated because the type of the property can't represent all valid results. Use System.Diagnostics.Process.PeakWorkingSet64 instead.")] public int PeakWorkingSet - { - get - { - return unchecked((int)GetProcessInfo().WorkingSetPeak); - } - } + => unchecked((int)GetProcessInfo().WorkingSetPeak); public long PeakVirtualMemorySize64 - { - get - { - return GetProcessInfo().VirtualBytesPeak; - } - } + => GetProcessInfo().VirtualBytesPeak; [Obsolete("Process.PeakVirtualMemorySize has been deprecated because the type of the property can't represent all valid results. Use System.Diagnostics.Process.PeakVirtualMemorySize64 instead.")] public int PeakVirtualMemorySize - { - get - { - return unchecked((int)GetProcessInfo().VirtualBytesPeak); - } - } + => unchecked((int)GetProcessInfo().VirtualBytesPeak); /// /// @@ -494,21 +429,11 @@ public ProcessPriorityClass PriorityClass } public long PrivateMemorySize64 - { - get - { - return GetProcessInfo().PrivateBytes; - } - } + => GetProcessInfo().PrivateBytes; [Obsolete("Process.PrivateMemorySize has been deprecated because the type of the property can't represent all valid results. Use System.Diagnostics.Process.PrivateMemorySize64 instead.")] public int PrivateMemorySize - { - get - { - return unchecked((int)GetProcessInfo().PrivateBytes); - } - } + => unchecked((int)GetProcessInfo().PrivateBytes); /// /// @@ -538,12 +463,7 @@ public IntPtr ProcessorAffinity } public int SessionId - { - get - { - return GetProcessInfo().SessionId; - } - } + => GetProcessInfo().SessionId; /// /// @@ -618,21 +538,11 @@ public int HandleCount partial void EnsureHandleCountPopulated(); public long VirtualMemorySize64 - { - get - { - return GetProcessInfo().VirtualBytes; - } - } + => GetProcessInfo().VirtualBytes; [Obsolete("Process.VirtualMemorySize has been deprecated because the type of the property can't represent all valid results. Use System.Diagnostics.Process.VirtualMemorySize64 instead.")] public int VirtualMemorySize - { - get - { - return unchecked((int)GetProcessInfo().VirtualBytes); - } - } + => unchecked((int)GetProcessInfo().VirtualBytes); /// /// @@ -739,21 +649,11 @@ public StreamReader StandardError } public long WorkingSet64 - { - get - { - return GetProcessInfo().WorkingSet; - } - } + => GetProcessInfo().WorkingSet; [Obsolete("Process.WorkingSet has been deprecated because the type of the property can't represent all valid results. Use System.Diagnostics.Process.WorkingSet64 instead.")] public int WorkingSet - { - get - { - return unchecked((int)GetProcessInfo().WorkingSet); - } - } + => unchecked((int)GetProcessInfo().WorkingSet); public event EventHandler Exited { From ed184f1760ca6f8bf5eae088f4ae0f8acad56f55 Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Fri, 3 Apr 2026 10:52:11 +0200 Subject: [PATCH 3/5] Apply suggestions from code review Co-authored-by: Jan Kotas --- .../src/System/Diagnostics/Process.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs index b7f3f6fdadcf8b..43662fb1bf0d56 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -1381,7 +1381,7 @@ public override string ToString() if (Associated && ProcessManager.IsProcessNameSupported) { string? processName = _processName ?? ProcessManager.GetProcessName(_processId, _machineName, ref _processInfo); - if (processName is { Length: > 0 }) + if (!string.IsNullOrEmpty(processName)) { result = $"{result} ({processName})"; } @@ -1741,8 +1741,8 @@ private enum State HaveId = 0x1, IsLocal = 0x2, HaveNonExitedId = HaveId | 0x4, - Exited = 0x10, - Associated = 0x20, + Exited = 0x8, + Associated = 0x10, } private ProcessInfo GetProcessInfo() From 6a6cba0cb08ea94c7ba8ceccc2df84d829fcbb72 Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Fri, 3 Apr 2026 10:55:03 +0200 Subject: [PATCH 4/5] Remove IsProcessNameSupported. --- .../src/System/Diagnostics/Process.cs | 3 +-- .../src/System/Diagnostics/ProcessManager.FreeBSD.cs | 2 -- .../src/System/Diagnostics/ProcessManager.Linux.cs | 2 -- .../src/System/Diagnostics/ProcessManager.OSX.cs | 2 -- .../src/System/Diagnostics/ProcessManager.SunOS.cs | 2 -- .../src/System/Diagnostics/ProcessManager.Windows.cs | 2 -- .../src/System/Diagnostics/ProcessManager.iOS.cs | 2 -- 7 files changed, 1 insertion(+), 14 deletions(-) diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs index 43662fb1bf0d56..4d34198b5e195c 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -1377,8 +1377,7 @@ public override string ToString() try { - // Avoid calling GetProcessName on platforms where it throws PlatformNotSupportedException. - if (Associated && ProcessManager.IsProcessNameSupported) + if (Associated) { string? processName = _processName ?? ProcessManager.GetProcessName(_processId, _machineName, ref _processInfo); if (!string.IsNullOrEmpty(processName)) diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.FreeBSD.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.FreeBSD.cs index 072f18fe1aa91e..259a5ae4ca89aa 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.FreeBSD.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.FreeBSD.cs @@ -20,8 +20,6 @@ internal static string GetProcPath(int processId) return Interop.Process.GetProcPath(processId); } - internal static bool IsProcessNameSupported => true; - internal static string? GetProcessName(int processId, string machineName, ref ProcessInfo? processInfo) { ThrowIfRemoteMachine(machineName); diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Linux.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Linux.cs index a220d8e1339005..e36725c033408f 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Linux.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Linux.cs @@ -38,8 +38,6 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string ma return processes.ToArray(); } - internal static bool IsProcessNameSupported => true; - internal static string? GetProcessName(int processId, string machineName, ref ProcessInfo? processInfo) { ThrowIfRemoteMachine(machineName); diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.OSX.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.OSX.cs index a65030cf1a9200..f0df4429cd0c70 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.OSX.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.OSX.cs @@ -21,8 +21,6 @@ private static string GetProcPath(int processId) return Interop.libproc.proc_pidpath(processId); } - internal static bool IsProcessNameSupported => true; - internal static string? GetProcessName(int processId, string machineName, ref ProcessInfo? processInfo) { ThrowIfRemoteMachine(machineName); diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.SunOS.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.SunOS.cs index 7c1af9a9cfca6a..4c708e9d122b37 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.SunOS.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.SunOS.cs @@ -71,8 +71,6 @@ internal static ProcessModuleCollection GetModules(int processId) return new ProcessModuleCollection(0); } - internal static bool IsProcessNameSupported => true; - internal static string? GetProcessName(int processId, string machineName, ref ProcessInfo? processInfo) { ThrowIfRemoteMachine(machineName); diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Windows.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Windows.cs index 47a7a47ae6c9d9..0e8806b091e02e 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Windows.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Windows.cs @@ -120,8 +120,6 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string ma return null; } - internal static bool IsProcessNameSupported => true; - internal static string? GetProcessName(int processId, string machineName, ref ProcessInfo? processInfo) { if (processInfo is not null) diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.iOS.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.iOS.cs index 87f263c95169a6..be5805bb3d09c8 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.iOS.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.iOS.cs @@ -33,8 +33,6 @@ internal static ProcessModuleCollection GetModules(int processId) return new ProcessModuleCollection(0); } - internal static bool IsProcessNameSupported => false; - internal static string? GetProcessName(int processId, string machineName, ref ProcessInfo? processInfo) { throw new PlatformNotSupportedException(); From e4df8c3102681da279610799386e14b79eb912cb Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Fri, 3 Apr 2026 13:33:21 +0200 Subject: [PATCH 5/5] Apply suggestion Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../src/System/Diagnostics/Process.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs index 4d34198b5e195c..e90b3f93dce0cc 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -1379,7 +1379,7 @@ public override string ToString() { if (Associated) { - string? processName = _processName ?? ProcessManager.GetProcessName(_processId, _machineName, ref _processInfo); + string? processName = _processName ??= ProcessManager.GetProcessName(_processId, _machineName, ref _processInfo); if (!string.IsNullOrEmpty(processName)) { result = $"{result} ({processName})";