View Javadoc
1   /*
2    * Copyright 2020-2022 The OSHI Project Contributors
3    * SPDX-License-Identifier: MIT
4    */
5   package oshi.driver.mac;
6   
7   import static oshi.software.os.OSProcess.State.OTHER;
8   import static oshi.software.os.OSProcess.State.RUNNING;
9   import static oshi.software.os.OSProcess.State.SLEEPING;
10  import static oshi.software.os.OSProcess.State.STOPPED;
11  import static oshi.software.os.OSProcess.State.WAITING;
12  import static oshi.software.os.OSProcess.State.ZOMBIE;
13  
14  import java.util.ArrayList;
15  import java.util.List;
16  import java.util.regex.Matcher;
17  import java.util.regex.Pattern;
18  import java.util.stream.Collectors;
19  
20  import oshi.annotation.concurrent.Immutable;
21  import oshi.annotation.concurrent.ThreadSafe;
22  import oshi.software.os.OSProcess.State;
23  import oshi.util.ExecutingCommand;
24  import oshi.util.ParseUtil;
25  
26  /**
27   * Utility to query threads for a process
28   */
29  @ThreadSafe
30  public final class ThreadInfo {
31  
32      private static final Pattern PS_M = Pattern.compile(
33              "\\D+(\\d+).+(\\d+\\.\\d)\\s+(\\w)\\s+(\\d+)\\D+(\\d+:\\d{2}\\.\\d{2})\\s+(\\d+:\\d{2}\\.\\d{2}).+");
34  
35      private ThreadInfo() {
36      }
37  
38      public static List<ThreadStats> queryTaskThreads(int pid) {
39          String pidStr = " " + pid + " ";
40          List<ThreadStats> taskThreads = new ArrayList<>();
41          // Only way to get thread info without root permissions
42          // Using the M switch gives all threads with no possibility to filter
43          List<String> psThread = ExecutingCommand.runNative("ps -awwxM").stream().filter(s -> s.contains(pidStr))
44                  .collect(Collectors.toList());
45          int tid = 0;
46          for (String thread : psThread) {
47              Matcher m = PS_M.matcher(thread);
48              if (m.matches() && pid == ParseUtil.parseIntOrDefault(m.group(1), -1)) {
49                  double cpu = ParseUtil.parseDoubleOrDefault(m.group(2), 0d);
50                  char state = m.group(3).charAt(0);
51                  int pri = ParseUtil.parseIntOrDefault(m.group(4), 0);
52                  long sTime = ParseUtil.parseDHMSOrDefault(m.group(5), 0L);
53                  long uTime = ParseUtil.parseDHMSOrDefault(m.group(6), 0L);
54                  taskThreads.add(new ThreadStats(tid++, cpu, state, sTime, uTime, pri));
55              }
56          }
57          return taskThreads;
58      }
59  
60      /**
61       * Class to encapsulate mach thread info
62       */
63      @Immutable
64      public static class ThreadStats {
65          private final int threadId;
66          private final long userTime;
67          private final long systemTime;
68          private final long upTime;
69          private final State state;
70          private final int priority;
71  
72          public ThreadStats(int tid, double cpu, char state, long sTime, long uTime, int pri) {
73              this.threadId = tid;
74              this.userTime = uTime;
75              this.systemTime = sTime;
76              // user + system / uptime = cpu/100
77              // so: uptime = user+system / cpu/100
78              this.upTime = (long) ((uTime + sTime) / (cpu / 100d + 0.0005));
79              switch (state) {
80              case 'I':
81              case 'S':
82                  this.state = SLEEPING;
83                  break;
84              case 'U':
85                  this.state = WAITING;
86                  break;
87              case 'R':
88                  this.state = RUNNING;
89                  break;
90              case 'Z':
91                  this.state = ZOMBIE;
92                  break;
93              case 'T':
94                  this.state = STOPPED;
95                  break;
96              default:
97                  this.state = OTHER;
98                  break;
99              }
100             this.priority = pri;
101         }
102 
103         /**
104          * @return the threadId
105          */
106         public int getThreadId() {
107             return threadId;
108         }
109 
110         /**
111          * @return the userTime
112          */
113         public long getUserTime() {
114             return userTime;
115         }
116 
117         /**
118          * @return the systemTime
119          */
120         public long getSystemTime() {
121             return systemTime;
122         }
123 
124         /**
125          * @return the upTime
126          */
127         public long getUpTime() {
128             return upTime;
129         }
130 
131         /**
132          * @return the state
133          */
134         public State getState() {
135             return state;
136         }
137 
138         /**
139          * @return the priority
140          */
141         public int getPriority() {
142             return priority;
143         }
144     }
145 }