1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System.Collections.Generic; 6 using System.IO; 7 using System.Runtime.InteropServices; 8 9 namespace System.Diagnostics 10 { 11 internal static partial class ProcessManager 12 { 13 /// <summary>Gets the IDs of all processes on the current machine.</summary> GetProcessIds()14 public static int[] GetProcessIds() 15 { 16 return Interop.libproc.proc_listallpids(); 17 } 18 GetProcPath(int processId)19 private static string GetProcPath(int processId) 20 { 21 return Interop.libproc.proc_pidpath(processId); 22 } 23 24 // ----------------------------- 25 // ---- PAL layer ends here ---- 26 // ----------------------------- 27 CreateProcessInfo(int pid)28 private static ProcessInfo CreateProcessInfo(int pid) 29 { 30 // Negative PIDs aren't valid 31 if (pid < 0) 32 { 33 throw new ArgumentOutOfRangeException(nameof(pid)); 34 } 35 36 ProcessInfo procInfo = new ProcessInfo() 37 { 38 ProcessId = pid 39 }; 40 41 // Try to get the task info. This can fail if the user permissions don't permit 42 // this user context to query the specified process 43 Interop.libproc.proc_taskallinfo? info = Interop.libproc.GetProcessInfoById(pid); 44 if (info.HasValue) 45 { 46 // Set the values we have; all the other values don't have meaning or don't exist on OSX 47 Interop.libproc.proc_taskallinfo temp = info.Value; 48 unsafe { procInfo.ProcessName = Marshal.PtrToStringAnsi(new IntPtr(temp.pbsd.pbi_comm)); } 49 procInfo.BasePriority = temp.pbsd.pbi_nice; 50 procInfo.VirtualBytes = (long)temp.ptinfo.pti_virtual_size; 51 procInfo.WorkingSet = (long)temp.ptinfo.pti_resident_size; 52 } 53 54 // Get the sessionId for the given pid, getsid returns -1 on error 55 int sessionId = Interop.Sys.GetSid(pid); 56 if (sessionId != -1) 57 procInfo.SessionId = sessionId; 58 59 // Create a threadinfo for each thread in the process 60 List<KeyValuePair<ulong, Interop.libproc.proc_threadinfo?>> lstThreads = Interop.libproc.GetAllThreadsInProcess(pid); 61 foreach (KeyValuePair<ulong, Interop.libproc.proc_threadinfo?> t in lstThreads) 62 { 63 var ti = new ThreadInfo() 64 { 65 _processId = pid, 66 _threadId = t.Key, 67 _basePriority = procInfo.BasePriority, 68 _startAddress = IntPtr.Zero 69 }; 70 71 // Fill in additional info if we were able to retrieve such data about the thread 72 if (t.Value.HasValue) 73 { 74 ti._currentPriority = t.Value.Value.pth_curpri; 75 ti._threadState = ConvertOsxThreadRunStateToThreadState((Interop.libproc.ThreadRunState)t.Value.Value.pth_run_state); 76 ti._threadWaitReason = ConvertOsxThreadFlagsToWaitReason((Interop.libproc.ThreadFlags)t.Value.Value.pth_flags); 77 } 78 79 procInfo._threadInfoList.Add(ti); 80 } 81 82 return procInfo; 83 } 84 85 // ---------------------------------- 86 // ---- Unix PAL layer ends here ---- 87 // ---------------------------------- 88 ConvertOsxThreadRunStateToThreadState(Interop.libproc.ThreadRunState state)89 private static System.Diagnostics.ThreadState ConvertOsxThreadRunStateToThreadState(Interop.libproc.ThreadRunState state) 90 { 91 switch (state) 92 { 93 case Interop.libproc.ThreadRunState.TH_STATE_RUNNING: 94 return System.Diagnostics.ThreadState.Running; 95 case Interop.libproc.ThreadRunState.TH_STATE_STOPPED: 96 return System.Diagnostics.ThreadState.Terminated; 97 case Interop.libproc.ThreadRunState.TH_STATE_HALTED: 98 return System.Diagnostics.ThreadState.Wait; 99 case Interop.libproc.ThreadRunState.TH_STATE_UNINTERRUPTIBLE: 100 return System.Diagnostics.ThreadState.Running; 101 case Interop.libproc.ThreadRunState.TH_STATE_WAITING: 102 return System.Diagnostics.ThreadState.Standby; 103 default: 104 throw new ArgumentOutOfRangeException(nameof(state)); 105 } 106 } 107 ConvertOsxThreadFlagsToWaitReason(Interop.libproc.ThreadFlags flags)108 private static System.Diagnostics.ThreadWaitReason ConvertOsxThreadFlagsToWaitReason(Interop.libproc.ThreadFlags flags) 109 { 110 // Since ThreadWaitReason isn't a flag, we have to do a mapping and will lose some information. 111 if ((flags & Interop.libproc.ThreadFlags.TH_FLAGS_SWAPPED) == Interop.libproc.ThreadFlags.TH_FLAGS_SWAPPED) 112 return System.Diagnostics.ThreadWaitReason.PageOut; 113 else 114 return System.Diagnostics.ThreadWaitReason.Unknown; // There isn't a good mapping for anything else 115 } 116 } 117 } 118