From c08d60daf33b54bf1a6e0009149aa35cdbada328 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 31 Mar 2026 00:33:08 +0000 Subject: [PATCH 01/54] Initial plan From 8a6508b1df4721ea3235484742459656b0b3a603 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 31 Mar 2026 01:05:46 +0000 Subject: [PATCH 02/54] Improve trimability of System.Diagnostics.Process by using lazy delegate for remote machine code Use a lazily-initialized delegate (s_getRemoteProcessInfos) for PerformanceCounterLib-based remote process info retrieval. The delegate is only initialized when remote machine support is explicitly requested (via GetProcesses/GetProcessesByName/GetProcessById with a remote name), allowing NativeAOT/trimmer to eliminate PerformanceCounterLib and its dependencies for apps that only use Process.Start and other local-machine operations. Key changes: - Add s_getRemoteProcessInfos delegate and EnsureRemoteMachineFuncs() to ProcessManager.Windows.cs - Refactor IsProcessRunning(int) to not delegate to the 2-arg version (avoids including remote machine code path for local-only operations) - Change GetProcessInfos, GetProcessInfo, GetProcessName, GetProcessIds to use delegate for remote - Refactor GetProcessById(int) in Process.cs to not delegate to GetProcessById(int, string) Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/4e21bece-9420-4574-97e9-54e4e22dc1ec Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/Process.cs | 9 ++- .../Diagnostics/ProcessManager.Windows.cs | 60 +++++++++++++++---- 2 files changed, 57 insertions(+), 12 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 a093dac7ceacb8..11631522116d53 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -1048,7 +1048,14 @@ public static Process GetProcessById(int processId, string machineName) /// public static Process GetProcessById(int processId) { - return GetProcessById(processId, "."); + // Avoid calling GetProcessById(processId, ".") so that the remote machine code path + // (reachable from the 2-arg overload) is not included when only local machine support is needed. + if (!ProcessManager.IsProcessRunning(processId)) + { + throw new ArgumentException(SR.Format(SR.MissingProcess, processId.ToString())); + } + + return new Process(".", false, processId, null); } /// 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..9b2e883528de03 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 @@ -14,12 +14,46 @@ namespace System.Diagnostics { internal static partial class ProcessManager { + // Allows PerformanceCounterLib (and its dependencies) to be trimmed when remote machine + // support is not used. s_getRemoteProcessInfos is only assigned in EnsureRemoteMachineFuncs, + // which is only called from public APIs that accept a remote machine name. + private static Func? s_getRemoteProcessInfos; + + // Called from public APIs that accept remote machine names to initialize remote machine support. + internal static void EnsureRemoteMachineFuncs() => + s_getRemoteProcessInfos ??= NtProcessManager.GetProcessInfos; + /// Gets whether the process with the specified ID is currently running. /// The process ID. /// true if the process is running; otherwise, false. public static bool IsProcessRunning(int processId) { - return IsProcessRunning(processId, "."); + // Avoid calling IsProcessRunning(processId, ".") so that the remote machine code path + // (reachable from the 2-arg overload) is not included when only local machine support is needed. + // Performance optimization: First try to OpenProcess by id. + // Attempt to open handle for Idle process (processId == 0) fails with ERROR_INVALID_PARAMETER. + if (processId != 0) + { + using (SafeProcessHandle processHandle = Interop.Kernel32.OpenProcess(ProcessOptions.PROCESS_QUERY_LIMITED_INFORMATION | ProcessOptions.SYNCHRONIZE, false, processId)) + { + if (processHandle.IsInvalid) + { + int error = Marshal.GetLastWin32Error(); + if (error == Interop.Errors.ERROR_INVALID_PARAMETER) + { + Debug.Assert(processId != 0, "OpenProcess fails with ERROR_INVALID_PARAMETER for Idle Process"); + return false; + } + } + else + { + bool signaled = false; + return !HasExited(processHandle, ref signaled, out _); + } + } + } + + return Array.IndexOf(GetProcessIds(), processId) >= 0; } /// Gets whether the process with the specified ID on the specified machine is currently running. @@ -67,7 +101,8 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string ma return NtProcessInfoHelper.GetProcessInfos(processNameFilter: processNameFilter); } - ProcessInfo[] processInfos = NtProcessManager.GetProcessInfos(machineName, isRemoteMachine: true); + EnsureRemoteMachineFuncs(); + ProcessInfo[] processInfos = s_getRemoteProcessInfos!(machineName, true); if (string.IsNullOrEmpty(processNameFilter)) { return processInfos; @@ -94,7 +129,7 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string ma if (IsRemoteMachine(machineName)) { // remote case: we take the hit of looping through all results - ProcessInfo[] processInfos = NtProcessManager.GetProcessInfos(machineName, isRemoteMachine: true); + ProcessInfo[] processInfos = s_getRemoteProcessInfos!(machineName, true); foreach (ProcessInfo processInfo in processInfos) { if (processInfo.ProcessId == processId) @@ -125,7 +160,7 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string ma if (IsRemoteMachine(machineName)) { // remote case: we take the hit of looping through all results - ProcessInfo[] processInfos = NtProcessManager.GetProcessInfos(machineName, isRemoteMachine: true); + ProcessInfo[] processInfos = s_getRemoteProcessInfos!(machineName, true); foreach (ProcessInfo processInfo in processInfos) { if (processInfo.ProcessId == processId) @@ -157,13 +192,16 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string ma /// An array of process IDs from the specified machine. public static int[] GetProcessIds(string machineName) { - // Due to the lack of support for EnumModules() on coresysserver, we rely - // on PerformanceCounters to get the ProcessIds for both remote desktop - // and the local machine, unlike Desktop on which we rely on PCs only for - // remote machines. - return IsRemoteMachine(machineName) ? - NtProcessManager.GetProcessIds(machineName, true) : - GetProcessIds(); + if (!IsRemoteMachine(machineName)) + { + return GetProcessIds(); + } + + EnsureRemoteMachineFuncs(); + ProcessInfo[] infos = s_getRemoteProcessInfos!(machineName, true); + int[] ids = new int[infos.Length]; + for (int i = 0; i < infos.Length; i++) ids[i] = infos[i].ProcessId; + return ids; } /// Gets the IDs of all processes on the current machine. From 1a2682a51b896827a91860f1c7733c03dcc85bbb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 31 Mar 2026 01:24:39 +0000 Subject: [PATCH 03/54] Add Debug.Assert to document invariant in GetProcessInfo remote path Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/4e21bece-9420-4574-97e9-54e4e22dc1ec Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/ProcessManager.Windows.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 9b2e883528de03..d4314a7ddd345a 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 @@ -129,7 +129,10 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string ma if (IsRemoteMachine(machineName)) { // remote case: we take the hit of looping through all results - ProcessInfo[] processInfos = s_getRemoteProcessInfos!(machineName, true); + // EnsureRemoteMachineFuncs() must have been called by the entry point that + // created this remote Process (GetProcesses, GetProcessById, GetProcessesByName). + Debug.Assert(s_getRemoteProcessInfos is not null); + ProcessInfo[] processInfos = s_getRemoteProcessInfos(machineName, true); foreach (ProcessInfo processInfo in processInfos) { if (processInfo.ProcessId == processId) From cbd9405b4f290bec12f7062464a58633203db2ee Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 31 Mar 2026 04:27:50 +0000 Subject: [PATCH 04/54] Use NtProcessManager.GetProcessInfos directly in entry point methods Per review feedback: calling EnsureRemoteMachineFuncs immediately followed by the s_getRemoteProcessInfos delegate adds overhead without trimability benefit. In GetProcessInfos and GetProcessIds (the remote machine entry points), call NtProcessManager.GetProcessInfos directly while still calling EnsureRemoteMachineFuncs to initialize s_getRemoteProcessInfos for later use by GetProcessInfo/GetProcessName (which benefit from the delegate for trimability since they are always reachable via the Process.ToString() virtual method). Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/ca005b69-3d61-4ca2-9a31-89403b539381 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/ProcessManager.Windows.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 d4314a7ddd345a..720f992e91111a 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 @@ -102,7 +102,7 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string ma } EnsureRemoteMachineFuncs(); - ProcessInfo[] processInfos = s_getRemoteProcessInfos!(machineName, true); + ProcessInfo[] processInfos = NtProcessManager.GetProcessInfos(machineName, isRemoteMachine: true); if (string.IsNullOrEmpty(processNameFilter)) { return processInfos; @@ -201,7 +201,7 @@ public static int[] GetProcessIds(string machineName) } EnsureRemoteMachineFuncs(); - ProcessInfo[] infos = s_getRemoteProcessInfos!(machineName, true); + ProcessInfo[] infos = NtProcessManager.GetProcessInfos(machineName, isRemoteMachine: true); int[] ids = new int[infos.Length]; for (int i = 0; i < infos.Length; i++) ids[i] = infos[i].ProcessId; return ids; From 262d6a939ddc90a12be97a62ab3ca760592cfd8c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Apr 2026 05:34:42 +0000 Subject: [PATCH 05/54] Fix GetProcesses() and GetProcessesByName(name) to avoid pulling in remote machine code Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/73d92001-6e4b-4fe8-aa2f-7f42beaf4d21 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/Process.cs | 22 +++++++++++++++++-- .../Diagnostics/ProcessManager.Linux.cs | 4 ++-- .../System/Diagnostics/ProcessManager.Unix.cs | 8 +++++++ .../Diagnostics/ProcessManager.Windows.cs | 6 +++++ 4 files changed, 36 insertions(+), 4 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 11631522116d53..95e67e14effff1 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -1071,7 +1071,16 @@ public static Process GetProcessById(int processId) [SupportedOSPlatform("maccatalyst")] public static Process[] GetProcessesByName(string? processName) { - return GetProcessesByName(processName, "."); + // Avoid calling GetProcessesByName(processName, ".") so that the remote machine code path + // (reachable from the 2-arg overload on Windows) is not included when only local machine support is needed. + ProcessInfo[] processInfos = ProcessManager.GetLocalProcessInfos(processName); + Process[] processes = new Process[processInfos.Length]; + for (int i = 0; i < processInfos.Length; i++) + { + ProcessInfo processInfo = processInfos[i]; + processes[i] = new Process(".", false, processInfo.ProcessId, processInfo); + } + return processes; } /// @@ -1085,7 +1094,16 @@ public static Process[] GetProcessesByName(string? processName) [SupportedOSPlatform("maccatalyst")] public static Process[] GetProcesses() { - return GetProcesses("."); + // Avoid calling GetProcesses(".") so that the remote machine code path + // (reachable from the 1-arg overload on Windows) is not included when only local machine support is needed. + ProcessInfo[] processInfos = ProcessManager.GetLocalProcessInfos(processNameFilter: null); + Process[] processes = new Process[processInfos.Length]; + for (int i = 0; i < processInfos.Length; i++) + { + ProcessInfo processInfo = processInfos[i]; + processes[i] = new Process(".", false, processInfo.ProcessId, processInfo); + } + return processes; } /// 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..e1ae792a296032 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 @@ -20,7 +20,6 @@ internal static partial class ProcessManager /// An array of process infos, one per found process. public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string machineName) { - Debug.Assert(processNameFilter is null, "Not used on Linux"); ThrowIfRemoteMachine(machineName); // Iterate through all process IDs to load information about each process @@ -29,7 +28,8 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string ma foreach (int pid in pids) { ProcessInfo? pi = CreateProcessInfo(pid); - if (pi != null) + if (pi != null && + (processNameFilter is null || string.Equals(pi.ProcessName, processNameFilter, StringComparison.OrdinalIgnoreCase))) { processes.Add(pi); } diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs index 4c17ad5ed1c039..a0a5b4b0aace00 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs @@ -76,5 +76,13 @@ internal static void ThrowIfRemoteMachine(string machineName) throw new PlatformNotSupportedException(SR.RemoteMachinesNotSupported); } } + + /// Gets process infos for each process on the local machine, without pulling in remote machine code. + /// Optional process name to use as an inclusion filter. + /// An array of process infos, one per found process. + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + internal static ProcessInfo[] GetLocalProcessInfos(string? processNameFilter) => + GetProcessInfos(processNameFilter, "."); } } 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 720f992e91111a..d115b7cb72f1c8 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 @@ -23,6 +23,12 @@ internal static partial class ProcessManager internal static void EnsureRemoteMachineFuncs() => s_getRemoteProcessInfos ??= NtProcessManager.GetProcessInfos; + /// Gets process infos for each process on the local machine, without pulling in remote machine code. + /// Optional process name to use as an inclusion filter. + /// An array of process infos, one per found process. + internal static ProcessInfo[] GetLocalProcessInfos(string? processNameFilter) => + NtProcessInfoHelper.GetProcessInfos(processNameFilter: processNameFilter); + /// Gets whether the process with the specified ID is currently running. /// The process ID. /// true if the process is running; otherwise, false. From 0bad8b4f41f3563678a48eb234fbd9f26658a6ba Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Apr 2026 05:50:00 +0000 Subject: [PATCH 06/54] Move EnsureRemoteMachineFuncs from GetProcessIds to IsProcessRunning remote branch Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/d1f924ee-1dd4-4239-8603-f4687cef3311 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/ProcessManager.Windows.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) 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 d115b7cb72f1c8..1f454d54942e47 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 @@ -68,11 +68,20 @@ public static bool IsProcessRunning(int processId) /// true if the process is running; otherwise, false. public static bool IsProcessRunning(int processId, string machineName) { + if (IsRemoteMachine(machineName)) + { + // Ensure the remote-machine delegate is initialized. GetProcessById will create a + // Process with this machine name, and the delegate must be set before that Process + // is used (e.g. via ToString() → GetProcessInfo). + EnsureRemoteMachineFuncs(); + return Array.IndexOf(GetProcessIds(machineName), processId) >= 0; + } + // Performance optimization for the local machine: // First try to OpenProcess by id, if valid handle is returned verify that process is running // When the attempt to open a handle fails due to lack of permissions enumerate all processes and compare ids // Attempt to open handle for Idle process (processId == 0) fails with ERROR_INVALID_PARAMETER - if (processId != 0 && !IsRemoteMachine(machineName)) + if (processId != 0) { using (SafeProcessHandle processHandle = Interop.Kernel32.OpenProcess(ProcessOptions.PROCESS_QUERY_LIMITED_INFORMATION | ProcessOptions.SYNCHRONIZE, false, processId)) { @@ -206,7 +215,6 @@ public static int[] GetProcessIds(string machineName) return GetProcessIds(); } - EnsureRemoteMachineFuncs(); ProcessInfo[] infos = NtProcessManager.GetProcessInfos(machineName, isRemoteMachine: true); int[] ids = new int[infos.Length]; for (int i = 0; i < infos.Length; i++) ids[i] = infos[i].ProcessId; From 541f513664b8472f602c13316b6d4e5d37dc99a6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Apr 2026 06:59:35 +0000 Subject: [PATCH 07/54] Remove parenthetical overload references from trimability comments in Process.cs Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/006b03f3-80a5-42a2-ae1f-d335c64b98a3 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/Process.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 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 95e67e14effff1..37c39be1b288ee 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -1048,8 +1048,7 @@ public static Process GetProcessById(int processId, string machineName) /// public static Process GetProcessById(int processId) { - // Avoid calling GetProcessById(processId, ".") so that the remote machine code path - // (reachable from the 2-arg overload) is not included when only local machine support is needed. + // Avoid calling GetProcessById(processId, ".") so that remote machine code is not included when only local machine support is needed. if (!ProcessManager.IsProcessRunning(processId)) { throw new ArgumentException(SR.Format(SR.MissingProcess, processId.ToString())); @@ -1071,8 +1070,7 @@ public static Process GetProcessById(int processId) [SupportedOSPlatform("maccatalyst")] public static Process[] GetProcessesByName(string? processName) { - // Avoid calling GetProcessesByName(processName, ".") so that the remote machine code path - // (reachable from the 2-arg overload on Windows) is not included when only local machine support is needed. + // Avoid calling GetProcessesByName(processName, ".") so that remote machine code is not included when only local machine support is needed. ProcessInfo[] processInfos = ProcessManager.GetLocalProcessInfos(processName); Process[] processes = new Process[processInfos.Length]; for (int i = 0; i < processInfos.Length; i++) @@ -1094,8 +1092,7 @@ public static Process[] GetProcessesByName(string? processName) [SupportedOSPlatform("maccatalyst")] public static Process[] GetProcesses() { - // Avoid calling GetProcesses(".") so that the remote machine code path - // (reachable from the 1-arg overload on Windows) is not included when only local machine support is needed. + // Avoid calling GetProcesses(".") so that remote machine code is not included when only local machine support is needed. ProcessInfo[] processInfos = ProcessManager.GetLocalProcessInfos(processNameFilter: null); Process[] processes = new Process[processInfos.Length]; for (int i = 0; i < processInfos.Length; i++) From 4ad117fd1c351f25d220fd2678ff0d96904526c8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Apr 2026 07:20:30 +0000 Subject: [PATCH 08/54] Rename GetLocalProcessInfos to GetProcessInfos; simplify IsProcessRunning/GetProcessInfos 2-arg overloads to call 1-arg Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/d21f4f2b-8240-4edd-8313-6108fa88012b Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/Process.cs | 4 +-- .../System/Diagnostics/ProcessManager.BSD.cs | 19 +++++++---- .../Diagnostics/ProcessManager.Linux.cs | 17 +++++++--- .../Diagnostics/ProcessManager.SunOS.cs | 17 +++++++--- .../System/Diagnostics/ProcessManager.Unix.cs | 7 ---- .../Diagnostics/ProcessManager.Windows.cs | 33 +++---------------- .../System/Diagnostics/ProcessManager.iOS.cs | 12 ++++++- 7 files changed, 54 insertions(+), 55 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 37c39be1b288ee..24ded951224e36 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -1071,7 +1071,7 @@ public static Process GetProcessById(int processId) public static Process[] GetProcessesByName(string? processName) { // Avoid calling GetProcessesByName(processName, ".") so that remote machine code is not included when only local machine support is needed. - ProcessInfo[] processInfos = ProcessManager.GetLocalProcessInfos(processName); + ProcessInfo[] processInfos = ProcessManager.GetProcessInfos(processName); Process[] processes = new Process[processInfos.Length]; for (int i = 0; i < processInfos.Length; i++) { @@ -1093,7 +1093,7 @@ public static Process[] GetProcessesByName(string? processName) public static Process[] GetProcesses() { // Avoid calling GetProcesses(".") so that remote machine code is not included when only local machine support is needed. - ProcessInfo[] processInfos = ProcessManager.GetLocalProcessInfos(processNameFilter: null); + ProcessInfo[] processInfos = ProcessManager.GetProcessInfos(processNameFilter: null); Process[] processes = new Process[processInfos.Length]; for (int i = 0; i < processInfos.Length; i++) { diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.BSD.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.BSD.cs index 4e58702f6c74db..de4faa32782868 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.BSD.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.BSD.cs @@ -9,16 +9,13 @@ namespace System.Diagnostics { internal static partial class ProcessManager { - /// Gets process infos for each process on the specified machine. + /// Gets process infos for each process on the local machine. /// Optional process name to use as an inclusion filter. - /// The target machine. /// An array of process infos, one per found process. - public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string machineName) + public static ProcessInfo[] GetProcessInfos(string? processNameFilter) { - ThrowIfRemoteMachine(machineName); - // Iterate through all process IDs to load information about each process - int[] pids = GetProcessIds(machineName); + int[] pids = GetProcessIds(); var processes = new ArrayBuilder(processNameFilter is null ? pids.Length : 0); foreach (int pid in pids) { @@ -32,6 +29,16 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string ma return processes.ToArray(); } + /// Gets process infos for each process on the specified machine. + /// Optional process name to use as an inclusion filter. + /// The target machine. + /// An array of process infos, one per found process. + public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string machineName) + { + ThrowIfRemoteMachine(machineName); + return GetProcessInfos(processNameFilter); + } + /// 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.Linux.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Linux.cs index e1ae792a296032..27d6925d01198a 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 @@ -14,14 +14,11 @@ internal static partial class ProcessManager /// Gets the IDs of all processes on the current machine. public static int[] GetProcessIds() => new List(EnumerateProcessIds()).ToArray(); - /// Gets process infos for each process on the specified machine. + /// Gets process infos for each process on the local machine. /// Optional process name to use as an inclusion filter. - /// The target machine. /// An array of process infos, one per found process. - public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string machineName) + public static ProcessInfo[] GetProcessInfos(string? processNameFilter) { - ThrowIfRemoteMachine(machineName); - // Iterate through all process IDs to load information about each process IEnumerable pids = EnumerateProcessIds(); ArrayBuilder processes = default; @@ -38,6 +35,16 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string ma return processes.ToArray(); } + /// Gets process infos for each process on the specified machine. + /// Optional process name to use as an inclusion filter. + /// The target machine. + /// An array of process infos, one per found process. + public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string machineName) + { + ThrowIfRemoteMachine(machineName); + return GetProcessInfos(processNameFilter); + } + /// 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.SunOS.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.SunOS.cs index 9b8cc20ac57335..81c968a4373a8c 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 @@ -17,14 +17,11 @@ public static int[] GetProcessIds() return new List(pids).ToArray(); } - /// Gets process infos for each process on the specified machine. + /// Gets process infos for each process on the local machine. /// Optional process name to use as an inclusion filter. - /// The target machine. /// An array of process infos, one per found process. - public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string machineName) + public static ProcessInfo[] GetProcessInfos(string? processNameFilter) { - ThrowIfRemoteMachine(machineName); - // Iterate through all process IDs to load information about each process IEnumerable pids = EnumerateProcessIds(); ArrayBuilder processes = default; @@ -40,6 +37,16 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string ma return processes.ToArray(); } + /// Gets process infos for each process on the specified machine. + /// Optional process name to use as an inclusion filter. + /// The target machine. + /// An array of process infos, one per found process. + public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string machineName) + { + ThrowIfRemoteMachine(machineName); + return GetProcessInfos(processNameFilter); + } + /// 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.Unix.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs index a0a5b4b0aace00..040c02580d89fa 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs @@ -77,12 +77,5 @@ internal static void ThrowIfRemoteMachine(string machineName) } } - /// Gets process infos for each process on the local machine, without pulling in remote machine code. - /// Optional process name to use as an inclusion filter. - /// An array of process infos, one per found process. - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - internal static ProcessInfo[] GetLocalProcessInfos(string? processNameFilter) => - GetProcessInfos(processNameFilter, "."); } } 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 1f454d54942e47..2ae0b4f02f5908 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 @@ -23,10 +23,10 @@ internal static partial class ProcessManager internal static void EnsureRemoteMachineFuncs() => s_getRemoteProcessInfos ??= NtProcessManager.GetProcessInfos; - /// Gets process infos for each process on the local machine, without pulling in remote machine code. + /// Gets process infos for each process on the local machine. /// Optional process name to use as an inclusion filter. /// An array of process infos, one per found process. - internal static ProcessInfo[] GetLocalProcessInfos(string? processNameFilter) => + internal static ProcessInfo[] GetProcessInfos(string? processNameFilter) => NtProcessInfoHelper.GetProcessInfos(processNameFilter: processNameFilter); /// Gets whether the process with the specified ID is currently running. @@ -77,32 +77,7 @@ public static bool IsProcessRunning(int processId, string machineName) return Array.IndexOf(GetProcessIds(machineName), processId) >= 0; } - // Performance optimization for the local machine: - // First try to OpenProcess by id, if valid handle is returned verify that process is running - // When the attempt to open a handle fails due to lack of permissions enumerate all processes and compare ids - // Attempt to open handle for Idle process (processId == 0) fails with ERROR_INVALID_PARAMETER - if (processId != 0) - { - using (SafeProcessHandle processHandle = Interop.Kernel32.OpenProcess(ProcessOptions.PROCESS_QUERY_LIMITED_INFORMATION | ProcessOptions.SYNCHRONIZE, false, processId)) - { - if (processHandle.IsInvalid) - { - int error = Marshal.GetLastWin32Error(); - if (error == Interop.Errors.ERROR_INVALID_PARAMETER) - { - Debug.Assert(processId != 0, "OpenProcess fails with ERROR_INVALID_PARAMETER for Idle Process"); - return false; - } - } - else - { - bool signaled = false; - return !HasExited(processHandle, ref signaled, out _); - } - } - } - - return Array.IndexOf(GetProcessIds(machineName), processId) >= 0; + return IsProcessRunning(processId); } /// Gets process infos for each process on the specified machine. @@ -113,7 +88,7 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string ma { if (!IsRemoteMachine(machineName)) { - return NtProcessInfoHelper.GetProcessInfos(processNameFilter: processNameFilter); + return GetProcessInfos(processNameFilter); } EnsureRemoteMachineFuncs(); 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..b9a3118a15b7f9 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 @@ -14,6 +14,16 @@ public static int[] GetProcessIds() throw new PlatformNotSupportedException(); } + /// Gets process infos for each process on the local machine. + /// Optional process name to use as an inclusion filter. + /// An array of process infos, one per found process. + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + public static ProcessInfo[] GetProcessInfos(string? processNameFilter) + { + throw new PlatformNotSupportedException(); + } + /// Gets process infos for each process on the specified machine. /// Optional process name to use as an inclusion filter. /// The target machine. @@ -22,7 +32,7 @@ public static int[] GetProcessIds() [UnsupportedOSPlatform("tvos")] public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string machineName) { - throw new PlatformNotSupportedException(); + return GetProcessInfos(processNameFilter); } /// Gets an array of module infos for the specified process. From 29b45dbce39991188384336b80b7a0c3c12b03eb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Apr 2026 07:54:38 +0000 Subject: [PATCH 09/54] Add HandleRemoteMachineSupport; add 3-arg GetProcessInfos to avoid redundant IsRemoteMachine call Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/7a23b1ac-d737-455f-92e8-2a8d94ef6eff Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/Process.Windows.cs | 4 +- .../src/System/Diagnostics/Process.cs | 7 ++-- .../System/Diagnostics/ProcessManager.Unix.cs | 24 ++++++++++++ .../Diagnostics/ProcessManager.Windows.cs | 39 +++++++++++++------ 4 files changed, 58 insertions(+), 16 deletions(-) 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 aa2b3e7fcb7ee8..ae34fd19bc3557 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 @@ -27,9 +27,9 @@ public partial class Process : IDisposable [SupportedOSPlatform("maccatalyst")] public static Process[] GetProcessesByName(string? processName, string machineName) { - bool isRemoteMachine = ProcessManager.IsRemoteMachine(machineName); + bool isRemoteMachine = ProcessManager.HandleRemoteMachineSupport(machineName); - ProcessInfo[] processInfos = ProcessManager.GetProcessInfos(processName, machineName); + ProcessInfo[] processInfos = ProcessManager.GetProcessInfos(processName, isRemoteMachine, machineName); Process[] processes = new Process[processInfos.Length]; for (int i = 0; i < processInfos.Length; i++) 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 24ded951224e36..b1f78f6b7dad1e 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -1032,12 +1032,13 @@ private void SetWorkingSetLimits(IntPtr? min, IntPtr? max) /// public static Process GetProcessById(int processId, string machineName) { + bool isRemoteMachine = ProcessManager.HandleRemoteMachineSupport(machineName); if (!ProcessManager.IsProcessRunning(processId, machineName)) { throw new ArgumentException(SR.Format(SR.MissingProcess, processId.ToString())); } - return new Process(machineName, ProcessManager.IsRemoteMachine(machineName), processId, null); + return new Process(machineName, isRemoteMachine, processId, null); } /// @@ -1115,8 +1116,8 @@ public static Process[] GetProcesses() [SupportedOSPlatform("maccatalyst")] public static Process[] GetProcesses(string machineName) { - bool isRemoteMachine = ProcessManager.IsRemoteMachine(machineName); - ProcessInfo[] processInfos = ProcessManager.GetProcessInfos(processNameFilter: null, machineName); + bool isRemoteMachine = ProcessManager.HandleRemoteMachineSupport(machineName); + ProcessInfo[] processInfos = ProcessManager.GetProcessInfos(processNameFilter: null, isRemoteMachine, machineName); Process[] processes = new Process[processInfos.Length]; for (int i = 0; i < processInfos.Length; i++) { diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs index 040c02580d89fa..d6db949eb57c04 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs @@ -77,5 +77,29 @@ internal static void ThrowIfRemoteMachine(string machineName) } } + /// + /// Validates that the machine supports remote queries. Throws for remote machines on Unix. + /// + /// The target machine name. + /// Always returns false on Unix since remote machines are not supported. + internal static bool HandleRemoteMachineSupport(string machineName) + { + ThrowIfRemoteMachine(machineName); + return false; + } + + /// Gets process infos for each process on the specified machine. + /// On Unix, and are unused since remote machines are not supported. + /// Optional process name to use as an inclusion filter. + /// Unused on Unix. + /// Unused on Unix. + /// An array of process infos, one per found process. + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] +#pragma warning disable IDE0060 + public static ProcessInfo[] GetProcessInfos(string? processNameFilter, bool isRemoteMachine, string machineName) => + GetProcessInfos(processNameFilter); +#pragma warning restore IDE0060 + } } 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 2ae0b4f02f5908..bb3fdad439658e 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 @@ -15,13 +15,24 @@ namespace System.Diagnostics internal static partial class ProcessManager { // Allows PerformanceCounterLib (and its dependencies) to be trimmed when remote machine - // support is not used. s_getRemoteProcessInfos is only assigned in EnsureRemoteMachineFuncs, + // support is not used. s_getRemoteProcessInfos is only assigned in HandleRemoteMachineSupport, // which is only called from public APIs that accept a remote machine name. private static Func? s_getRemoteProcessInfos; - // Called from public APIs that accept remote machine names to initialize remote machine support. - internal static void EnsureRemoteMachineFuncs() => - s_getRemoteProcessInfos ??= NtProcessManager.GetProcessInfos; + /// + /// Validates that the machine supports remote queries and initializes remote machine support. + /// + /// The target machine name. + /// true if the machine is remote; otherwise, false. + internal static bool HandleRemoteMachineSupport(string machineName) + { + if (IsRemoteMachine(machineName)) + { + s_getRemoteProcessInfos ??= NtProcessManager.GetProcessInfos; + return true; + } + return false; + } /// Gets process infos for each process on the local machine. /// Optional process name to use as an inclusion filter. @@ -70,10 +81,6 @@ public static bool IsProcessRunning(int processId, string machineName) { if (IsRemoteMachine(machineName)) { - // Ensure the remote-machine delegate is initialized. GetProcessById will create a - // Process with this machine name, and the delegate must be set before that Process - // is used (e.g. via ToString() → GetProcessInfo). - EnsureRemoteMachineFuncs(); return Array.IndexOf(GetProcessIds(machineName), processId) >= 0; } @@ -86,12 +93,22 @@ public static bool IsProcessRunning(int processId, string machineName) /// An array of process infos, one per found process. public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string machineName) { - if (!IsRemoteMachine(machineName)) + bool isRemoteMachine = HandleRemoteMachineSupport(machineName); + return GetProcessInfos(processNameFilter, isRemoteMachine, machineName); + } + + /// Gets process infos for each process on the specified machine. + /// Optional process name to use as an inclusion filter. + /// Whether the machine is remote; avoids a redundant call. + /// The target machine. + /// An array of process infos, one per found process. + public static ProcessInfo[] GetProcessInfos(string? processNameFilter, bool isRemoteMachine, string machineName) + { + if (!isRemoteMachine) { return GetProcessInfos(processNameFilter); } - EnsureRemoteMachineFuncs(); ProcessInfo[] processInfos = NtProcessManager.GetProcessInfos(machineName, isRemoteMachine: true); if (string.IsNullOrEmpty(processNameFilter)) { @@ -119,7 +136,7 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string ma if (IsRemoteMachine(machineName)) { // remote case: we take the hit of looping through all results - // EnsureRemoteMachineFuncs() must have been called by the entry point that + // HandleRemoteMachineSupport must have been called by the entry point that // created this remote Process (GetProcesses, GetProcessById, GetProcessesByName). Debug.Assert(s_getRemoteProcessInfos is not null); ProcessInfo[] processInfos = s_getRemoteProcessInfos(machineName, true); From 0b0f364fd77acdff952fc578d53da7c56e72a57c Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 2 Apr 2026 01:02:47 -0700 Subject: [PATCH 10/54] Apply suggestion from @jkotas --- .../src/System/Diagnostics/ProcessManager.Windows.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 bb3fdad439658e..130d61b18c258f 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 @@ -46,7 +46,7 @@ internal static ProcessInfo[] GetProcessInfos(string? processNameFilter) => public static bool IsProcessRunning(int processId) { // Avoid calling IsProcessRunning(processId, ".") so that the remote machine code path - // (reachable from the 2-arg overload) is not included when only local machine support is needed. + // is not included when only local machine support is needed. // Performance optimization: First try to OpenProcess by id. // Attempt to open handle for Idle process (processId == 0) fails with ERROR_INVALID_PARAMETER. if (processId != 0) From 5d340a0ecbfc459b14b4aa7754f936ab4d07e651 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Apr 2026 08:10:26 +0000 Subject: [PATCH 11/54] De-dup 2-arg GetProcessInfos to Unix.cs; remove isRemoteMachine from NtProcessManager.GetProcessInfos; delete unused NtProcessManager.GetProcessIds(string,bool) Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/3830f5d5-73cc-4e25-a7cc-d3ba4c16e72f Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../System/Diagnostics/ProcessManager.BSD.cs | 10 ------- .../Diagnostics/ProcessManager.Linux.cs | 10 ------- .../Diagnostics/ProcessManager.SunOS.cs | 10 ------- .../System/Diagnostics/ProcessManager.Unix.cs | 12 ++++++++ .../Diagnostics/ProcessManager.Windows.cs | 30 +++++-------------- .../System/Diagnostics/ProcessManager.iOS.cs | 11 ------- 6 files changed, 19 insertions(+), 64 deletions(-) diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.BSD.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.BSD.cs index de4faa32782868..bf7af99799b19d 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.BSD.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.BSD.cs @@ -29,16 +29,6 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter) return processes.ToArray(); } - /// Gets process infos for each process on the specified machine. - /// Optional process name to use as an inclusion filter. - /// The target machine. - /// An array of process infos, one per found process. - public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string machineName) - { - ThrowIfRemoteMachine(machineName); - return GetProcessInfos(processNameFilter); - } - /// 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.Linux.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Linux.cs index 27d6925d01198a..a5432b374867fc 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 @@ -35,16 +35,6 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter) return processes.ToArray(); } - /// Gets process infos for each process on the specified machine. - /// Optional process name to use as an inclusion filter. - /// The target machine. - /// An array of process infos, one per found process. - public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string machineName) - { - ThrowIfRemoteMachine(machineName); - return GetProcessInfos(processNameFilter); - } - /// 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.SunOS.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.SunOS.cs index 81c968a4373a8c..458532e2093335 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 @@ -37,16 +37,6 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter) return processes.ToArray(); } - /// Gets process infos for each process on the specified machine. - /// Optional process name to use as an inclusion filter. - /// The target machine. - /// An array of process infos, one per found process. - public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string machineName) - { - ThrowIfRemoteMachine(machineName); - return GetProcessInfos(processNameFilter); - } - /// 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.Unix.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs index d6db949eb57c04..7322118d774f1a 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs @@ -88,6 +88,18 @@ internal static bool HandleRemoteMachineSupport(string machineName) return false; } + /// Gets process infos for each process on the specified machine. + /// Optional process name to use as an inclusion filter. + /// The target machine. + /// An array of process infos, one per found process. + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string machineName) + { + ThrowIfRemoteMachine(machineName); + return GetProcessInfos(processNameFilter); + } + /// Gets process infos for each process on the specified machine. /// On Unix, and are unused since remote machines are not supported. /// Optional process name to use as an inclusion filter. 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 130d61b18c258f..da5728e4bf3046 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 @@ -17,7 +17,7 @@ internal static partial class ProcessManager // Allows PerformanceCounterLib (and its dependencies) to be trimmed when remote machine // support is not used. s_getRemoteProcessInfos is only assigned in HandleRemoteMachineSupport, // which is only called from public APIs that accept a remote machine name. - private static Func? s_getRemoteProcessInfos; + private static Func? s_getRemoteProcessInfos; /// /// Validates that the machine supports remote queries and initializes remote machine support. @@ -109,7 +109,7 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter, bool isRe return GetProcessInfos(processNameFilter); } - ProcessInfo[] processInfos = NtProcessManager.GetProcessInfos(machineName, isRemoteMachine: true); + ProcessInfo[] processInfos = NtProcessManager.GetProcessInfos(machineName); if (string.IsNullOrEmpty(processNameFilter)) { return processInfos; @@ -139,7 +139,7 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter, bool isRe // HandleRemoteMachineSupport must have been called by the entry point that // created this remote Process (GetProcesses, GetProcessById, GetProcessesByName). Debug.Assert(s_getRemoteProcessInfos is not null); - ProcessInfo[] processInfos = s_getRemoteProcessInfos(machineName, true); + ProcessInfo[] processInfos = s_getRemoteProcessInfos(machineName); foreach (ProcessInfo processInfo in processInfos) { if (processInfo.ProcessId == processId) @@ -170,7 +170,7 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter, bool isRe if (IsRemoteMachine(machineName)) { // remote case: we take the hit of looping through all results - ProcessInfo[] processInfos = s_getRemoteProcessInfos!(machineName, true); + ProcessInfo[] processInfos = s_getRemoteProcessInfos!(machineName); foreach (ProcessInfo processInfo in processInfos) { if (processInfo.ProcessId == processId) @@ -207,7 +207,7 @@ public static int[] GetProcessIds(string machineName) return GetProcessIds(); } - ProcessInfo[] infos = NtProcessManager.GetProcessInfos(machineName, isRemoteMachine: true); + ProcessInfo[] infos = NtProcessManager.GetProcessInfos(machineName); int[] ids = new int[infos.Length]; for (int i = 0; i < infos.Length; i++) ids[i] = infos[i].ProcessId; return ids; @@ -409,15 +409,6 @@ internal static int SystemProcessID } } - public static int[] GetProcessIds(string machineName, bool isRemoteMachine) - { - ProcessInfo[] infos = GetProcessInfos(machineName, isRemoteMachine); - int[] ids = new int[infos.Length]; - for (int i = 0; i < infos.Length; i++) - ids[i] = infos[i].ProcessId; - return ids; - } - public static int[] GetProcessIds() { int[] processIds = ArrayPool.Shared.Rent(256); @@ -465,7 +456,7 @@ public static int GetProcessIdFromHandle(SafeProcessHandle processHandle) return Interop.Kernel32.GetProcessId(processHandle); } - public static ProcessInfo[] GetProcessInfos(string machineName, bool isRemoteMachine) + public static ProcessInfo[] GetProcessInfos(string machineName) { try { @@ -476,14 +467,7 @@ public static ProcessInfo[] GetProcessInfos(string machineName, bool isRemoteMac } catch (Exception e) { - if (isRemoteMachine) - { - throw new InvalidOperationException(SR.CouldntConnectToRemoteMachine, e); - } - else - { - throw; - } + throw new InvalidOperationException(SR.CouldntConnectToRemoteMachine, e); } } 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 b9a3118a15b7f9..c8958a18aeef1f 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 @@ -24,17 +24,6 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter) throw new PlatformNotSupportedException(); } - /// Gets process infos for each process on the specified machine. - /// Optional process name to use as an inclusion filter. - /// The target machine. - /// An array of process infos, one per found process. - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string machineName) - { - return GetProcessInfos(processNameFilter); - } - /// Gets an array of module infos for the specified process. /// The ID of the process whose modules should be enumerated. /// The array of modules. From 033ab8fd2495ab32ceb05118c27e307bbd4af647 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 2 Apr 2026 01:18:40 -0700 Subject: [PATCH 12/54] Apply suggestion from @jkotas --- .../src/System/Diagnostics/ProcessManager.Windows.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 da5728e4bf3046..9e1379c4448429 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 @@ -20,7 +20,8 @@ internal static partial class ProcessManager private static Func? s_getRemoteProcessInfos; /// - /// Validates that the machine supports remote queries and initializes remote machine support. + /// Initializes remote machine support if necessary. This method should be called in all public + /// entrypoints with machineName argument. /// /// The target machine name. /// true if the machine is remote; otherwise, false. From 023f34d41318b03cecefc5811c61ad9c8c2e3fcd Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 2 Apr 2026 01:24:27 -0700 Subject: [PATCH 13/54] Apply suggestion from @jkotas --- .../src/System/Diagnostics/ProcessManager.Windows.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) 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 9e1379c4448429..f39fc461cd4bb9 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 @@ -137,10 +137,7 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter, bool isRe if (IsRemoteMachine(machineName)) { // remote case: we take the hit of looping through all results - // HandleRemoteMachineSupport must have been called by the entry point that - // created this remote Process (GetProcesses, GetProcessById, GetProcessesByName). - Debug.Assert(s_getRemoteProcessInfos is not null); - ProcessInfo[] processInfos = s_getRemoteProcessInfos(machineName); + ProcessInfo[] processInfos = s_getRemoteProcessInfos!(machineName); foreach (ProcessInfo processInfo in processInfos) { if (processInfo.ProcessId == processId) From ad51e3783d091af3d26d9146580fd2a1356bae45 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Apr 2026 08:30:43 +0000 Subject: [PATCH 14/54] Pass isRemoteMachine as arg through IsProcessRunning/GetProcessIds/GetProcessInfos; swap (machineName, isRemoteMachine) ordering for consistency Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/abda5dea-fa01-4886-b4e8-3e7d106aec2f Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/Process.Windows.cs | 2 +- .../src/System/Diagnostics/Process.cs | 4 +-- .../System/Diagnostics/ProcessManager.Unix.cs | 14 +++++++-- .../Diagnostics/ProcessManager.Windows.cs | 29 ++++++++++--------- 4 files changed, 30 insertions(+), 19 deletions(-) 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 ae34fd19bc3557..3526d80bf5934b 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 @@ -29,7 +29,7 @@ public static Process[] GetProcessesByName(string? processName, string machineNa { bool isRemoteMachine = ProcessManager.HandleRemoteMachineSupport(machineName); - ProcessInfo[] processInfos = ProcessManager.GetProcessInfos(processName, isRemoteMachine, machineName); + ProcessInfo[] processInfos = ProcessManager.GetProcessInfos(processName, machineName, isRemoteMachine); Process[] processes = new Process[processInfos.Length]; for (int i = 0; i < processInfos.Length; i++) 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 b1f78f6b7dad1e..3f75236fee5d45 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -1033,7 +1033,7 @@ private void SetWorkingSetLimits(IntPtr? min, IntPtr? max) public static Process GetProcessById(int processId, string machineName) { bool isRemoteMachine = ProcessManager.HandleRemoteMachineSupport(machineName); - if (!ProcessManager.IsProcessRunning(processId, machineName)) + if (!ProcessManager.IsProcessRunning(processId, machineName, isRemoteMachine)) { throw new ArgumentException(SR.Format(SR.MissingProcess, processId.ToString())); } @@ -1117,7 +1117,7 @@ public static Process[] GetProcesses() public static Process[] GetProcesses(string machineName) { bool isRemoteMachine = ProcessManager.HandleRemoteMachineSupport(machineName); - ProcessInfo[] processInfos = ProcessManager.GetProcessInfos(processNameFilter: null, isRemoteMachine, machineName); + ProcessInfo[] processInfos = ProcessManager.GetProcessInfos(processNameFilter: null, machineName, isRemoteMachine); Process[] processes = new Process[processInfos.Length]; for (int i = 0; i < processInfos.Length; i++) { diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs index 7322118d774f1a..dc8e0f018d87a1 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs @@ -10,6 +10,16 @@ namespace System.Diagnostics { internal static partial class ProcessManager { + /// Gets whether the process with the specified ID on the specified machine is currently running. + /// The process ID. + /// The machine name. + /// Unused on Unix since remote machines are not supported. + /// true if the process is running; otherwise, false. +#pragma warning disable IDE0060 + public static bool IsProcessRunning(int processId, string machineName, bool isRemoteMachine) => + IsProcessRunning(processId); +#pragma warning restore IDE0060 + /// Gets whether the process with the specified ID on the specified machine is currently running. /// The process ID. /// The machine name. @@ -103,13 +113,13 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string ma /// Gets process infos for each process on the specified machine. /// On Unix, and are unused since remote machines are not supported. /// Optional process name to use as an inclusion filter. - /// Unused on Unix. /// Unused on Unix. + /// Unused on Unix. /// An array of process infos, one per found process. [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] #pragma warning disable IDE0060 - public static ProcessInfo[] GetProcessInfos(string? processNameFilter, bool isRemoteMachine, string machineName) => + public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string machineName, bool isRemoteMachine) => GetProcessInfos(processNameFilter); #pragma warning restore IDE0060 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 f39fc461cd4bb9..f490b82255b377 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 @@ -77,33 +77,33 @@ public static bool IsProcessRunning(int processId) /// Gets whether the process with the specified ID on the specified machine is currently running. /// The process ID. /// The machine name. + /// Whether the machine is remote; avoids a redundant call. /// true if the process is running; otherwise, false. - public static bool IsProcessRunning(int processId, string machineName) + public static bool IsProcessRunning(int processId, string machineName, bool isRemoteMachine) { - if (IsRemoteMachine(machineName)) + if (isRemoteMachine) { - return Array.IndexOf(GetProcessIds(machineName), processId) >= 0; + return Array.IndexOf(GetProcessIds(machineName, isRemoteMachine), processId) >= 0; } return IsProcessRunning(processId); } - /// Gets process infos for each process on the specified machine. - /// Optional process name to use as an inclusion filter. - /// The target machine. - /// An array of process infos, one per found process. - public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string machineName) + /// Gets whether the process with the specified ID on the specified machine is currently running. + /// The process ID. + /// The machine name. + /// true if the process is running; otherwise, false. + public static bool IsProcessRunning(int processId, string machineName) { - bool isRemoteMachine = HandleRemoteMachineSupport(machineName); - return GetProcessInfos(processNameFilter, isRemoteMachine, machineName); + return IsProcessRunning(processId, machineName, IsRemoteMachine(machineName)); } /// Gets process infos for each process on the specified machine. /// Optional process name to use as an inclusion filter. - /// Whether the machine is remote; avoids a redundant call. /// The target machine. + /// Whether the machine is remote; avoids a redundant call. /// An array of process infos, one per found process. - public static ProcessInfo[] GetProcessInfos(string? processNameFilter, bool isRemoteMachine, string machineName) + public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string machineName, bool isRemoteMachine) { if (!isRemoteMachine) { @@ -197,10 +197,11 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter, bool isRe /// Gets the IDs of all processes on the specified machine. /// The machine to examine. + /// Whether the machine is remote; avoids a redundant call. /// An array of process IDs from the specified machine. - public static int[] GetProcessIds(string machineName) + public static int[] GetProcessIds(string machineName, bool isRemoteMachine) { - if (!IsRemoteMachine(machineName)) + if (!isRemoteMachine) { return GetProcessIds(); } From 6935198a2177467644039043ed4b63042af32a78 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 2 Apr 2026 01:43:11 -0700 Subject: [PATCH 15/54] Apply suggestion from @jkotas --- .../src/System/Diagnostics/ProcessManager.Windows.cs | 2 -- 1 file changed, 2 deletions(-) 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 f490b82255b377..ed1163c85bfd29 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 @@ -46,8 +46,6 @@ internal static ProcessInfo[] GetProcessInfos(string? processNameFilter) => /// true if the process is running; otherwise, false. public static bool IsProcessRunning(int processId) { - // Avoid calling IsProcessRunning(processId, ".") so that the remote machine code path - // is not included when only local machine support is needed. // Performance optimization: First try to OpenProcess by id. // Attempt to open handle for Idle process (processId == 0) fails with ERROR_INVALID_PARAMETER. if (processId != 0) From 588a25238ba1a44abb7180e79f7a4dd09592ea39 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Apr 2026 08:46:15 +0000 Subject: [PATCH 16/54] Use s_getRemoteProcessInfos in GetProcessInfos; inline ThrowIfRemoteMachine and remove it Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/560e83b9-a909-44e1-ba8e-56b1d51e93f8 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/Process.BSD.cs | 5 ++- .../src/System/Diagnostics/Process.Linux.cs | 5 ++- .../System/Diagnostics/ProcessManager.Unix.cs | 32 ++++++++++--------- .../Diagnostics/ProcessManager.Windows.cs | 2 +- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.BSD.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.BSD.cs index 97c0b27c730982..03e73845a59ef0 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.BSD.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.BSD.cs @@ -18,7 +18,10 @@ public partial class Process [SupportedOSPlatform("maccatalyst")] public static Process[] GetProcessesByName(string? processName, string machineName) { - ProcessManager.ThrowIfRemoteMachine(machineName); + if (ProcessManager.IsRemoteMachine(machineName)) + { + throw new PlatformNotSupportedException(SR.RemoteMachinesNotSupported); + } int[] procIds = ProcessManager.GetProcessIds(); var processes = new ArrayBuilder(string.IsNullOrEmpty(processName) ? procIds.Length : 0); diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs index 449543d53db458..6d867191320e2b 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs @@ -24,7 +24,10 @@ public partial class Process : IDisposable [SupportedOSPlatform("maccatalyst")] public static Process[] GetProcessesByName(string? processName, string machineName) { - ProcessManager.ThrowIfRemoteMachine(machineName); + if (ProcessManager.IsRemoteMachine(machineName)) + { + throw new PlatformNotSupportedException(SR.RemoteMachinesNotSupported); + } processName ??= ""; diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs index dc8e0f018d87a1..0a1872b79d6ba6 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs @@ -26,7 +26,10 @@ public static bool IsProcessRunning(int processId, string machineName, bool isRe /// true if the process is running; otherwise, false. public static bool IsProcessRunning(int processId, string machineName) { - ThrowIfRemoteMachine(machineName); + if (IsRemoteMachine(machineName)) + { + throw new PlatformNotSupportedException(SR.RemoteMachinesNotSupported); + } return IsProcessRunning(processId); } @@ -48,7 +51,10 @@ public static bool IsProcessRunning(int processId) /// The ProcessInfo for the process if it could be found; otherwise, null. public static ProcessInfo? GetProcessInfo(int processId, string machineName) { - ThrowIfRemoteMachine(machineName); + if (IsRemoteMachine(machineName)) + { + throw new PlatformNotSupportedException(SR.RemoteMachinesNotSupported); + } return CreateProcessInfo(processId); } @@ -60,7 +66,10 @@ public static bool IsProcessRunning(int processId) [SupportedOSPlatform("maccatalyst")] public static int[] GetProcessIds(string machineName) { - ThrowIfRemoteMachine(machineName); + if (IsRemoteMachine(machineName)) + { + throw new PlatformNotSupportedException(SR.RemoteMachinesNotSupported); + } return GetProcessIds(); } @@ -79,22 +88,12 @@ private static bool IsRemoteMachineCore(string machineName) machineName != Interop.Sys.GetHostName(); } - internal static void ThrowIfRemoteMachine(string machineName) + internal static bool HandleRemoteMachineSupport(string machineName) { if (IsRemoteMachine(machineName)) { throw new PlatformNotSupportedException(SR.RemoteMachinesNotSupported); } - } - - /// - /// Validates that the machine supports remote queries. Throws for remote machines on Unix. - /// - /// The target machine name. - /// Always returns false on Unix since remote machines are not supported. - internal static bool HandleRemoteMachineSupport(string machineName) - { - ThrowIfRemoteMachine(machineName); return false; } @@ -106,7 +105,10 @@ internal static bool HandleRemoteMachineSupport(string machineName) [UnsupportedOSPlatform("tvos")] public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string machineName) { - ThrowIfRemoteMachine(machineName); + if (IsRemoteMachine(machineName)) + { + throw new PlatformNotSupportedException(SR.RemoteMachinesNotSupported); + } return GetProcessInfos(processNameFilter); } 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 ed1163c85bfd29..c6d5c4525d522d 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 @@ -108,7 +108,7 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string ma return GetProcessInfos(processNameFilter); } - ProcessInfo[] processInfos = NtProcessManager.GetProcessInfos(machineName); + ProcessInfo[] processInfos = s_getRemoteProcessInfos!(machineName); if (string.IsNullOrEmpty(processNameFilter)) { return processInfos; From 679b872d0d52978672122e7e99cde5ca7fd610eb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Apr 2026 09:03:16 +0000 Subject: [PATCH 17/54] Remove dead IsProcessRunning(int,string) and GetProcessInfos(string?,string) overloads; flip IsProcessRunning(int,string,bool) to check !isRemoteMachine first Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/60011ee5-0e6e-44f8-afca-9358301227f3 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../System/Diagnostics/ProcessManager.Unix.cs | 28 ------------------- .../Diagnostics/ProcessManager.Windows.cs | 15 ++-------- 2 files changed, 3 insertions(+), 40 deletions(-) diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs index 0a1872b79d6ba6..b84edb0c4c78a8 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs @@ -20,19 +20,6 @@ public static bool IsProcessRunning(int processId, string machineName, bool isRe IsProcessRunning(processId); #pragma warning restore IDE0060 - /// Gets whether the process with the specified ID on the specified machine is currently running. - /// The process ID. - /// The machine name. - /// true if the process is running; otherwise, false. - public static bool IsProcessRunning(int processId, string machineName) - { - if (IsRemoteMachine(machineName)) - { - throw new PlatformNotSupportedException(SR.RemoteMachinesNotSupported); - } - return IsProcessRunning(processId); - } - /// Gets whether the process with the specified ID is currently running. /// The process ID. /// true if the process is running; otherwise, false. @@ -97,21 +84,6 @@ internal static bool HandleRemoteMachineSupport(string machineName) return false; } - /// Gets process infos for each process on the specified machine. - /// Optional process name to use as an inclusion filter. - /// The target machine. - /// An array of process infos, one per found process. - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string machineName) - { - if (IsRemoteMachine(machineName)) - { - throw new PlatformNotSupportedException(SR.RemoteMachinesNotSupported); - } - return GetProcessInfos(processNameFilter); - } - /// Gets process infos for each process on the specified machine. /// On Unix, and are unused since remote machines are not supported. /// Optional process name to use as an inclusion filter. 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 c6d5c4525d522d..11c654995a27ed 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 @@ -79,21 +79,12 @@ public static bool IsProcessRunning(int processId) /// true if the process is running; otherwise, false. public static bool IsProcessRunning(int processId, string machineName, bool isRemoteMachine) { - if (isRemoteMachine) + if (!isRemoteMachine) { - return Array.IndexOf(GetProcessIds(machineName, isRemoteMachine), processId) >= 0; + return IsProcessRunning(processId); } - return IsProcessRunning(processId); - } - - /// Gets whether the process with the specified ID on the specified machine is currently running. - /// The process ID. - /// The machine name. - /// true if the process is running; otherwise, false. - public static bool IsProcessRunning(int processId, string machineName) - { - return IsProcessRunning(processId, machineName, IsRemoteMachine(machineName)); + return Array.IndexOf(GetProcessIds(machineName, isRemoteMachine), processId) >= 0; } /// Gets process infos for each process on the specified machine. From 447190e128e9e7eba4e66ad6268c341416472e8c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Apr 2026 09:35:44 +0000 Subject: [PATCH 18/54] Use HandleRemoteMachineSupport in Process.BSD.cs and Process.Linux.cs Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/917b94fc-00fd-4307-b544-64c7db71f45a Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/Process.BSD.cs | 5 +---- .../src/System/Diagnostics/Process.Linux.cs | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.BSD.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.BSD.cs index 03e73845a59ef0..238c86d8a70c1f 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.BSD.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.BSD.cs @@ -18,10 +18,7 @@ public partial class Process [SupportedOSPlatform("maccatalyst")] public static Process[] GetProcessesByName(string? processName, string machineName) { - if (ProcessManager.IsRemoteMachine(machineName)) - { - throw new PlatformNotSupportedException(SR.RemoteMachinesNotSupported); - } + ProcessManager.HandleRemoteMachineSupport(machineName); int[] procIds = ProcessManager.GetProcessIds(); var processes = new ArrayBuilder(string.IsNullOrEmpty(processName) ? procIds.Length : 0); diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs index 6d867191320e2b..8e4bc989f7de8c 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs @@ -24,10 +24,7 @@ public partial class Process : IDisposable [SupportedOSPlatform("maccatalyst")] public static Process[] GetProcessesByName(string? processName, string machineName) { - if (ProcessManager.IsRemoteMachine(machineName)) - { - throw new PlatformNotSupportedException(SR.RemoteMachinesNotSupported); - } + ProcessManager.HandleRemoteMachineSupport(machineName); processName ??= ""; From e9f6f41575055b84a7093e5d48e80b7e2e087285 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Apr 2026 10:01:29 +0000 Subject: [PATCH 19/54] Revert Linux GetProcessInfos filter; add assert back; filter by name in GetProcessesByName Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/5d1df815-608a-4338-9f99-fa2302e430f6 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/Process.cs | 14 ++++++++------ .../src/System/Diagnostics/ProcessManager.Linux.cs | 5 +++-- 2 files changed, 11 insertions(+), 8 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 3f75236fee5d45..8734d7ef5ff6a9 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -1072,14 +1072,16 @@ public static Process GetProcessById(int processId) public static Process[] GetProcessesByName(string? processName) { // Avoid calling GetProcessesByName(processName, ".") so that remote machine code is not included when only local machine support is needed. - ProcessInfo[] processInfos = ProcessManager.GetProcessInfos(processName); - Process[] processes = new Process[processInfos.Length]; - for (int i = 0; i < processInfos.Length; i++) + ProcessInfo[] processInfos = ProcessManager.GetProcessInfos(processNameFilter: null); + var processes = new List(processInfos.Length); + foreach (ProcessInfo processInfo in processInfos) { - ProcessInfo processInfo = processInfos[i]; - processes[i] = new Process(".", false, processInfo.ProcessId, processInfo); + if (processName is null || string.Equals(processInfo.ProcessName, processName, StringComparison.OrdinalIgnoreCase)) + { + processes.Add(new Process(".", false, processInfo.ProcessId, processInfo)); + } } - return processes; + return processes.ToArray(); } /// 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 a5432b374867fc..c8718ac38cd847 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 @@ -19,14 +19,15 @@ internal static partial class ProcessManager /// An array of process infos, one per found process. public static ProcessInfo[] GetProcessInfos(string? processNameFilter) { + Debug.Assert(processNameFilter is null, "Not used on Linux"); + // Iterate through all process IDs to load information about each process IEnumerable pids = EnumerateProcessIds(); ArrayBuilder processes = default; foreach (int pid in pids) { ProcessInfo? pi = CreateProcessInfo(pid); - if (pi != null && - (processNameFilter is null || string.Equals(pi.ProcessName, processNameFilter, StringComparison.OrdinalIgnoreCase))) + if (pi != null) { processes.Add(pi); } From 4e0557acbc9e67d196dc9b7b775e6994a4b6671d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Apr 2026 10:29:58 +0000 Subject: [PATCH 20/54] Fix GetProcessesByName empty string edge case: use IsNullOrEmpty instead of is null Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/5d1df815-608a-4338-9f99-fa2302e430f6 Co-authored-by: jkotas <6668460+jkotas@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 8734d7ef5ff6a9..80d4af8945f363 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -1076,7 +1076,7 @@ public static Process[] GetProcessesByName(string? processName) var processes = new List(processInfos.Length); foreach (ProcessInfo processInfo in processInfos) { - if (processName is null || string.Equals(processInfo.ProcessName, processName, StringComparison.OrdinalIgnoreCase)) + if (string.IsNullOrEmpty(processName) || string.Equals(processInfo.ProcessName, processName, StringComparison.OrdinalIgnoreCase)) { processes.Add(new Process(".", false, processInfo.ProcessId, processInfo)); } From f1fd1d6d5c379391c263754193f9a96e4b1a42fb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Apr 2026 17:06:51 +0000 Subject: [PATCH 21/54] Use HandleRemoteMachineSupport in GetProcessInfo and GetProcessIds on Unix Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/23e117ba-62e5-482f-82d9-6dd434af7836 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/ProcessManager.Unix.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs index b84edb0c4c78a8..177f822f8c6e6e 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs @@ -38,10 +38,7 @@ public static bool IsProcessRunning(int processId) /// The ProcessInfo for the process if it could be found; otherwise, null. public static ProcessInfo? GetProcessInfo(int processId, string machineName) { - if (IsRemoteMachine(machineName)) - { - throw new PlatformNotSupportedException(SR.RemoteMachinesNotSupported); - } + HandleRemoteMachineSupport(machineName); return CreateProcessInfo(processId); } @@ -53,10 +50,7 @@ public static bool IsProcessRunning(int processId) [SupportedOSPlatform("maccatalyst")] public static int[] GetProcessIds(string machineName) { - if (IsRemoteMachine(machineName)) - { - throw new PlatformNotSupportedException(SR.RemoteMachinesNotSupported); - } + HandleRemoteMachineSupport(machineName); return GetProcessIds(); } From 0a326b1bfddd793bc12f04cfdcf503948c250eb8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 2 Apr 2026 17:20:14 +0000 Subject: [PATCH 22/54] Remove redundant HandleRemoteMachineSupport call in Unix GetProcessInfo; delete dead GetProcessIds(string) overload Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/d7dea159-e4f7-463b-9b6a-2215ac2a5280 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../System/Diagnostics/ProcessManager.Unix.cs | 23 ++++--------------- 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs index 177f822f8c6e6e..551f9352f91c2b 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs @@ -34,25 +34,12 @@ public static bool IsProcessRunning(int processId) /// Gets the ProcessInfo for the specified process ID on the specified machine. /// The process ID. - /// The machine name. + /// Unused on Unix since remote machines are not supported. /// The ProcessInfo for the process if it could be found; otherwise, null. - public static ProcessInfo? GetProcessInfo(int processId, string machineName) - { - HandleRemoteMachineSupport(machineName); - return CreateProcessInfo(processId); - } - - /// Gets the IDs of all processes on the specified machine. - /// The machine to examine. - /// An array of process IDs from the specified machine. - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - [SupportedOSPlatform("maccatalyst")] - public static int[] GetProcessIds(string machineName) - { - HandleRemoteMachineSupport(machineName); - return GetProcessIds(); - } +#pragma warning disable IDE0060 + public static ProcessInfo? GetProcessInfo(int processId, string machineName) => + CreateProcessInfo(processId); +#pragma warning restore IDE0060 /// Gets the ID of a process from a handle to the process. /// The handle. From bb8955899f103c6de3ac7b6b57458129f12b872b Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 2 Apr 2026 15:54:21 -0700 Subject: [PATCH 23/54] Apply suggestion from @jkotas --- .../src/System/Diagnostics/ProcessManager.Unix.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs index eae5d28753476f..76a8f15a9280e0 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs @@ -71,8 +71,6 @@ internal static bool HandleRemoteMachineSupport(string machineName) /// Unused on Unix. /// Unused on Unix. /// An array of process infos, one per found process. - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] #pragma warning disable IDE0060 public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string machineName, bool isRemoteMachine) => GetProcessInfos(processNameFilter); From f50b6b1a6688c27b688ef3d3fd080a8fe0df71f4 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 2 Apr 2026 15:55:52 -0700 Subject: [PATCH 24/54] Apply suggestion from @jkotas --- .../src/System/Diagnostics/ProcessManager.Windows.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 658a1936808fe1..a6361195ecabae 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 @@ -201,7 +201,8 @@ public static int[] GetProcessIds(string machineName, bool isRemoteMachine) ProcessInfo[] infos = NtProcessManager.GetProcessInfos(machineName); int[] ids = new int[infos.Length]; - for (int i = 0; i < infos.Length; i++) ids[i] = infos[i].ProcessId; + for (int i = 0; i < infos.Length; i++) + ids[i] = infos[i].ProcessId; return ids; } From c4c37f95820f3139bc8fdd1ec2233a8d85961850 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 2 Apr 2026 18:11:48 -0700 Subject: [PATCH 25/54] Apply suggestion from @jkotas --- .../src/System/Diagnostics/ProcessManager.iOS.cs | 2 -- 1 file changed, 2 deletions(-) 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 c8958a18aeef1f..b4839ea9abc846 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 @@ -17,8 +17,6 @@ public static int[] GetProcessIds() /// Gets process infos for each process on the local machine. /// Optional process name to use as an inclusion filter. /// An array of process infos, one per found process. - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] public static ProcessInfo[] GetProcessInfos(string? processNameFilter) { throw new PlatformNotSupportedException(); From 3c9faba515d9e58c4c1bcc80c89ce6874e3e4924 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 2 Apr 2026 18:15:55 -0700 Subject: [PATCH 26/54] Apply suggestion from @jkotas --- .../src/System/Diagnostics/ProcessManager.Windows.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 a6361195ecabae..edc3d37bbf0807 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 @@ -199,7 +199,7 @@ public static int[] GetProcessIds(string machineName, bool isRemoteMachine) return GetProcessIds(); } - ProcessInfo[] infos = NtProcessManager.GetProcessInfos(machineName); + ProcessInfo[] infos = s_getRemoteProcessInfos!(machineName); int[] ids = new int[infos.Length]; for (int i = 0; i < infos.Length; i++) ids[i] = infos[i].ProcessId; From b0ed32b59809ffb0f88142c45c28706e57818fe3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 01:32:55 +0000 Subject: [PATCH 27/54] Pass processNameFilter to GetProcessInfos in GetProcessesByName; implement filter on Linux - GetProcessesByName(processName) now passes the name filter directly to ProcessManager.GetProcessInfos instead of fetching all processes and post-filtering. This avoids allocating ProcessInfo+ThreadInfo objects for non-matching processes during the NtQuerySystemInformation parse loop on Windows (and the equivalent on Unix). - ProcessManager.Linux.cs: remove Debug.Assert(processNameFilter is null), implement early filtering in CreateProcessInfo by reading the untruncated process name from /proc/pid/cmdline and skipping non-matching processes before the expensive thread enumeration in /proc/pid/task/. The obtained name is reused when building ProcessInfo to avoid reading cmdline twice. - BSD/SunOS already supported processNameFilter correctly. Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/ffa52b42-ce32-480c-bc2d-ca2f054b9cf1 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/Process.cs | 14 +++++----- .../Diagnostics/ProcessManager.Linux.cs | 27 ++++++++++++------- 2 files changed, 24 insertions(+), 17 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 25047c4bc5877a..faa2c5780c7ce2 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -1072,16 +1072,14 @@ public static Process GetProcessById(int processId) public static Process[] GetProcessesByName(string? processName) { // Avoid calling GetProcessesByName(processName, ".") so that remote machine code is not included when only local machine support is needed. - ProcessInfo[] processInfos = ProcessManager.GetProcessInfos(processNameFilter: null); - var processes = new List(processInfos.Length); - foreach (ProcessInfo processInfo in processInfos) + // Normalize empty processName to null so that GetProcessInfos treats it as "no filter". + ProcessInfo[] processInfos = ProcessManager.GetProcessInfos(processNameFilter: string.IsNullOrEmpty(processName) ? null : processName); + Process[] processes = new Process[processInfos.Length]; + for (int i = 0; i < processInfos.Length; i++) { - if (string.IsNullOrEmpty(processName) || string.Equals(processInfo.ProcessName, processName, StringComparison.OrdinalIgnoreCase)) - { - processes.Add(new Process(".", false, processInfo.ProcessId, processInfo)); - } + processes[i] = new Process(".", false, processInfos[i].ProcessId, processInfos[i]); } - return processes.ToArray(); + return processes; } /// 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 c8718ac38cd847..9a5954079ebb62 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 @@ -19,14 +19,12 @@ internal static partial class ProcessManager /// An array of process infos, one per found process. public static ProcessInfo[] GetProcessInfos(string? processNameFilter) { - Debug.Assert(processNameFilter is null, "Not used on Linux"); - // Iterate through all process IDs to load information about each process IEnumerable pids = EnumerateProcessIds(); ArrayBuilder processes = default; foreach (int pid in pids) { - ProcessInfo? pi = CreateProcessInfo(pid); + ProcessInfo? pi = CreateProcessInfo(pid, processNameFilter); if (pi != null) { processes.Add(pi); @@ -71,15 +69,26 @@ internal static ProcessModuleCollection GetModules(int processId) /// /// Creates a ProcessInfo from the specified process ID. /// - internal static ProcessInfo? CreateProcessInfo(int pid) + internal static ProcessInfo? CreateProcessInfo(int pid, string? processNameFilter = null) { - if (TryGetProcPid(pid, out Interop.procfs.ProcPid procPid) && - Interop.procfs.TryReadStatFile(procPid, out Interop.procfs.ParsedStat stat)) + if (!TryGetProcPid(pid, out Interop.procfs.ProcPid procPid) || + !Interop.procfs.TryReadStatFile(procPid, out Interop.procfs.ParsedStat stat)) { - Interop.procfs.TryReadStatusFile(procPid, out Interop.procfs.ParsedStatus status); - return CreateProcessInfo(procPid, ref stat, ref status); + return null; } - return null; + + string? processName = null; + if (!string.IsNullOrEmpty(processNameFilter)) + { + processName = Process.GetUntruncatedProcessName(procPid, ref stat) ?? string.Empty; + if (!string.Equals(processName, processNameFilter, StringComparison.OrdinalIgnoreCase)) + { + return null; + } + } + + Interop.procfs.TryReadStatusFile(procPid, out Interop.procfs.ParsedStatus status); + return CreateProcessInfo(procPid, ref stat, ref status, processName: processName); } /// From 185de4c64189dcc7c38ae8c990ddcdc146f5c443 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 04:28:37 +0000 Subject: [PATCH 28/54] Pass isRemoteMachine as argument to GetProcessInfo and GetProcessName Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/9165bdb5-be99-49a3-a9a1-5ba9cbda68f1 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/Process.Windows.cs | 2 +- .../src/System/Diagnostics/Process.cs | 4 ++-- .../src/System/Diagnostics/ProcessManager.Unix.cs | 3 ++- .../src/System/Diagnostics/ProcessManager.Windows.cs | 10 ++++++---- 4 files changed, 11 insertions(+), 8 deletions(-) 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 fe8bef22c91a88..80eca7533fda9a 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 @@ -551,7 +551,7 @@ public string ProcessName { // Ensure that the process is not yet exited EnsureState(State.HaveNonExitedId); - _processName = ProcessManager.GetProcessName(_processId, _machineName); + _processName = ProcessManager.GetProcessName(_processId, _machineName, _isRemoteMachine); // 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) 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 faa2c5780c7ce2..2a9607472415b8 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -979,7 +979,7 @@ private void EnsureState(State state) { EnsureState(State.HaveNonExitedId); } - _processInfo = ProcessManager.GetProcessInfo(_processId, _machineName); + _processInfo = ProcessManager.GetProcessInfo(_processId, _machineName, _isRemoteMachine); if (_processInfo == null) { throw new InvalidOperationException(SR.NoProcessInfo); @@ -1520,7 +1520,7 @@ public override string ToString() { if (Associated) { - _processInfo ??= ProcessManager.GetProcessInfo(_processId, _machineName); + _processInfo ??= ProcessManager.GetProcessInfo(_processId, _machineName, _isRemoteMachine); if (_processInfo is not null) { string processName = _processInfo.ProcessName; diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs index 76a8f15a9280e0..1903e7776763cf 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs @@ -35,9 +35,10 @@ public static bool IsProcessRunning(int processId) /// Gets the ProcessInfo for the specified process ID on the specified machine. /// The process ID. /// Unused on Unix since remote machines are not supported. + /// Unused on Unix since remote machines are not supported. /// The ProcessInfo for the process if it could be found; otherwise, null. #pragma warning disable IDE0060 - public static ProcessInfo? GetProcessInfo(int processId, string machineName) => + public static ProcessInfo? GetProcessInfo(int processId, string machineName, bool isRemoteMachine) => CreateProcessInfo(processId); #pragma warning restore IDE0060 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 edc3d37bbf0807..a1468d06414149 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 @@ -124,10 +124,11 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string ma /// Gets the ProcessInfo for the specified process ID on the specified machine. /// The process ID. /// The machine name. + /// Whether the machine is remote; avoids a redundant call. /// The ProcessInfo for the process if it could be found; otherwise, null. - public static ProcessInfo? GetProcessInfo(int processId, string machineName) + public static ProcessInfo? GetProcessInfo(int processId, string machineName, bool isRemoteMachine) { - if (IsRemoteMachine(machineName)) + if (isRemoteMachine) { // remote case: we take the hit of looping through all results ProcessInfo[] processInfos = s_getRemoteProcessInfos!(machineName); @@ -155,10 +156,11 @@ public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string ma /// Gets the process name for the specified process ID on the specified machine. /// The process ID. /// The machine name. + /// Whether the machine is remote; avoids a redundant call. /// The process name for the process if it could be found; otherwise, null. - public static string? GetProcessName(int processId, string machineName) + public static string? GetProcessName(int processId, string machineName, bool isRemoteMachine) { - if (IsRemoteMachine(machineName)) + if (isRemoteMachine) { // remote case: we take the hit of looping through all results ProcessInfo[] processInfos = s_getRemoteProcessInfos!(machineName); From aa5e73fad7a9282c6d2fdb7da9540e97feff6cc5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 04:40:11 +0000 Subject: [PATCH 29/54] Remove redundant null-coalescing operator in ProcessManager.Linux.cs Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/0819b7d7-ebf3-41f3-ae1b-f82dc6560090 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/ProcessManager.Linux.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 9a5954079ebb62..795d14281aa82c 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 @@ -80,7 +80,7 @@ internal static ProcessModuleCollection GetModules(int processId) string? processName = null; if (!string.IsNullOrEmpty(processNameFilter)) { - processName = Process.GetUntruncatedProcessName(procPid, ref stat) ?? string.Empty; + processName = Process.GetUntruncatedProcessName(procPid, ref stat); if (!string.Equals(processName, processNameFilter, StringComparison.OrdinalIgnoreCase)) { return null; From 36c5e939c637e6a41f316d073fe7961a3ca80fd8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 05:30:36 +0000 Subject: [PATCH 30/54] Move GetProcessesByName(string, string) to OS-neutral Process.cs Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/05acbc96-3fdb-464a-8b80-b5aa299444fe Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/Process.BSD.cs | 28 --------------- .../src/System/Diagnostics/Process.Linux.cs | 34 ------------------- .../src/System/Diagnostics/Process.Windows.cs | 23 ------------- .../src/System/Diagnostics/Process.cs | 20 +++++++++++ .../src/System/Diagnostics/Process.iOS.cs | 12 ------- 5 files changed, 20 insertions(+), 97 deletions(-) diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.BSD.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.BSD.cs index 238c86d8a70c1f..85caf5c0d71e3d 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.BSD.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.BSD.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Generic; using System.ComponentModel; using System.Runtime.Versioning; @@ -9,33 +8,6 @@ namespace System.Diagnostics { public partial class Process { - /// - /// Creates an array of components that are associated with process resources on a - /// remote computer. These process resources share the specified process name. - /// - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - [SupportedOSPlatform("maccatalyst")] - public static Process[] GetProcessesByName(string? processName, string machineName) - { - ProcessManager.HandleRemoteMachineSupport(machineName); - - int[] procIds = ProcessManager.GetProcessIds(); - var processes = new ArrayBuilder(string.IsNullOrEmpty(processName) ? procIds.Length : 0); - - // Iterate through all process IDs to load information about each process - foreach (int pid in procIds) - { - ProcessInfo? processInfo = ProcessManager.CreateProcessInfo(pid, processName); - if (processInfo != null) - { - processes.Add(new Process(machineName, isRemoteMachine: false, pid, processInfo)); - } - } - - return processes.ToArray(); - } - /// /// Gets or sets which processors the threads in this process can be scheduled to run on. /// diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs index 8e4bc989f7de8c..74715a03aaa9e6 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Linux.cs @@ -3,9 +3,7 @@ using System; using System.Buffers; -using System.Collections.Generic; using System.ComponentModel; -using System.Globalization; using System.IO; using System.Runtime.Versioning; using System.Text; @@ -15,38 +13,6 @@ namespace System.Diagnostics { public partial class Process : IDisposable { - /// - /// Creates an array of components that are associated with process resources on a - /// remote computer. These process resources share the specified process name. - /// - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - [SupportedOSPlatform("maccatalyst")] - public static Process[] GetProcessesByName(string? processName, string machineName) - { - ProcessManager.HandleRemoteMachineSupport(machineName); - - processName ??= ""; - - ArrayBuilder processes = default; - foreach (int pid in ProcessManager.EnumerateProcessIds()) - { - if (ProcessManager.TryGetProcPid(pid, out Interop.procfs.ProcPid procPid) && - Interop.procfs.TryReadStatFile(procPid, out Interop.procfs.ParsedStat parsedStat)) - { - string actualProcessName = GetUntruncatedProcessName(procPid, ref parsedStat); - if ((processName == "" || string.Equals(processName, actualProcessName, StringComparison.OrdinalIgnoreCase)) && - Interop.procfs.TryReadStatusFile(procPid, out Interop.procfs.ParsedStatus parsedStatus)) - { - ProcessInfo processInfo = ProcessManager.CreateProcessInfo(procPid, ref parsedStat, ref parsedStatus, actualProcessName); - processes.Add(new Process(machineName, isRemoteMachine: false, pid, processInfo)); - } - } - } - - return processes.ToArray(); - } - /// Gets the amount of time the process has spent running code inside the operating system core. [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] 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 80eca7533fda9a..cb12ddfb0b4c2c 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 @@ -27,29 +27,6 @@ public partial class Process : IDisposable private bool _signaled; - /// - /// Creates an array of components that are associated with process resources on a - /// remote computer. These process resources share the specified process name. - /// - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - [SupportedOSPlatform("maccatalyst")] - public static Process[] GetProcessesByName(string? processName, string machineName) - { - bool isRemoteMachine = ProcessManager.HandleRemoteMachineSupport(machineName); - - ProcessInfo[] processInfos = ProcessManager.GetProcessInfos(processName, machineName, isRemoteMachine); - Process[] processes = new Process[processInfos.Length]; - - for (int i = 0; i < processInfos.Length; i++) - { - ProcessInfo processInfo = processInfos[i]; - processes[i] = new Process(machineName, isRemoteMachine, processInfo.ProcessId, processInfo); - } - - return processes; - } - [CLSCompliant(false)] [SupportedOSPlatform("windows")] public static Process? Start(string fileName, string userName, SecureString password, string domain) 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 2a9607472415b8..067888751aec74 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -1082,6 +1082,26 @@ public static Process[] GetProcessesByName(string? processName) return processes; } + /// + /// Creates an array of components that are associated with process resources on a + /// remote computer. These process resources share the specified process name. + /// + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [SupportedOSPlatform("maccatalyst")] + public static Process[] GetProcessesByName(string? processName, string machineName) + { + bool isRemoteMachine = ProcessManager.HandleRemoteMachineSupport(machineName); + ProcessInfo[] processInfos = ProcessManager.GetProcessInfos(processName, machineName, isRemoteMachine); + Process[] processes = new Process[processInfos.Length]; + for (int i = 0; i < processInfos.Length; i++) + { + ProcessInfo processInfo = processInfos[i]; + processes[i] = new Process(machineName, isRemoteMachine, processInfo.ProcessId, processInfo); + } + return processes; + } + /// /// /// Creates a new diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.iOS.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.iOS.cs index 49519cfc243b29..2a5d3ddb785291 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.iOS.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.iOS.cs @@ -18,18 +18,6 @@ public void Kill(bool entireProcessTree) throw new PlatformNotSupportedException(); } - /// - /// Creates an array of components that are associated with process resources on a - /// remote computer. These process resources share the specified process name. - /// - [UnsupportedOSPlatform("ios")] - [UnsupportedOSPlatform("tvos")] - [SupportedOSPlatform("maccatalyst")] - public static Process[] GetProcessesByName(string? processName, string machineName) - { - throw new PlatformNotSupportedException(); - } - /// Gets the amount of time the process has spent running code inside the operating system core. [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] From a1a792c5c9fb5eacf81466e7dbff1de2f0d5e571 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 05:56:31 +0000 Subject: [PATCH 31/54] Change GetProcessInfos to use ref ArrayBuilder to save array allocations Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/3cc9f25d-58ae-4f40-966f-7eb24cc500c9 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/Process.cs | 39 ++++++++++++------- .../System/Diagnostics/ProcessManager.BSD.cs | 9 ++--- .../Diagnostics/ProcessManager.Linux.cs | 9 ++--- .../Diagnostics/ProcessManager.SunOS.cs | 9 ++--- .../System/Diagnostics/ProcessManager.Unix.cs | 6 +-- .../Diagnostics/ProcessManager.Windows.cs | 29 +++++++------- .../System/Diagnostics/ProcessManager.iOS.cs | 5 ++- 7 files changed, 54 insertions(+), 52 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 067888751aec74..53e5ef32e3b4b6 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -1073,11 +1073,15 @@ public static Process[] GetProcessesByName(string? processName) { // Avoid calling GetProcessesByName(processName, ".") so that remote machine code is not included when only local machine support is needed. // Normalize empty processName to null so that GetProcessInfos treats it as "no filter". - ProcessInfo[] processInfos = ProcessManager.GetProcessInfos(processNameFilter: string.IsNullOrEmpty(processName) ? null : processName); - Process[] processes = new Process[processInfos.Length]; - for (int i = 0; i < processInfos.Length; i++) + ArrayBuilder processInfos = default; + ProcessManager.GetProcessInfos(ref processInfos, processNameFilter: string.IsNullOrEmpty(processName) ? null : processName); + if (processInfos.Count == 0) + return []; + Process[] processes = new Process[processInfos.Count]; + for (int i = 0; i < processes.Length; i++) { - processes[i] = new Process(".", false, processInfos[i].ProcessId, processInfos[i]); + ProcessInfo processInfo = processInfos[i]; + processes[i] = new Process(".", false, processInfo.ProcessId, processInfo); } return processes; } @@ -1092,9 +1096,12 @@ public static Process[] GetProcessesByName(string? processName) public static Process[] GetProcessesByName(string? processName, string machineName) { bool isRemoteMachine = ProcessManager.HandleRemoteMachineSupport(machineName); - ProcessInfo[] processInfos = ProcessManager.GetProcessInfos(processName, machineName, isRemoteMachine); - Process[] processes = new Process[processInfos.Length]; - for (int i = 0; i < processInfos.Length; i++) + ArrayBuilder processInfos = default; + ProcessManager.GetProcessInfos(ref processInfos, processName, machineName, isRemoteMachine); + if (processInfos.Count == 0) + return []; + Process[] processes = new Process[processInfos.Count]; + for (int i = 0; i < processes.Length; i++) { ProcessInfo processInfo = processInfos[i]; processes[i] = new Process(machineName, isRemoteMachine, processInfo.ProcessId, processInfo); @@ -1114,9 +1121,12 @@ public static Process[] GetProcessesByName(string? processName, string machineNa public static Process[] GetProcesses() { // Avoid calling GetProcesses(".") so that remote machine code is not included when only local machine support is needed. - ProcessInfo[] processInfos = ProcessManager.GetProcessInfos(processNameFilter: null); - Process[] processes = new Process[processInfos.Length]; - for (int i = 0; i < processInfos.Length; i++) + ArrayBuilder processInfos = default; + ProcessManager.GetProcessInfos(ref processInfos, processNameFilter: null); + if (processInfos.Count == 0) + return []; + Process[] processes = new Process[processInfos.Count]; + for (int i = 0; i < processes.Length; i++) { ProcessInfo processInfo = processInfos[i]; processes[i] = new Process(".", false, processInfo.ProcessId, processInfo); @@ -1137,9 +1147,12 @@ public static Process[] GetProcesses() public static Process[] GetProcesses(string machineName) { bool isRemoteMachine = ProcessManager.HandleRemoteMachineSupport(machineName); - ProcessInfo[] processInfos = ProcessManager.GetProcessInfos(processNameFilter: null, machineName, isRemoteMachine); - Process[] processes = new Process[processInfos.Length]; - for (int i = 0; i < processInfos.Length; i++) + ArrayBuilder processInfos = default; + ProcessManager.GetProcessInfos(ref processInfos, processNameFilter: null, machineName, isRemoteMachine); + if (processInfos.Count == 0) + return []; + Process[] processes = new Process[processInfos.Count]; + for (int i = 0; i < processes.Length; i++) { ProcessInfo processInfo = processInfos[i]; processes[i] = new Process(machineName, isRemoteMachine, processInfo.ProcessId, processInfo); diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.BSD.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.BSD.cs index bf7af99799b19d..ec2a2e5c6df2c5 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.BSD.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.BSD.cs @@ -10,23 +10,20 @@ namespace System.Diagnostics internal static partial class ProcessManager { /// Gets process infos for each process on the local machine. + /// The builder to add found process infos to. /// Optional process name to use as an inclusion filter. - /// An array of process infos, one per found process. - public static ProcessInfo[] GetProcessInfos(string? processNameFilter) + public static void GetProcessInfos(ref ArrayBuilder builder, string? processNameFilter) { // Iterate through all process IDs to load information about each process int[] pids = GetProcessIds(); - var processes = new ArrayBuilder(processNameFilter is null ? pids.Length : 0); foreach (int pid in pids) { ProcessInfo? pi = CreateProcessInfo(pid, processNameFilter); if (pi != null) { - processes.Add(pi); + builder.Add(pi); } } - - return processes.ToArray(); } /// Gets an array of module infos for the specified process. 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 795d14281aa82c..4735b3b548e5d3 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 @@ -15,23 +15,20 @@ internal static partial class ProcessManager public static int[] GetProcessIds() => new List(EnumerateProcessIds()).ToArray(); /// Gets process infos for each process on the local machine. + /// The builder to add found process infos to. /// Optional process name to use as an inclusion filter. - /// An array of process infos, one per found process. - public static ProcessInfo[] GetProcessInfos(string? processNameFilter) + public static void GetProcessInfos(ref ArrayBuilder builder, string? processNameFilter) { // Iterate through all process IDs to load information about each process IEnumerable pids = EnumerateProcessIds(); - ArrayBuilder processes = default; foreach (int pid in pids) { ProcessInfo? pi = CreateProcessInfo(pid, processNameFilter); if (pi != null) { - processes.Add(pi); + builder.Add(pi); } } - - return processes.ToArray(); } /// Gets an array of module infos for the specified process. 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 458532e2093335..67383bd563db08 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 @@ -18,23 +18,20 @@ public static int[] GetProcessIds() } /// Gets process infos for each process on the local machine. + /// The builder to add found process infos to. /// Optional process name to use as an inclusion filter. - /// An array of process infos, one per found process. - public static ProcessInfo[] GetProcessInfos(string? processNameFilter) + public static void GetProcessInfos(ref ArrayBuilder builder, string? processNameFilter) { // Iterate through all process IDs to load information about each process IEnumerable pids = EnumerateProcessIds(); - ArrayBuilder processes = default; foreach (int pid in pids) { ProcessInfo? pi = CreateProcessInfo(pid, processNameFilter); if (pi != null) { - processes.Add(pi); + builder.Add(pi); } } - - return processes.ToArray(); } /// Gets an array of module infos for the specified process. diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs index 1903e7776763cf..42a6e32cb1253b 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs @@ -68,13 +68,13 @@ internal static bool HandleRemoteMachineSupport(string machineName) /// Gets process infos for each process on the specified machine. /// On Unix, and are unused since remote machines are not supported. + /// The builder to add found process infos to. /// Optional process name to use as an inclusion filter. /// Unused on Unix. /// Unused on Unix. - /// An array of process infos, one per found process. #pragma warning disable IDE0060 - public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string machineName, bool isRemoteMachine) => - GetProcessInfos(processNameFilter); + public static void GetProcessInfos(ref ArrayBuilder builder, string? processNameFilter, string machineName, bool isRemoteMachine) => + GetProcessInfos(ref builder, processNameFilter); #pragma warning restore IDE0060 } 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 a1468d06414149..92b54345c42334 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 @@ -40,10 +40,14 @@ internal static bool HandleRemoteMachineSupport(string machineName) } /// Gets process infos for each process on the local machine. + /// The builder to add found process infos to. /// Optional process name to use as an inclusion filter. - /// An array of process infos, one per found process. - internal static ProcessInfo[] GetProcessInfos(string? processNameFilter) => - NtProcessInfoHelper.GetProcessInfos(processNameFilter: processNameFilter); + internal static void GetProcessInfos(ref ArrayBuilder builder, string? processNameFilter) + { + ProcessInfo[] processInfos = NtProcessInfoHelper.GetProcessInfos(processNameFilter: processNameFilter); + foreach (ProcessInfo pi in processInfos) + builder.Add(pi); + } /// Gets whether the process with the specified ID is currently running. /// The process ID. @@ -92,33 +96,26 @@ public static bool IsProcessRunning(int processId, string machineName, bool isRe } /// Gets process infos for each process on the specified machine. + /// The builder to add found process infos to. /// Optional process name to use as an inclusion filter. /// The target machine. /// Whether the machine is remote; avoids a redundant call. - /// An array of process infos, one per found process. - public static ProcessInfo[] GetProcessInfos(string? processNameFilter, string machineName, bool isRemoteMachine) + public static void GetProcessInfos(ref ArrayBuilder builder, string? processNameFilter, string machineName, bool isRemoteMachine) { if (!isRemoteMachine) { - return GetProcessInfos(processNameFilter); + GetProcessInfos(ref builder, processNameFilter); + return; } ProcessInfo[] processInfos = s_getRemoteProcessInfos!(machineName); - if (string.IsNullOrEmpty(processNameFilter)) - { - return processInfos; - } - - ArrayBuilder results = default; foreach (ProcessInfo pi in processInfos) { - if (string.Equals(processNameFilter, pi.ProcessName, StringComparison.OrdinalIgnoreCase)) + if (string.IsNullOrEmpty(processNameFilter) || string.Equals(processNameFilter, pi.ProcessName, StringComparison.OrdinalIgnoreCase)) { - results.Add(pi); + builder.Add(pi); } } - - return results.ToArray(); } /// Gets the ProcessInfo for the specified process ID on 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 b4839ea9abc846..da7d7a74363c57 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 @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; using System.Runtime.Versioning; namespace System.Diagnostics @@ -15,9 +16,9 @@ public static int[] GetProcessIds() } /// Gets process infos for each process on the local machine. + /// The builder to add found process infos to. /// Optional process name to use as an inclusion filter. - /// An array of process infos, one per found process. - public static ProcessInfo[] GetProcessInfos(string? processNameFilter) + public static void GetProcessInfos(ref ArrayBuilder builder, string? processNameFilter) { throw new PlatformNotSupportedException(); } From 61d89cc6cde24d9d4ddfb47eeb05ece2439301fc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 06:10:00 +0000 Subject: [PATCH 32/54] Delete GetProcessIdFromHandle; use SafeProcessHandle.ProcessId; normalize processName in both GetProcessesByName overloads Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/d1de65e4-b189-44f8-8cb9-42a5dbb8e6b5 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/Process.cs | 4 ++-- .../src/System/Diagnostics/ProcessManager.Unix.cs | 8 -------- .../System/Diagnostics/ProcessManager.Windows.cs | 13 ------------- 3 files changed, 2 insertions(+), 23 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 53e5ef32e3b4b6..d3abe4f07c3b9b 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -952,7 +952,7 @@ private void EnsureState(State state) { if (_haveProcessHandle) { - SetProcessId(ProcessManager.GetProcessIdFromHandle(_processHandle!)); + SetProcessId(_processHandle!.ProcessId); } else { @@ -1097,7 +1097,7 @@ public static Process[] GetProcessesByName(string? processName, string machineNa { bool isRemoteMachine = ProcessManager.HandleRemoteMachineSupport(machineName); ArrayBuilder processInfos = default; - ProcessManager.GetProcessInfos(ref processInfos, processName, machineName, isRemoteMachine); + ProcessManager.GetProcessInfos(ref processInfos, string.IsNullOrEmpty(processName) ? null : processName, machineName, isRemoteMachine); if (processInfos.Count == 0) return []; Process[] processes = new Process[processInfos.Count]; diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs index 42a6e32cb1253b..c181b8ccabbe3d 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs @@ -42,14 +42,6 @@ public static bool IsProcessRunning(int processId) CreateProcessInfo(processId); #pragma warning restore IDE0060 - /// Gets the ID of a process from a handle to the process. - /// The handle. - /// The process ID. - public static int GetProcessIdFromHandle(SafeProcessHandle processHandle) - { - return processHandle.ProcessId; - } - private static bool IsRemoteMachineCore(string machineName) { return 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 92b54345c42334..d278845caa0d60 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 @@ -211,14 +211,6 @@ public static int[] GetProcessIds() return NtProcessManager.GetProcessIds(); } - /// Gets the ID of a process from a handle to the process. - /// The handle. - /// The process ID. - public static int GetProcessIdFromHandle(SafeProcessHandle processHandle) - { - return NtProcessManager.GetProcessIdFromHandle(processHandle); - } - /// Gets an array of module infos for the specified process. /// The ID of the process whose modules should be enumerated. /// The array of modules. @@ -488,11 +480,6 @@ public static ProcessModuleCollection GetModules(int processId) return modules.Count == 0 ? null : modules[0]; } - public static int GetProcessIdFromHandle(SafeProcessHandle processHandle) - { - return Interop.Kernel32.GetProcessId(processHandle); - } - public static ProcessInfo[] GetProcessInfos(string machineName) { try From af23f50fd637e67e9ceadb81f10efd638d443047 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 2 Apr 2026 23:24:04 -0700 Subject: [PATCH 33/54] Apply suggestion from @jkotas --- .../System.Diagnostics.Process/src/System/Diagnostics/Process.cs | 1 + 1 file changed, 1 insertion(+) 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 d3abe4f07c3b9b..ea550fcdc228ef 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -1097,6 +1097,7 @@ public static Process[] GetProcessesByName(string? processName, string machineNa { bool isRemoteMachine = ProcessManager.HandleRemoteMachineSupport(machineName); ArrayBuilder processInfos = default; + // Normalize empty processName to null so that GetProcessInfos treats it as "no filter". ProcessManager.GetProcessInfos(ref processInfos, string.IsNullOrEmpty(processName) ? null : processName, machineName, isRemoteMachine); if (processInfos.Count == 0) return []; From 4370688828a6dfabddc41cc45491722295c93f5e Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 2 Apr 2026 23:24:15 -0700 Subject: [PATCH 34/54] Apply suggestion from @jkotas --- .../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 ea550fcdc228ef..37d1a938ddd663 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -1072,8 +1072,8 @@ public static Process GetProcessById(int processId) public static Process[] GetProcessesByName(string? processName) { // Avoid calling GetProcessesByName(processName, ".") so that remote machine code is not included when only local machine support is needed. - // Normalize empty processName to null so that GetProcessInfos treats it as "no filter". ArrayBuilder processInfos = default; + // Normalize empty processName to null so that GetProcessInfos treats it as "no filter". ProcessManager.GetProcessInfos(ref processInfos, processNameFilter: string.IsNullOrEmpty(processName) ? null : processName); if (processInfos.Count == 0) return []; From 3574d01261566c1ec21690667a3cb60968c9d220 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 06:40:58 +0000 Subject: [PATCH 35/54] Address review feedback: BSD pre-alloc, Linux null check, Windows delegate refactor for ArrayBuilder Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/a1187473-9da1-4744-b3f6-54ec997f99f5 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../System/Diagnostics/ProcessManager.BSD.cs | 4 + .../Diagnostics/ProcessManager.Linux.cs | 2 +- .../Diagnostics/ProcessManager.Windows.cs | 74 +++++++++---------- 3 files changed, 39 insertions(+), 41 deletions(-) diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.BSD.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.BSD.cs index ec2a2e5c6df2c5..38ec76e062597f 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.BSD.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.BSD.cs @@ -16,6 +16,10 @@ public static void GetProcessInfos(ref ArrayBuilder builder, string { // Iterate through all process IDs to load information about each process int[] pids = GetProcessIds(); + if (processNameFilter is not null) + { + builder = new ArrayBuilder(pids.Length); + } foreach (int pid in pids) { ProcessInfo? pi = CreateProcessInfo(pid, processNameFilter); 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 4735b3b548e5d3..8ade1202f94ec0 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 @@ -75,7 +75,7 @@ internal static ProcessModuleCollection GetModules(int processId) } string? processName = null; - if (!string.IsNullOrEmpty(processNameFilter)) + if (processNameFilter != null) { processName = Process.GetUntruncatedProcessName(procPid, ref stat); if (!string.Equals(processName, processNameFilter, StringComparison.OrdinalIgnoreCase)) 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 d278845caa0d60..20f796d07be36a 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 @@ -21,7 +21,8 @@ internal static partial class ProcessManager // Allows PerformanceCounterLib (and its dependencies) to be trimmed when remote machine // support is not used. s_getRemoteProcessInfos is only assigned in HandleRemoteMachineSupport, // which is only called from public APIs that accept a remote machine name. - private static Func? s_getRemoteProcessInfos; + private delegate void GetRemoteProcessInfosDelegate(ref ArrayBuilder builder, string? processNameFilter, string machineName); + private static GetRemoteProcessInfosDelegate? s_getRemoteProcessInfos; /// /// Initializes remote machine support if necessary. This method should be called in all public @@ -108,14 +109,7 @@ public static void GetProcessInfos(ref ArrayBuilder builder, string return; } - ProcessInfo[] processInfos = s_getRemoteProcessInfos!(machineName); - foreach (ProcessInfo pi in processInfos) - { - if (string.IsNullOrEmpty(processNameFilter) || string.Equals(processNameFilter, pi.ProcessName, StringComparison.OrdinalIgnoreCase)) - { - builder.Add(pi); - } - } + s_getRemoteProcessInfos!(ref builder, processNameFilter, machineName); } /// Gets the ProcessInfo for the specified process ID on the specified machine. @@ -128,13 +122,12 @@ public static void GetProcessInfos(ref ArrayBuilder builder, string if (isRemoteMachine) { // remote case: we take the hit of looping through all results - ProcessInfo[] processInfos = s_getRemoteProcessInfos!(machineName); - foreach (ProcessInfo processInfo in processInfos) + ArrayBuilder builder = default; + s_getRemoteProcessInfos!(ref builder, processNameFilter: null, machineName); + for (int i = 0; i < builder.Count; i++) { - if (processInfo.ProcessId == processId) - { - return processInfo; - } + if (builder[i].ProcessId == processId) + return builder[i]; } } else @@ -160,13 +153,12 @@ public static void GetProcessInfos(ref ArrayBuilder builder, string if (isRemoteMachine) { // remote case: we take the hit of looping through all results - ProcessInfo[] processInfos = s_getRemoteProcessInfos!(machineName); - foreach (ProcessInfo processInfo in processInfos) + ArrayBuilder builder = default; + s_getRemoteProcessInfos!(ref builder, processNameFilter: null, machineName); + for (int i = 0; i < builder.Count; i++) { - if (processInfo.ProcessId == processId) - { - return processInfo.ProcessName; - } + if (builder[i].ProcessId == processId) + return builder[i].ProcessName; } } else @@ -198,10 +190,11 @@ public static int[] GetProcessIds(string machineName, bool isRemoteMachine) return GetProcessIds(); } - ProcessInfo[] infos = s_getRemoteProcessInfos!(machineName); - int[] ids = new int[infos.Length]; - for (int i = 0; i < infos.Length; i++) - ids[i] = infos[i].ProcessId; + ArrayBuilder builder = default; + s_getRemoteProcessInfos!(ref builder, processNameFilter: null, machineName); + int[] ids = new int[builder.Count]; + for (int i = 0; i < ids.Length; i++) + ids[i] = builder[i].ProcessId; return ids; } @@ -480,32 +473,32 @@ public static ProcessModuleCollection GetModules(int processId) return modules.Count == 0 ? null : modules[0]; } - public static ProcessInfo[] GetProcessInfos(string machineName) + public static void GetProcessInfos(ref ArrayBuilder builder, string? processNameFilter, string machineName) { + PerformanceCounterLib library; try { // We don't want to call library.Close() here because that would cause us to unload all of the perflibs. // On the next call to GetProcessInfos, we'd have to load them all up again, which is SLOW! - PerformanceCounterLib library = PerformanceCounterLib.GetPerformanceCounterLib(machineName, new CultureInfo("en")); - return GetProcessInfos(library); + library = PerformanceCounterLib.GetPerformanceCounterLib(machineName, new CultureInfo("en")); } catch (Exception e) { throw new InvalidOperationException(SR.CouldntConnectToRemoteMachine, e); } + GetProcessInfos(library, ref builder, processNameFilter); } - private static ProcessInfo[] GetProcessInfos(PerformanceCounterLib library) + private static void GetProcessInfos(PerformanceCounterLib library, ref ArrayBuilder builder, string? processNameFilter) { - ProcessInfo[] processInfos; - int retryCount = 5; + int totalProcessCount; do { try { byte[]? dataPtr = library.GetPerformanceData(PerfCounterQueryString); - processInfos = GetProcessInfos(library, ProcessPerfCounterId, ThreadPerfCounterId, dataPtr); + totalProcessCount = GetProcessInfos(library, ProcessPerfCounterId, ThreadPerfCounterId, dataPtr, ref builder, processNameFilter); } catch (Exception e) { @@ -514,15 +507,13 @@ private static ProcessInfo[] GetProcessInfos(PerformanceCounterLib library) --retryCount; } - while (processInfos.Length == 0 && retryCount != 0); + while (totalProcessCount == 0 && retryCount != 0); - if (processInfos.Length == 0) + if (totalProcessCount == 0) throw new InvalidOperationException(SR.ProcessDisabled); - - return processInfos; } - private static ProcessInfo[] GetProcessInfos(PerformanceCounterLib library, int processIndex, int threadIndex, ReadOnlySpan data) + private static int GetProcessInfos(PerformanceCounterLib library, int processIndex, int threadIndex, ReadOnlySpan data, ref ArrayBuilder builder, string? processNameFilter) { Dictionary processInfos = new Dictionary(); List threadInfos = new List(); @@ -643,9 +634,12 @@ private static ProcessInfo[] GetProcessInfos(PerformanceCounterLib library, int } } - ProcessInfo[] temp = new ProcessInfo[processInfos.Values.Count]; - processInfos.Values.CopyTo(temp, 0); - return temp; + foreach (KeyValuePair entry in processInfos) + { + if (processNameFilter is null || string.Equals(processNameFilter, entry.Value.ProcessName, StringComparison.OrdinalIgnoreCase)) + builder.Add(entry.Value); + } + return processInfos.Count; } private static unsafe ThreadInfo GetThreadInfo(ReadOnlySpan instanceData, PERF_COUNTER_DEFINITION[] counters) From a59bbd0dab1297193c0cb162c39d76f97d1b56f9 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 2 Apr 2026 23:42:08 -0700 Subject: [PATCH 36/54] Apply suggestion from @jkotas --- .../src/System/Diagnostics/ProcessManager.BSD.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.BSD.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.BSD.cs index 38ec76e062597f..4429513ff9317d 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.BSD.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.BSD.cs @@ -16,7 +16,7 @@ public static void GetProcessInfos(ref ArrayBuilder builder, string { // Iterate through all process IDs to load information about each process int[] pids = GetProcessIds(); - if (processNameFilter is not null) + if (processNameFilter is null) { builder = new ArrayBuilder(pids.Length); } From 7ca415439d3fb024d26b820f206a5828b9399f66 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 06:52:55 +0000 Subject: [PATCH 37/54] Remove dead GetProcessIds() from ProcessManager.Linux.cs and ProcessManager.SunOS.cs Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/efb1c868-78f1-409b-9c4b-accbb1a49c84 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/ProcessManager.Linux.cs | 3 --- .../src/System/Diagnostics/ProcessManager.SunOS.cs | 7 ------- 2 files changed, 10 deletions(-) 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 8ade1202f94ec0..a70c22d296ae2d 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 @@ -11,9 +11,6 @@ internal static partial class ProcessManager { private static NullableBool _procMatchesPidNamespace; - /// Gets the IDs of all processes on the current machine. - public static int[] GetProcessIds() => new List(EnumerateProcessIds()).ToArray(); - /// Gets process infos for each process on the local machine. /// The builder to add found process infos to. /// Optional process name to use as an inclusion filter. 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 67383bd563db08..a883b8aa75fd56 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 @@ -10,13 +10,6 @@ namespace System.Diagnostics { internal static partial class ProcessManager { - /// Gets the IDs of all processes on the current machine. - public static int[] GetProcessIds() - { - IEnumerable pids = EnumerateProcessIds(); - return new List(pids).ToArray(); - } - /// Gets process infos for each process on the local machine. /// The builder to add found process infos to. /// Optional process name to use as an inclusion filter. From 0e1922baa0403757902706ab9dae2512885f99e2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 07:09:26 +0000 Subject: [PATCH 38/54] Refactor NtProcessManager.GetProcessInfos: return Dictionary, inline constants Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/e8d6bb66-20ff-479d-a648-5b91818a4756 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../Diagnostics/ProcessManager.Windows.cs | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) 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 20f796d07be36a..fd63a75509cb91 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 @@ -492,13 +492,13 @@ public static void GetProcessInfos(ref ArrayBuilder builder, string private static void GetProcessInfos(PerformanceCounterLib library, ref ArrayBuilder builder, string? processNameFilter) { int retryCount = 5; - int totalProcessCount; + Dictionary processInfos; do { try { byte[]? dataPtr = library.GetPerformanceData(PerfCounterQueryString); - totalProcessCount = GetProcessInfos(library, ProcessPerfCounterId, ThreadPerfCounterId, dataPtr, ref builder, processNameFilter); + processInfos = GetProcessInfos(library, dataPtr); } catch (Exception e) { @@ -507,13 +507,19 @@ private static void GetProcessInfos(PerformanceCounterLib library, ref ArrayBuil --retryCount; } - while (totalProcessCount == 0 && retryCount != 0); + while (processInfos.Count == 0 && retryCount != 0); - if (totalProcessCount == 0) + if (processInfos.Count == 0) throw new InvalidOperationException(SR.ProcessDisabled); + + foreach (KeyValuePair entry in processInfos) + { + if (processNameFilter is null || string.Equals(processNameFilter, entry.Value.ProcessName, StringComparison.OrdinalIgnoreCase)) + builder.Add(entry.Value); + } } - private static int GetProcessInfos(PerformanceCounterLib library, int processIndex, int threadIndex, ReadOnlySpan data, ref ArrayBuilder builder, string? processNameFilter) + private static Dictionary GetProcessInfos(PerformanceCounterLib library, ReadOnlySpan data) { Dictionary processInfos = new Dictionary(); List threadInfos = new List(); @@ -542,9 +548,9 @@ private static int GetProcessInfos(PerformanceCounterLib library, int processInd string counterName = library.GetCounterName(counter.CounterNameTitleIndex); counters[j] = counter; - if (type.ObjectNameTitleIndex == processIndex) + if (type.ObjectNameTitleIndex == ProcessPerfCounterId) counters[j].CounterNameTitlePtr = (int)GetValueId(counterName); - else if (type.ObjectNameTitleIndex == threadIndex) + else if (type.ObjectNameTitleIndex == ThreadPerfCounterId) counters[j].CounterNameTitlePtr = (int)GetValueId(counterName); counterPos += counter.ByteLength; @@ -563,7 +569,7 @@ private static int GetProcessInfos(PerformanceCounterLib library, int processInd { // continue } - else if (type.ObjectNameTitleIndex == processIndex) + else if (type.ObjectNameTitleIndex == ProcessPerfCounterId) { ProcessInfo processInfo = GetProcessInfo(data.Slice(instancePos + instance.ByteLength), counters); if (processInfo.ProcessId == 0 && !instanceName.Equals("Idle", StringComparison.OrdinalIgnoreCase)) @@ -604,7 +610,7 @@ private static int GetProcessInfos(PerformanceCounterLib library, int processInd } } } - else if (type.ObjectNameTitleIndex == threadIndex) + else if (type.ObjectNameTitleIndex == ThreadPerfCounterId) { ThreadInfo threadInfo = GetThreadInfo(data.Slice(instancePos + instance.ByteLength), counters); if (threadInfo._threadId != 0) @@ -634,12 +640,7 @@ private static int GetProcessInfos(PerformanceCounterLib library, int processInd } } - foreach (KeyValuePair entry in processInfos) - { - if (processNameFilter is null || string.Equals(processNameFilter, entry.Value.ProcessName, StringComparison.OrdinalIgnoreCase)) - builder.Add(entry.Value); - } - return processInfos.Count; + return processInfos; } private static unsafe ThreadInfo GetThreadInfo(ReadOnlySpan instanceData, PERF_COUNTER_DEFINITION[] counters) From 1043bb486ff72ae787fde52a66824c787e6fdf2b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 07:25:48 +0000 Subject: [PATCH 39/54] Fold two NtProcessManager.GetProcessInfos(PerformanceCounterLib,...) overloads into one Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/31d4f43b-d24a-4a52-b113-f739626cdb1c Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/ProcessManager.Windows.cs | 4 ---- 1 file changed, 4 deletions(-) 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 fd63a75509cb91..a0acb7cddcae3e 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 @@ -486,11 +486,7 @@ public static void GetProcessInfos(ref ArrayBuilder builder, string { throw new InvalidOperationException(SR.CouldntConnectToRemoteMachine, e); } - GetProcessInfos(library, ref builder, processNameFilter); - } - private static void GetProcessInfos(PerformanceCounterLib library, ref ArrayBuilder builder, string? processNameFilter) - { int retryCount = 5; Dictionary processInfos; do From 861760b56cd2eba39f0d68990c32e47dea03cd7f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 07:39:01 +0000 Subject: [PATCH 40/54] NtProcessInfoHelper.GetProcessInfos returns Dictionary; remove redundant IsNullOrEmpty check Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/14a0d806-d0ea-46ef-a529-91231c12cb56 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../Diagnostics/ProcessManager.Windows.cs | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) 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 a0acb7cddcae3e..2f2d6d50d9bd85 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 @@ -45,8 +45,8 @@ internal static bool HandleRemoteMachineSupport(string machineName) /// Optional process name to use as an inclusion filter. internal static void GetProcessInfos(ref ArrayBuilder builder, string? processNameFilter) { - ProcessInfo[] processInfos = NtProcessInfoHelper.GetProcessInfos(processNameFilter: processNameFilter); - foreach (ProcessInfo pi in processInfos) + Dictionary processInfos = NtProcessInfoHelper.GetProcessInfos(processNameFilter: processNameFilter); + foreach (ProcessInfo pi in processInfos.Values) builder.Add(pi); } @@ -133,11 +133,9 @@ public static void GetProcessInfos(ref ArrayBuilder builder, string else { // local case: do not use performance counter and also attempt to get the matching (by pid) process only - ProcessInfo[] processInfos = NtProcessInfoHelper.GetProcessInfos(processId); - if (processInfos.Length == 1) - { - return processInfos[0]; - } + Dictionary processInfos = NtProcessInfoHelper.GetProcessInfos(processId); + if (processInfos.TryGetValue(processId, out ProcessInfo? processInfo)) + return processInfo; } return null; @@ -1009,7 +1007,7 @@ internal static class NtProcessInfoHelper /// Optional filter used to filter processes down to only those with the specified id. /// Optional filter used to filter processes down to only those with the specified name. /// All specified non-null filters are applied. - internal static unsafe ProcessInfo[] GetProcessInfos(int? processIdFilter = null, string? processNameFilter = null) + internal static unsafe Dictionary GetProcessInfos(int? processIdFilter = null, string? processNameFilter = null) { // Start with the default buffer size. uint bufferSize = MostRecentSize; @@ -1055,7 +1053,7 @@ internal static unsafe ProcessInfo[] GetProcessInfos(int? processIdFilter = null // kicked in since new call to NtQuerySystemInformation private static uint GetEstimatedBufferSize(uint actualSize) => actualSize + 1024 * 10; - private static unsafe ProcessInfo[] GetProcessInfos(ReadOnlySpan data, int? processIdFilter, string? processNameFilter) + private static unsafe Dictionary GetProcessInfos(ReadOnlySpan data, int? processIdFilter, string? processNameFilter) { // Use a dictionary to avoid duplicate entries if any // 60 is a reasonable number for processes on a normal machine. @@ -1079,7 +1077,7 @@ private static unsafe ProcessInfo[] GetProcessInfos(ReadOnlySpan data, int processId == NtProcessManager.IdleProcessID ? "Idle" : processId.ToString(CultureInfo.InvariantCulture)); // use the process ID for a normal process without a name - if (string.IsNullOrEmpty(processNameFilter) || processNameSpan.Equals(processNameFilter, StringComparison.OrdinalIgnoreCase)) + if (processNameFilter == null || processNameSpan.Equals(processNameFilter, StringComparison.OrdinalIgnoreCase)) { processName ??= processNameSpan.ToString(); @@ -1135,9 +1133,7 @@ private static unsafe ProcessInfo[] GetProcessInfos(ReadOnlySpan data, int processInformationOffset += (int)pi.NextEntryOffset; } - ProcessInfo[] temp = new ProcessInfo[processInfos.Values.Count]; - processInfos.Values.CopyTo(temp, 0); - return temp; + return processInfos; } // This function generates the short form of process name. From 01ff6617474042aa3cfa065d849d50b9254aa559 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Fri, 3 Apr 2026 00:45:53 -0700 Subject: [PATCH 41/54] Apply suggestion from @jkotas --- .../src/System/Diagnostics/ProcessManager.Windows.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 2f2d6d50d9bd85..2ebf1ed991e16d 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 @@ -46,8 +46,9 @@ internal static bool HandleRemoteMachineSupport(string machineName) internal static void GetProcessInfos(ref ArrayBuilder builder, string? processNameFilter) { Dictionary processInfos = NtProcessInfoHelper.GetProcessInfos(processNameFilter: processNameFilter); - foreach (ProcessInfo pi in processInfos.Values) - builder.Add(pi); + builder = new ArrayBuilder(processInfos.Count); + foreach (KeyValuePair entry in processInfos) + builder.Add(entry.Value); } /// Gets whether the process with the specified ID is currently running. From 1d45f23b0a93d6d70fb59e23da63ebee9713e13c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 07:50:41 +0000 Subject: [PATCH 42/54] Extract CreateProcessArray helper to reduce duplication in GetProcesses/GetProcessesByName Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/4d8d540b-97ed-45e4-8b8a-5f57abbe45ae Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/Process.cs | 35 +++++-------------- 1 file changed, 8 insertions(+), 27 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 37d1a938ddd663..51dc5dec47ab41 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -1075,15 +1075,7 @@ public static Process[] GetProcessesByName(string? processName) ArrayBuilder processInfos = default; // Normalize empty processName to null so that GetProcessInfos treats it as "no filter". ProcessManager.GetProcessInfos(ref processInfos, processNameFilter: string.IsNullOrEmpty(processName) ? null : processName); - if (processInfos.Count == 0) - return []; - Process[] processes = new Process[processInfos.Count]; - for (int i = 0; i < processes.Length; i++) - { - ProcessInfo processInfo = processInfos[i]; - processes[i] = new Process(".", false, processInfo.ProcessId, processInfo); - } - return processes; + return CreateProcessArray(processInfos, ".", false); } /// @@ -1099,15 +1091,7 @@ public static Process[] GetProcessesByName(string? processName, string machineNa ArrayBuilder processInfos = default; // Normalize empty processName to null so that GetProcessInfos treats it as "no filter". ProcessManager.GetProcessInfos(ref processInfos, string.IsNullOrEmpty(processName) ? null : processName, machineName, isRemoteMachine); - if (processInfos.Count == 0) - return []; - Process[] processes = new Process[processInfos.Count]; - for (int i = 0; i < processes.Length; i++) - { - ProcessInfo processInfo = processInfos[i]; - processes[i] = new Process(machineName, isRemoteMachine, processInfo.ProcessId, processInfo); - } - return processes; + return CreateProcessArray(processInfos, machineName, isRemoteMachine); } /// @@ -1124,15 +1108,7 @@ public static Process[] GetProcesses() // Avoid calling GetProcesses(".") so that remote machine code is not included when only local machine support is needed. ArrayBuilder processInfos = default; ProcessManager.GetProcessInfos(ref processInfos, processNameFilter: null); - if (processInfos.Count == 0) - return []; - Process[] processes = new Process[processInfos.Count]; - for (int i = 0; i < processes.Length; i++) - { - ProcessInfo processInfo = processInfos[i]; - processes[i] = new Process(".", false, processInfo.ProcessId, processInfo); - } - return processes; + return CreateProcessArray(processInfos, ".", false); } /// @@ -1150,6 +1126,11 @@ public static Process[] GetProcesses(string machineName) bool isRemoteMachine = ProcessManager.HandleRemoteMachineSupport(machineName); ArrayBuilder processInfos = default; ProcessManager.GetProcessInfos(ref processInfos, processNameFilter: null, machineName, isRemoteMachine); + return CreateProcessArray(processInfos, machineName, isRemoteMachine); + } + + private static Process[] CreateProcessArray(ArrayBuilder processInfos, string machineName, bool isRemoteMachine) + { if (processInfos.Count == 0) return []; Process[] processes = new Process[processInfos.Count]; From c11540a6f22f4490f7a54383c356d239ba313d80 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 08:17:06 +0000 Subject: [PATCH 43/54] Rename IsRemoteMachineCore to IsRemoteMachine, delete shared wrapper, move arg validation to HandleRemoteMachineSupport Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/73a4231d-8f5d-477c-8680-9a3a863cabf3 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/ProcessManager.Unix.cs | 3 ++- .../src/System/Diagnostics/ProcessManager.Windows.cs | 3 ++- .../src/System/Diagnostics/ProcessManager.cs | 9 --------- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs index c181b8ccabbe3d..f85ad5098185b7 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Unix.cs @@ -42,7 +42,7 @@ public static bool IsProcessRunning(int processId) CreateProcessInfo(processId); #pragma warning restore IDE0060 - private static bool IsRemoteMachineCore(string machineName) + private static bool IsRemoteMachine(string machineName) { return machineName != "." && @@ -51,6 +51,7 @@ private static bool IsRemoteMachineCore(string machineName) internal static bool HandleRemoteMachineSupport(string machineName) { + ArgumentException.ThrowIfNullOrEmpty(machineName); if (IsRemoteMachine(machineName)) { throw new PlatformNotSupportedException(SR.RemoteMachinesNotSupported); 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 2ebf1ed991e16d..53de5f06f9d33b 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 @@ -32,6 +32,7 @@ internal static partial class ProcessManager /// true if the machine is remote; otherwise, false. internal static bool HandleRemoteMachineSupport(string machineName) { + ArgumentException.ThrowIfNullOrEmpty(machineName); if (IsRemoteMachine(machineName)) { s_getRemoteProcessInfos ??= NtProcessManager.GetProcessInfos; @@ -211,7 +212,7 @@ public static ProcessModuleCollection GetModules(int processId) return NtProcessManager.GetModules(processId); } - private static bool IsRemoteMachineCore(string machineName) + internal static bool IsRemoteMachine(string machineName) { ReadOnlySpan baseName = machineName.AsSpan(machineName.StartsWith('\\') ? 2 : 0); return diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.cs index 7a776feba46dc6..acd2537d6bdcb5 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.cs @@ -5,14 +5,5 @@ namespace System.Diagnostics { internal static partial class ProcessManager { - /// Gets whether the named machine is remote or local. - /// The machine name. - /// true if the machine is remote; false if it's local. - public static bool IsRemoteMachine(string machineName) - { - ArgumentException.ThrowIfNullOrEmpty(machineName); - - return IsRemoteMachineCore(machineName); - } } } From ada09b510cd42c6b33abd9356c11b48a178049e6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 08:30:59 +0000 Subject: [PATCH 44/54] Delete empty ProcessManager.cs and remove from csproj Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/f1984485-e3d3-4c22-a4ba-d010d7ddbc21 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System.Diagnostics.Process.csproj | 1 - .../src/System/Diagnostics/ProcessManager.cs | 9 --------- 2 files changed, 10 deletions(-) delete mode 100644 src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.cs diff --git a/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj b/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj index a07bd634b1eae5..7dcba388e75c26 100644 --- a/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj +++ b/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj @@ -22,7 +22,6 @@ - diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.cs deleted file mode 100644 index acd2537d6bdcb5..00000000000000 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.cs +++ /dev/null @@ -1,9 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Diagnostics -{ - internal static partial class ProcessManager - { - } -} From 9ca37113ea623e258261588d010e7980bc2590ba Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 18:06:34 +0000 Subject: [PATCH 45/54] Remove HandleRemoteMachineSupport from GetProcessName; add isRemoteMachine parameter Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/85b5145d-83e5-4298-b4c1-025c0dd77d09 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/Process.cs | 4 ++-- .../src/System/Diagnostics/ProcessManager.FreeBSD.cs | 6 +++--- .../src/System/Diagnostics/ProcessManager.Linux.cs | 6 +++--- .../src/System/Diagnostics/ProcessManager.OSX.cs | 6 +++--- .../src/System/Diagnostics/ProcessManager.SunOS.cs | 6 +++--- .../src/System/Diagnostics/ProcessManager.Windows.cs | 3 +-- .../src/System/Diagnostics/ProcessManager.iOS.cs | 2 +- 7 files changed, 16 insertions(+), 17 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 8e5cd2e346ab32..69baf80ee6d568 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -257,7 +257,7 @@ public string ProcessName get { EnsureState(State.HaveNonExitedId); - string? processName = _processName ??= ProcessManager.GetProcessName(_processId, _machineName, ref _processInfo); + string? processName = _processName ??= ProcessManager.GetProcessName(_processId, _machineName, _isRemoteMachine, ref _processInfo); if (processName is null) { ThrowNoProcessInfo(); @@ -1418,7 +1418,7 @@ public override string ToString() { if (Associated) { - string? processName = _processName ??= ProcessManager.GetProcessName(_processId, _machineName, ref _processInfo); + string? processName = _processName ??= ProcessManager.GetProcessName(_processId, _machineName, _isRemoteMachine, ref _processInfo); if (!string.IsNullOrEmpty(processName)) { result = $"{result} ({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 24f05545bb7ff2..8470dc85b5f6fd 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,10 +20,10 @@ internal static string GetProcPath(int processId) return Interop.Process.GetProcPath(processId); } - internal static string? GetProcessName(int processId, string machineName, ref ProcessInfo? processInfo) +#pragma warning disable IDE0060 + internal static string? GetProcessName(int processId, string machineName, bool isRemoteMachine, ref ProcessInfo? processInfo) +#pragma warning restore IDE0060 { - HandleRemoteMachineSupport(machineName); - if (processInfo is not null) { return processInfo.ProcessName; 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 b6559a220502ad..d22fb242689cd2 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 @@ -28,10 +28,10 @@ public static void GetProcessInfos(ref ArrayBuilder builder, string } } - internal static string? GetProcessName(int processId, string machineName, ref ProcessInfo? processInfo) +#pragma warning disable IDE0060 + internal static string? GetProcessName(int processId, string machineName, bool isRemoteMachine, ref ProcessInfo? processInfo) +#pragma warning restore IDE0060 { - HandleRemoteMachineSupport(machineName); - if (processInfo is not null) { return processInfo.ProcessName; 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 3daa04d9ae656c..1c6c4ddca7ed0f 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,10 +21,10 @@ private static string GetProcPath(int processId) return Interop.libproc.proc_pidpath(processId); } - internal static string? GetProcessName(int processId, string machineName, ref ProcessInfo? processInfo) +#pragma warning disable IDE0060 + internal static string? GetProcessName(int processId, string machineName, bool isRemoteMachine, ref ProcessInfo? processInfo) +#pragma warning restore IDE0060 { - HandleRemoteMachineSupport(machineName); - if (processInfo is not null) { return processInfo.ProcessName; 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 d83c1c98a76617..c9d8b962a9da8f 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 @@ -58,10 +58,10 @@ internal static ProcessModuleCollection GetModules(int processId) return new ProcessModuleCollection(0); } - internal static string? GetProcessName(int processId, string machineName, ref ProcessInfo? processInfo) +#pragma warning disable IDE0060 + internal static string? GetProcessName(int processId, string machineName, bool isRemoteMachine, ref ProcessInfo? processInfo) +#pragma warning restore IDE0060 { - HandleRemoteMachineSupport(machineName); - if (processInfo is not null) { return processInfo.ProcessName; 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 a2caea4011d8f1..c2356ced965405 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 @@ -143,14 +143,13 @@ public static void GetProcessInfos(ref ArrayBuilder builder, string return null; } - internal static string? GetProcessName(int processId, string machineName, ref ProcessInfo? processInfo) + internal static string? GetProcessName(int processId, string machineName, bool isRemoteMachine, ref ProcessInfo? processInfo) { if (processInfo is not null) { return processInfo.ProcessName; } - bool isRemoteMachine = IsRemoteMachine(machineName); if (!isRemoteMachine) { string? processName = Interop.Kernel32.GetProcessName((uint)processId); 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 7934b9eddf1e89..c052c2ca79063b 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 @@ -31,7 +31,7 @@ internal static ProcessModuleCollection GetModules(int processId) return new ProcessModuleCollection(0); } - internal static string? GetProcessName(int processId, string machineName, ref ProcessInfo? processInfo) + internal static string? GetProcessName(int processId, string machineName, bool isRemoteMachine, ref ProcessInfo? processInfo) { throw new PlatformNotSupportedException(); } From 1ae42cc5d7ad26f0f71158d0ba23d3c236fef641 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 18:17:13 +0000 Subject: [PATCH 46/54] Remove redundant IsNullOrEmpty check on processNameFilter in BSD/OSX/SunOS CreateProcessInfo Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/8621c930-4bf4-4381-bec7-2541991cf40c Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/ProcessManager.FreeBSD.cs | 2 +- .../src/System/Diagnostics/ProcessManager.OSX.cs | 2 +- .../src/System/Diagnostics/ProcessManager.SunOS.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) 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 8470dc85b5f6fd..6e0c17aab236aa 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 @@ -41,7 +41,7 @@ internal static string GetProcPath(int processId) // Try to get the task info. This can fail if the user permissions don't permit // this user context to query the specified process ProcessInfo iinfo = Interop.Process.GetProcessInfoById(pid); - if (!string.IsNullOrEmpty(processNameFilter) && !processNameFilter.Equals(iinfo.ProcessName)) + if (processNameFilter != null && !processNameFilter.Equals(iinfo.ProcessName)) { return null; } 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 1c6c4ddca7ed0f..8dce79455da4ea 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 @@ -81,7 +81,7 @@ private static string GetProcPath(int processId) Interop.libproc.proc_taskallinfo? info; string processName = GetProcessName(pid, out info, getInfo: true) ?? ""; - if (!string.IsNullOrEmpty(processNameFilter) && !string.Equals(processName, processNameFilter, StringComparison.OrdinalIgnoreCase)) + if (processNameFilter != null && !string.Equals(processName, processNameFilter, StringComparison.OrdinalIgnoreCase)) { return null; } 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 c9d8b962a9da8f..414b9417431180 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 @@ -87,7 +87,7 @@ internal static ProcessModuleCollection GetModules(int processId) } string? processName = Process.GetUntruncatedProcessName(ref processInfo, ref argString); - if (!string.IsNullOrEmpty(processNameFilter) && + if (processNameFilter != null && !string.Equals(processName, processNameFilter, StringComparison.OrdinalIgnoreCase)) { return null; From b0182ab98c430251c9c831e2f06f88fe9eee26f5 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Fri, 3 Apr 2026 11:47:45 -0700 Subject: [PATCH 47/54] Apply suggestions from code review Co-authored-by: Jan Kotas --- .../src/System/Diagnostics/ProcessManager.FreeBSD.cs | 2 +- .../src/System/Diagnostics/ProcessManager.OSX.cs | 2 +- .../src/System/Diagnostics/ProcessManager.SunOS.cs | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) 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 6e0c17aab236aa..6dcbe3a88101e6 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 @@ -41,7 +41,7 @@ internal static string GetProcPath(int processId) // Try to get the task info. This can fail if the user permissions don't permit // this user context to query the specified process ProcessInfo iinfo = Interop.Process.GetProcessInfoById(pid); - if (processNameFilter != null && !processNameFilter.Equals(iinfo.ProcessName)) + if (processNameFilter != null && !processNameFilter.Equals(iinfo.ProcessName, StringComparison.OrdinalIgnoreCase)) { return null; } 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 8dce79455da4ea..db768d63868333 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 @@ -81,7 +81,7 @@ private static string GetProcPath(int processId) Interop.libproc.proc_taskallinfo? info; string processName = GetProcessName(pid, out info, getInfo: true) ?? ""; - if (processNameFilter != null && !string.Equals(processName, processNameFilter, StringComparison.OrdinalIgnoreCase)) + if (processNameFilter != null && !processNameFilter.Equals(processName, StringComparison.OrdinalIgnoreCase)) { return null; } 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 414b9417431180..fa6b6b25658b92 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 @@ -87,8 +87,7 @@ internal static ProcessModuleCollection GetModules(int processId) } string? processName = Process.GetUntruncatedProcessName(ref processInfo, ref argString); - if (processNameFilter != null && - !string.Equals(processName, processNameFilter, StringComparison.OrdinalIgnoreCase)) + if (processNameFilter != null && !processNameFilter.Equals(processName, StringComparison.OrdinalIgnoreCase)) { return null; } From e962f351041aaa94076abc54d2154b21f0a96304 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Fri, 3 Apr 2026 11:48:32 -0700 Subject: [PATCH 48/54] Apply suggestion from @jkotas --- .../src/System/Diagnostics/ProcessManager.Linux.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 d22fb242689cd2..a241b59b5901b0 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 @@ -93,7 +93,7 @@ internal static ProcessModuleCollection GetModules(int processId) if (processNameFilter != null) { processName = Process.GetUntruncatedProcessName(procPid, ref stat); - if (!string.Equals(processName, processNameFilter, StringComparison.OrdinalIgnoreCase)) + if (!processNameFilter.Equals(processName, StringComparison.OrdinalIgnoreCase)) { return null; } From ee4db6a3489c6f2872be117ec1f4ad7edc5c18aa Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Fri, 3 Apr 2026 12:25:55 -0700 Subject: [PATCH 49/54] Apply suggestion from @jkotas --- .../src/System/Diagnostics/ProcessManager.Windows.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 c2356ced965405..ae602dfbc31e45 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 @@ -497,7 +497,7 @@ public static void GetProcessInfos(ref ArrayBuilder builder, string foreach (KeyValuePair entry in processInfos) { - if (processNameFilter is null || string.Equals(processNameFilter, entry.Value.ProcessName, StringComparison.OrdinalIgnoreCase)) + if (processNameFilter is null || processNameFilter.Equals(entry.Value.ProcessName, StringComparison.OrdinalIgnoreCase)) builder.Add(entry.Value); } } From 37d8c5687d1e27f3a6050de1e09a35a2b077a39b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 19:46:13 +0000 Subject: [PATCH 50/54] Fix extra blank lines and inconsistent null-check style Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/e881e4f5-7fee-4cef-bfa7-561466495b2a Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/Process.Windows.cs | 1 - .../src/System/Diagnostics/Process.cs | 1 - .../src/System/Diagnostics/ProcessManager.Windows.cs | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) 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 d592f55ebf542f..c735f73304531e 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 @@ -508,7 +508,6 @@ private SafeProcessHandle GetProcessHandle(int access, bool throwIfExited = true private static ConsoleEncoding GetStandardOutputEncoding() => GetEncoding((int)Interop.Kernel32.GetConsoleOutputCP()); - private bool StartCore(ProcessStartInfo startInfo, SafeFileHandle? stdinHandle, SafeFileHandle? stdoutHandle, SafeFileHandle? stderrHandle) { SafeProcessHandle startedProcess = SafeProcessHandle.StartCore(startInfo, stdinHandle, stdoutHandle, stderrHandle); 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 69baf80ee6d568..86315f19cb722f 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -868,7 +868,6 @@ private void EnsureState(State state) throw new NotSupportedException(SR.NotSupportedRemote); } - if ((state & State.Exited) != (State)0) { if (!HasExited) 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 ae602dfbc31e45..7cf3255fbf7562 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 @@ -1066,7 +1066,7 @@ private static unsafe Dictionary GetProcessInfos(ReadOnlySpan< processId == NtProcessManager.IdleProcessID ? "Idle" : processId.ToString(CultureInfo.InvariantCulture)); // use the process ID for a normal process without a name - if (processNameFilter == null || processNameSpan.Equals(processNameFilter, StringComparison.OrdinalIgnoreCase)) + if (processNameFilter is null || processNameSpan.Equals(processNameFilter, StringComparison.OrdinalIgnoreCase)) { processName ??= processNameSpan.ToString(); From 56656d50e0052be0eb0322fd69ee82c36a120e1e Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Fri, 3 Apr 2026 13:11:34 -0700 Subject: [PATCH 51/54] Update src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Windows.cs Co-authored-by: Adam Sitnik --- .../src/System/Diagnostics/ProcessManager.Windows.cs | 5 +++++ 1 file changed, 5 insertions(+) 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 7cf3255fbf7562..8504d68f217470 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 @@ -182,6 +182,11 @@ public static int[] GetProcessIds(string machineName, bool isRemoteMachine) int[] ids = new int[builder.Count]; for (int i = 0; i < ids.Length; i++) ids[i] = builder[i].ProcessId; + for (int i = 0; i < ids.Length; i++) + { + ids[i] = builder[i].ProcessId; + } + return ids; } From 0159e644f53613a497f70a453c4c4d6091ee5c76 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Fri, 3 Apr 2026 13:12:33 -0700 Subject: [PATCH 52/54] Apply suggestion from @jkotas --- .../src/System/Diagnostics/ProcessManager.Windows.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 8504d68f217470..13d5921b7abd12 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 @@ -179,9 +179,8 @@ public static int[] GetProcessIds(string machineName, bool isRemoteMachine) ArrayBuilder builder = default; s_getRemoteProcessInfos!(ref builder, processNameFilter: null, machineName); + int[] ids = new int[builder.Count]; - for (int i = 0; i < ids.Length; i++) - ids[i] = builder[i].ProcessId; for (int i = 0; i < ids.Length; i++) { ids[i] = builder[i].ProcessId; From 67ebd5002d5565a7bf46b21e3f4c64edb176b376 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 20:54:48 +0000 Subject: [PATCH 53/54] Fix processIdFilter == null to use is null per dotnet/runtime conventions Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/57e910b4-e9dc-4d58-be98-3307b7bb2fb6 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/ProcessManager.Windows.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 13d5921b7abd12..8c329e98857dc9 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 @@ -1060,7 +1060,7 @@ private static unsafe Dictionary GetProcessInfos(ReadOnlySpan< // Process ID shouldn't overflow. OS API GetCurrentProcessID returns DWORD. int processId = pi.UniqueProcessId.ToInt32(); - if (processIdFilter == null || processIdFilter.GetValueOrDefault() == processId) + if (processIdFilter is null || processIdFilter.GetValueOrDefault() == processId) { string? processName = null; ReadOnlySpan processNameSpan = From 4e2d150f1ad4789ad7afee27015605dbf22ed7a4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 21:12:22 +0000 Subject: [PATCH 54/54] Replace #pragma warning disable IDE0060 with discard params; add foreach braces; fix double blank lines Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/d5325063-0131-4c3c-a241-a0a4e3d178dc Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> --- .../src/System/Diagnostics/Process.cs | 5 ----- .../src/System/Diagnostics/ProcessManager.FreeBSD.cs | 4 +--- .../src/System/Diagnostics/ProcessManager.Linux.cs | 4 +--- .../src/System/Diagnostics/ProcessManager.OSX.cs | 4 +--- .../src/System/Diagnostics/ProcessManager.SunOS.cs | 4 +--- .../src/System/Diagnostics/ProcessManager.Windows.cs | 2 ++ 6 files changed, 6 insertions(+), 17 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 86315f19cb722f..361ef0361bf7ee 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs @@ -334,7 +334,6 @@ public long NonpagedSystemMemorySize64 public int NonpagedSystemMemorySize => unchecked((int)GetProcessInfo().PoolNonPagedBytes); - public long PagedMemorySize64 => GetProcessInfo().PageFileBytes; @@ -342,7 +341,6 @@ public long PagedMemorySize64 public int PagedMemorySize => unchecked((int)GetProcessInfo().PageFileBytes); - public long PagedSystemMemorySize64 => GetProcessInfo().PoolPagedBytes; @@ -350,7 +348,6 @@ public long PagedSystemMemorySize64 public int PagedSystemMemorySize => unchecked((int)GetProcessInfo().PoolPagedBytes); - public long PeakPagedMemorySize64 => GetProcessInfo().PageFileBytesPeak; @@ -577,7 +574,6 @@ public bool EnableRaisingEvents } } - /// /// [To be supplied.] /// @@ -1634,7 +1630,6 @@ public void BeginOutputReadLine() _output.BeginReadLine(); } - /// /// /// Instructs the component to start 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 6dcbe3a88101e6..bfb355e51fd9de 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,9 +20,7 @@ internal static string GetProcPath(int processId) return Interop.Process.GetProcPath(processId); } -#pragma warning disable IDE0060 - internal static string? GetProcessName(int processId, string machineName, bool isRemoteMachine, ref ProcessInfo? processInfo) -#pragma warning restore IDE0060 + internal static string? GetProcessName(int processId, string _ /* machineName */, bool __ /* isRemoteMachine */, ref ProcessInfo? processInfo) { if (processInfo is not null) { 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 a241b59b5901b0..d7aa0eded800fe 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 @@ -28,9 +28,7 @@ public static void GetProcessInfos(ref ArrayBuilder builder, string } } -#pragma warning disable IDE0060 - internal static string? GetProcessName(int processId, string machineName, bool isRemoteMachine, ref ProcessInfo? processInfo) -#pragma warning restore IDE0060 + internal static string? GetProcessName(int processId, string _ /* machineName */, bool __ /* isRemoteMachine */, ref ProcessInfo? processInfo) { if (processInfo is not null) { 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 db768d63868333..4e60e7a1288664 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,9 +21,7 @@ private static string GetProcPath(int processId) return Interop.libproc.proc_pidpath(processId); } -#pragma warning disable IDE0060 - internal static string? GetProcessName(int processId, string machineName, bool isRemoteMachine, ref ProcessInfo? processInfo) -#pragma warning restore IDE0060 + internal static string? GetProcessName(int processId, string _ /* machineName */, bool __ /* isRemoteMachine */, ref ProcessInfo? processInfo) { if (processInfo is not null) { 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 fa6b6b25658b92..d34fa5679e6895 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 @@ -58,9 +58,7 @@ internal static ProcessModuleCollection GetModules(int processId) return new ProcessModuleCollection(0); } -#pragma warning disable IDE0060 - internal static string? GetProcessName(int processId, string machineName, bool isRemoteMachine, ref ProcessInfo? processInfo) -#pragma warning restore IDE0060 + internal static string? GetProcessName(int processId, string _ /* machineName */, bool __ /* isRemoteMachine */, ref ProcessInfo? processInfo) { if (processInfo is not null) { 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 8c329e98857dc9..7c2bb7b35764b3 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 @@ -49,7 +49,9 @@ internal static void GetProcessInfos(ref ArrayBuilder builder, stri Dictionary processInfos = NtProcessInfoHelper.GetProcessInfos(processNameFilter: processNameFilter); builder = new ArrayBuilder(processInfos.Count); foreach (KeyValuePair entry in processInfos) + { builder.Add(entry.Value); + } } /// Gets whether the process with the specified ID is currently running.