Beispiel #1
0
        // -----------------------------
        // ---- PAL layer ends here ----
        // -----------------------------

        private static ProcessInfo CreateProcessInfo(int pid)
        {
            // Read /proc/pid/stat to get information about the process, and churn that into a ProcessInfo
            ProcessInfo pi;

            try
            {
                Interop.procfs.ParsedStat procFsStat = Interop.procfs.ReadStatFile(pid);
                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.
                };
            }
            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.
                return(null);
            }

            // Then read through /proc/pid/task/ to find each thread in the process...
            try
            {
                string tasksDir = Interop.procfs.GetTaskDirectoryPathForProcess(pid);
                foreach (string taskDir in Directory.EnumerateDirectories(tasksDir))
                {
                    string dirName = Path.GetFileName(taskDir);
                    int    tid;
                    if (int.TryParse(dirName, NumberStyles.Integer, CultureInfo.InvariantCulture, out tid))
                    {
                        // ...and read its associated /proc/pid/task/tid/stat file to create a ThreadInfo
                        Interop.procfs.ParsedStat stat = Interop.procfs.ReadStatFile(pid, tid);
                        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
                        });
                    }
                }
            }
            catch (IOException) { } // process and/or threads may go away by the time we try to read from them

            // Finally return what we've built up
            return(pi);
        }
        /// <summary>
        /// Creates a ProcessInfo from the data parsed from a /proc/pid/stat file and the associated tasks directory.
        /// </summary>
        internal static ProcessInfo CreateProcessInfo(ref Interop.procfs.ParsedStat procFsStat, ref Interop.procfs.ParsedStatus procFsStatus, string?processName = null)
        {
            int pid = procFsStat.pid;

            var pi = new ProcessInfo()
            {
                ProcessId        = pid,
                ProcessName      = processName ?? Process.GetUntruncatedProcessName(ref procFsStat) ?? string.Empty,
                BasePriority     = (int)procFsStat.nice,
                SessionId        = procFsStat.session,
                PoolPagedBytes   = (long)procFsStatus.VmSwap,
                VirtualBytes     = (long)procFsStatus.VmSize,
                VirtualBytesPeak = (long)procFsStatus.VmPeak,
                WorkingSetPeak   = (long)procFsStatus.VmHWM,
                WorkingSet       = (long)procFsStatus.VmRSS,
                PageFileBytes    = (long)procFsStatus.VmSwap,
                PrivateBytes     = (long)procFsStatus.VmData,
                // 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);

            try
            {
                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))
                    {
                        pi._threadInfoList.Add(new ThreadInfo()
                        {
                            _processId        = pid,
                            _threadId         = (ulong)tid,
                            _basePriority     = pi.BasePriority,
                            _currentPriority  = (int)stat.nice,
                            _startAddress     = IntPtr.Zero,
                            _threadState      = ProcFsStateToThreadState(stat.state),
                            _threadWaitReason = ThreadWaitReason.Unknown
                        });
                    }
                }
            }
            catch (IOException)
            {
                // Between the time that we get an ID and the time that we try to read the associated
                // directories and files in procfs, the process could be gone.
            }

            // Finally return what we've built up
            return(pi);
        }
Beispiel #3
0
        /// <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);
        }
Beispiel #4
0
        /// <summary>Gets the name that was used to start the process, or null if it could not be retrieved.</summary>
        /// <param name="stat">The stat for the target process.</param>
        internal static string GetUntruncatedProcessName(ref Interop.procfs.ParsedStat stat)
        {
            string cmdLineFilePath = Interop.procfs.GetCmdLinePathForProcess(stat.pid);

            byte[]? rentedArray = null;
            try
            {
                // bufferSize == 1 used to avoid unnecessary buffer in FileStream
                using (var fs = new FileStream(cmdLineFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 1, useAsync: false))
                {
                    Span <byte> buffer    = stackalloc byte[512];
                    int         bytesRead = 0;
                    while (true)
                    {
                        // Resize buffer if it was too small.
                        if (bytesRead == buffer.Length)
                        {
                            uint newLength = (uint)buffer.Length * 2;

                            byte[] tmp = ArrayPool <byte> .Shared.Rent((int)newLength);

                            buffer.CopyTo(tmp);
                            byte[]? toReturn = rentedArray;
                            buffer           = rentedArray = tmp;
                            if (toReturn != null)
                            {
                                ArrayPool <byte> .Shared.Return(toReturn);
                            }
                        }

                        Debug.Assert(bytesRead < buffer.Length);
                        int n = fs.Read(buffer.Slice(bytesRead));
                        bytesRead += n;

                        // cmdline contains the argv array separated by '\0' bytes.
                        // stat.comm contains a possibly truncated version of the process name.
                        // When the program is a native executable, the process name will be in argv[0].
                        // When the program is a script, argv[0] contains the interpreter, and argv[1] contains the script name.
                        Span <byte> argRemainder = buffer.Slice(0, bytesRead);
                        int         argEnd       = argRemainder.IndexOf((byte)'\0');
                        if (argEnd != -1)
                        {
                            // Check if argv[0] has the process name.
                            string?name = GetUntruncatedNameFromArg(argRemainder.Slice(0, argEnd), prefix: stat.comm);
                            if (name != null)
                            {
                                return(name);
                            }

                            // Check if argv[1] has the process name.
                            argRemainder = argRemainder.Slice(argEnd + 1);
                            argEnd       = argRemainder.IndexOf((byte)'\0');
                            if (argEnd != -1)
                            {
                                name = GetUntruncatedNameFromArg(argRemainder.Slice(0, argEnd), prefix: stat.comm);
                                return(name ?? stat.comm);
                            }
                        }

                        if (n == 0)
                        {
                            return(stat.comm);
                        }
                    }
                }
            }
            catch (IOException)
            {
                return(stat.comm);
            }
            finally
            {
                if (rentedArray != null)
                {
                    ArrayPool <byte> .Shared.Return(rentedArray);
                }
            }
Beispiel #5
0
        /// <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;

            // Get long process name if possible, otherwise use a fall back method.
            string procName = Path.GetFileName(Process.GetExePath(pid));

            if (string.IsNullOrEmpty(procName))
            {
                procName = procFsStat.comm;
            }

            var pi = new ProcessInfo()
            {
                ProcessId    = pid,
                ProcessName  = procName,
                BasePriority = (int)procFsStat.nice,
                VirtualBytes = (long)procFsStat.vsize,
                WorkingSet   = procFsStat.rss * Environment.SystemPageSize,
                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);

            try
            {
                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))
                    {
                        unsafe
                        {
                            pi._threadInfoList.Add(new ThreadInfo()
                            {
                                _processId        = pid,
                                _threadId         = (ulong)tid,
                                _basePriority     = pi.BasePriority,
                                _currentPriority  = (int)stat.nice,
                                _startAddress     = IntPtr.Zero,
                                _threadState      = ProcFsStateToThreadState(stat.state),
                                _threadWaitReason = ThreadWaitReason.Unknown
                            });
                        }
                    }
                }
            }
            catch (IOException)
            {
                // Between the time that we get an ID and the time that we try to read the associated
                // directories and files in procfs, the process could be gone.
            }

            // Finally return what we've built up
            return(pi);
        }