|
4 | 4 |
|
5 | 5 | using System.Collections; |
6 | 6 | using System.Diagnostics; |
7 | | -using System.Globalization; |
8 | 7 | using System.IO; |
9 | 8 | using System.Linq; |
10 | 9 | using System.Reflection; |
|
16 | 15 | using Microsoft.Win32; |
17 | 16 | using System.Collections.Generic; |
18 | 17 | using System.Management.Automation.Language; |
19 | | -using Microsoft.Management.Infrastructure; |
| 18 | +#if CORECLR |
| 19 | +// Use stubs for SerializableAttribute, SecurityPermissionAttribute, ReliabilityContractAttribute and ISerializable related types. |
| 20 | +using Microsoft.PowerShell.CoreClr.Stubs; |
| 21 | +#endif |
20 | 22 |
|
21 | 23 | namespace System.Management.Automation |
22 | 24 | { |
@@ -91,57 +93,64 @@ internal static ProcessModule GetMainModule(Process targetProcess) |
91 | 93 | /// <summary> |
92 | 94 | /// Retrieve the parent process of a process. |
93 | 95 | /// |
94 | | - /// This is an extremely expensive operation, as WMI |
95 | | - /// needs to work with an ugly Win32 API. The Win32 API |
96 | | - /// creates a snapshot of every process in the system, which |
97 | | - /// you then need to iterate through to find your process and |
98 | | - /// its parent PID. |
99 | | - /// |
100 | | - /// Also, since this is PID based, this API is only reliable |
101 | | - /// when the process has not yet exited. |
| 96 | + /// Previously this code used WMI, but WMI is causing a CPU spike whenever the query gets called as it results in |
| 97 | + /// tzres.dll and tzres.mui.dll being loaded into every process to conver the time information to local format. |
| 98 | + /// For perf reasons, we result to P/Invoke. |
102 | 99 | /// </summary> |
103 | 100 | /// |
104 | 101 | /// <param name="current">The process we want to find the |
105 | 102 | /// parent of</param> |
106 | 103 | internal static Process GetParentProcess(Process current) |
107 | 104 | { |
108 | | - string wmiQuery = String.Format(CultureInfo.CurrentCulture, |
109 | | - "Select * From Win32_Process Where Handle='{0}'", |
110 | | - current.Id); |
111 | | - |
112 | | - using (CimSession cimSession = CimSession.Create(null)) |
113 | | - { |
114 | | - IEnumerable<CimInstance> processCollection = |
115 | | - cimSession.QueryInstances("root/cimv2", "WQL", wmiQuery); |
116 | | - |
117 | | - int parentPid = |
118 | | - processCollection.Select( |
119 | | - cimProcess => |
120 | | - Convert.ToInt32(cimProcess.CimInstanceProperties["ParentProcessId"].Value, |
121 | | - CultureInfo.CurrentCulture)).FirstOrDefault(); |
| 105 | + int parentPid = 0; |
122 | 106 |
|
123 | | - if (parentPid == 0) |
124 | | - return null; |
| 107 | +#if !UNIX |
| 108 | + PlatformInvokes.PROCESSENTRY32 pe32 = new PlatformInvokes.PROCESSENTRY32 { }; |
| 109 | + pe32.dwSize = (uint)ClrFacade.SizeOf<PlatformInvokes.PROCESSENTRY32>(); |
125 | 110 |
|
126 | | - try |
| 111 | + using (PlatformInvokes.SafeSnapshotHandle hSnapshot = PlatformInvokes.CreateToolhelp32Snapshot(PlatformInvokes.SnapshotFlags.Process, (uint)current.Id)) |
| 112 | + { |
| 113 | + if (!PlatformInvokes.Process32First(hSnapshot, ref pe32)) |
127 | 114 | { |
128 | | - Process returnProcess = Process.GetProcessById(parentPid); |
129 | | - |
130 | | - // Ensure the process started before the current |
131 | | - // process, as it could have gone away and had the |
132 | | - // PID recycled. |
133 | | - if (returnProcess.StartTime <= current.StartTime) |
134 | | - return returnProcess; |
135 | | - else |
| 115 | + int errno = Marshal.GetLastWin32Error(); |
| 116 | + if (errno == PlatformInvokes.ERROR_NO_MORE_FILES) |
| 117 | + { |
136 | 118 | return null; |
| 119 | + } |
137 | 120 | } |
138 | | - catch (ArgumentException) |
| 121 | + do |
139 | 122 | { |
140 | | - // GetProcessById throws an ArgumentException when |
141 | | - // you reach the top of the chain -- Explorer.exe |
142 | | - // has a parent process, but you cannot retrieve it. |
| 123 | + if (pe32.th32ProcessID == (uint)current.Id) |
| 124 | + { |
| 125 | + parentPid = (int)pe32.th32ParentProcessID; |
| 126 | + break; |
| 127 | + } |
| 128 | + |
| 129 | + } while (PlatformInvokes.Process32Next(hSnapshot, ref pe32)); |
| 130 | + } |
| 131 | +#endif |
| 132 | + |
| 133 | + if (parentPid == 0) |
| 134 | + return null; |
| 135 | + |
| 136 | + try |
| 137 | + { |
| 138 | + Process returnProcess = Process.GetProcessById(parentPid); |
| 139 | + |
| 140 | + // Ensure the process started before the current |
| 141 | + // process, as it could have gone away and had the |
| 142 | + // PID recycled. |
| 143 | + if (returnProcess.StartTime <= current.StartTime) |
| 144 | + return returnProcess; |
| 145 | + else |
143 | 146 | return null; |
144 | | - } |
| 147 | + } |
| 148 | + catch (ArgumentException) |
| 149 | + { |
| 150 | + // GetProcessById throws an ArgumentException when |
| 151 | + // you reach the top of the chain -- Explorer.exe |
| 152 | + // has a parent process, but you cannot retrieve it. |
| 153 | + return null; |
145 | 154 | } |
146 | 155 | } |
147 | 156 |
|
|
0 commit comments