/// <summary>Gets process infos for each process on the specified machine.</summary> /// <param name="machineName">The target machine.</param> /// <returns>An array of process infos, one per found process.</returns> public static ProcessInfo[] GetProcessInfos(string machineName) { ThrowIfRemoteMachine(machineName); int[] procIds = GetProcessIds(machineName); // Iterate through all process IDs to load information about each process var reusableReader = new ReusableTextReader(); var processes = new List<ProcessInfo>(procIds.Length); foreach (int pid in procIds) { ProcessInfo pi = CreateProcessInfo(pid, reusableReader); if (pi != null) { processes.Add(pi); } } return processes.ToArray(); }
/// <summary> /// Creates an array of <see cref="Process"/> components that are associated with process resources on a /// remote computer. These process resources share the specified process name. /// </summary> public static Process[] GetProcessesByName(string processName, string machineName) { ProcessManager.ThrowIfRemoteMachine(machineName); if (processName == null) { processName = string.Empty; } var reusableReader = new ReusableTextReader(); var processes = new List<Process>(); foreach (int pid in ProcessManager.EnumerateProcessIds()) { Interop.procfs.ParsedStat parsedStat; if (Interop.procfs.TryReadStatFile(pid, out parsedStat, reusableReader) && string.Equals(processName, parsedStat.comm, StringComparison.OrdinalIgnoreCase)) { ProcessInfo processInfo = ProcessManager.CreateProcessInfo(parsedStat, reusableReader); processes.Add(new Process(machineName, false, processInfo.ProcessId, processInfo)); } } return processes.ToArray(); }
private static bool TryParseStatFile(string statFilePath, out ParsedStat result, ReusableTextReader reusableReader) { string statFileContents; try { using (var source = new FileStream(statFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 1, useAsync: false)) { statFileContents = reusableReader.ReadAllText(source); } } catch (IOException) { // Between the time that we get an ID and the time that we try to read the associated stat // file(s), the process could be gone. result = default(ParsedStat); return false; } var parser = new StringParser(statFileContents, ' '); var results = default(ParsedStat); results.pid = parser.ParseNextInt32(); results.comm = parser.ParseRaw(delegate (string str, ref int startIndex, ref int endIndex) { if (str[startIndex] == '(') { int i; for (i = endIndex; i < str.Length && str[i - 1] != ')'; i++) ; if (str[i - 1] == ')') { endIndex = i; return str.Substring(startIndex + 1, i - startIndex - 2); } } throw new InvalidDataException(); }); results.state = parser.ParseNextChar(); parser.MoveNextOrFail(); // ppid parser.MoveNextOrFail(); // pgrp results.session = parser.ParseNextInt32(); parser.MoveNextOrFail(); // tty_nr parser.MoveNextOrFail(); // tpgid parser.MoveNextOrFail(); // flags parser.MoveNextOrFail(); // majflt parser.MoveNextOrFail(); // cmagflt parser.MoveNextOrFail(); // minflt parser.MoveNextOrFail(); // cminflt results.utime = parser.ParseNextUInt64(); results.stime = parser.ParseNextUInt64(); parser.MoveNextOrFail(); // cutime parser.MoveNextOrFail(); // cstime parser.MoveNextOrFail(); // priority results.nice = parser.ParseNextInt64(); parser.MoveNextOrFail(); // num_threads parser.MoveNextOrFail(); // itrealvalue results.starttime = parser.ParseNextUInt64(); results.vsize = parser.ParseNextUInt64(); results.rss = parser.ParseNextInt64(); results.rsslim = parser.ParseNextUInt64(); parser.MoveNextOrFail(); // startcode parser.MoveNextOrFail(); // endcode results.startstack = parser.ParseNextUInt64(); // The following lines are commented out as there's no need to parse through // the rest of the entry (we've gotten all of the data we need). Should any // of these fields be needed in the future, uncomment all of the lines up // through and including the one that's needed. For now, these are being left // commented to document what's available in the remainder of the entry. //parser.MoveNextOrFail(); // kstkesp //parser.MoveNextOrFail(); // kstkeip //parser.MoveNextOrFail(); // signal //parser.MoveNextOrFail(); // blocked //parser.MoveNextOrFail(); // sigignore //parser.MoveNextOrFail(); // sigcatch //parser.MoveNextOrFail(); // wchan //parser.MoveNextOrFail(); // nswap //parser.MoveNextOrFail(); // cnswap //parser.MoveNextOrFail(); // exit_signal //parser.MoveNextOrFail(); // processor //parser.MoveNextOrFail(); // rt_priority //parser.MoveNextOrFail(); // policy //parser.MoveNextOrFail(); // delayacct_blkio_ticks //parser.MoveNextOrFail(); // guest_time //parser.MoveNextOrFail(); // cguest_time result = results; return true; }
internal static bool TryReadStatFile(int pid, int tid, out ParsedStat result, ReusableTextReader reusableReader) { bool b = TryParseStatFile(GetStatFilePathForThread(pid, tid), out result, reusableReader); Debug.Assert(!b || result.pid == tid, "Expected thread ID from stat file to match supplied tid"); return b; }
// ----------------------------- // ---- PAL layer ends here ---- // ----------------------------- /// <summary> /// Creates a ProcessInfo from the specified process ID. /// </summary> internal static ProcessInfo CreateProcessInfo(int pid, ReusableTextReader reusableReader = null) { if (reusableReader == null) { reusableReader = new ReusableTextReader(); } Interop.procfs.ParsedStat stat; return Interop.procfs.TryReadStatFile(pid, out stat, reusableReader) ? CreateProcessInfo(stat, reusableReader) : null; }
/// <summary> /// Creates a ProcessInfo from the data parsed from a /proc/pid/stat file and the associated tasks directory. /// </summary> internal static ProcessInfo CreateProcessInfo(Interop.procfs.ParsedStat procFsStat, ReusableTextReader reusableReader) { int pid = procFsStat.pid; var pi = new ProcessInfo() { ProcessId = pid, ProcessName = procFsStat.comm, BasePriority = (int)procFsStat.nice, VirtualBytes = (long)procFsStat.vsize, WorkingSet = procFsStat.rss, SessionId = procFsStat.session, // We don't currently fill in the other values. // A few of these could probably be filled in from getrusage, // but only for the current process or its children, not for // arbitrary other processes. }; // Then read through /proc/pid/task/ to find each thread in the process... string tasksDir = Interop.procfs.GetTaskDirectoryPathForProcess(pid); foreach (string taskDir in Directory.EnumerateDirectories(tasksDir)) { // ...and read its associated /proc/pid/task/tid/stat file to create a ThreadInfo string dirName = Path.GetFileName(taskDir); int tid; Interop.procfs.ParsedStat stat; if (int.TryParse(dirName, NumberStyles.Integer, CultureInfo.InvariantCulture, out tid) && Interop.procfs.TryReadStatFile(pid, tid, out stat, reusableReader)) { pi._threadInfoList.Add(new ThreadInfo() { _processId = pid, _threadId = (ulong)tid, _basePriority = pi.BasePriority, _currentPriority = (int)stat.nice, _startAddress = (IntPtr)stat.startstack, _threadState = ProcFsStateToThreadState(stat.state), _threadWaitReason = ThreadWaitReason.Unknown }); } } // Finally return what we've built up return pi; }
internal static bool TryReadStatFile(int pid, int tid, out ParsedStat result, ReusableTextReader reusableReader) { bool b = TryParseStatFile(GetStatFilePathForThread(pid, tid), out result, reusableReader); // // This assert currently fails in the Windows Subsystem For Linux. See https://github.com/Microsoft/BashOnWindows/issues/967. // //Debug.Assert(!b || result.pid == tid, "Expected thread ID from stat file to match supplied tid"); return b; }
private static bool TryParseStatFile(string statFilePath, out ParsedStat result, ReusableTextReader reusableReader) { string statFileContents; try { using (var source = new FileStream(statFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 1, useAsync: false)) { statFileContents = reusableReader.ReadAllText(source); } } catch (IOException) { // Between the time that we get an ID and the time that we try to read the associated stat // file(s), the process could be gone. result = default(ParsedStat); return false; } var parser = new StringParser(statFileContents, ' '); var results = default(ParsedStat); results.pid = parser.ParseNextInt32(); results.comm = parser.ParseRaw(delegate (string str, ref int startIndex, ref int endIndex) { if (str[startIndex] == '(') { int i; for (i = endIndex; i < str.Length && str[i - 1] != ')'; i++) ; if (str[i - 1] == ')') { endIndex = i; return str.Substring(startIndex + 1, i - startIndex - 2); } } throw new InvalidDataException(); }); results.state = parser.ParseNextChar(); parser.MoveNextOrFail(); // ppid parser.MoveNextOrFail(); // pgrp results.session = parser.ParseNextInt32(); parser.MoveNextOrFail(); // tty_nr parser.MoveNextOrFail(); // tpgid parser.MoveNextOrFail(); // flags parser.MoveNextOrFail(); // majflt parser.MoveNextOrFail(); // cmagflt parser.MoveNextOrFail(); // minflt parser.MoveNextOrFail(); // cminflt results.utime = parser.ParseNextUInt64(); results.stime = parser.ParseNextUInt64(); parser.MoveNextOrFail(); // cutime parser.MoveNextOrFail(); // cstime parser.MoveNextOrFail(); // priority results.nice = parser.ParseNextInt64(); parser.MoveNextOrFail(); // num_threads parser.MoveNextOrFail(); // itrealvalue results.starttime = parser.ParseNextUInt64(); results.vsize = parser.ParseNextUInt64(); results.rss = parser.ParseNextInt64(); results.rsslim = parser.ParseNextUInt64(); parser.MoveNextOrFail(); // startcode parser.MoveNextOrFail(); // endcode results.startstack = parser.ParseNextUInt64(); parser.MoveNextOrFail(); // kstkesp parser.MoveNextOrFail(); // kstkeip parser.MoveNextOrFail(); // signal parser.MoveNextOrFail(); // blocked parser.MoveNextOrFail(); // sigignore parser.MoveNextOrFail(); // sigcatch parser.MoveNextOrFail(); // wchan parser.MoveNextOrFail(); // nswap parser.MoveNextOrFail(); // cnswap parser.MoveNextOrFail(); // exit_signal parser.MoveNextOrFail(); // processor parser.MoveNextOrFail(); // rt_priority parser.MoveNextOrFail(); // policy parser.MoveNextOrFail(); // delayacct_blkio_ticks parser.MoveNextOrFail(); // guest_time parser.MoveNextOrFail(); // cguest_time result = results; return true; }