View Javadoc
1   /*
2    * Copyright 2020-2022 The OSHI Project Contributors
3    * SPDX-License-Identifier: MIT
4    */
5   package oshi.software.os.unix.freebsd;
6   
7   import static oshi.software.os.OSProcess.State.INVALID;
8   import static oshi.software.os.OSProcess.State.OTHER;
9   import static oshi.software.os.OSProcess.State.RUNNING;
10  import static oshi.software.os.OSProcess.State.SLEEPING;
11  import static oshi.software.os.OSProcess.State.STOPPED;
12  import static oshi.software.os.OSProcess.State.WAITING;
13  import static oshi.software.os.OSProcess.State.ZOMBIE;
14  
15  import java.util.List;
16  import java.util.Map;
17  
18  import oshi.annotation.concurrent.ThreadSafe;
19  import oshi.software.common.AbstractOSThread;
20  import oshi.software.os.OSProcess;
21  import oshi.software.os.unix.freebsd.FreeBsdOSProcess.PsThreadColumns;
22  import oshi.util.ExecutingCommand;
23  import oshi.util.ParseUtil;
24  
25  /**
26   * OSThread implementation
27   */
28  @ThreadSafe
29  public class FreeBsdOSThread extends AbstractOSThread {
30  
31      private int threadId;
32      private String name = "";
33      private OSProcess.State state = INVALID;
34      private long minorFaults;
35      private long majorFaults;
36      private long startMemoryAddress;
37      private long contextSwitches;
38      private long kernelTime;
39      private long userTime;
40      private long startTime;
41      private long upTime;
42      private int priority;
43  
44      public FreeBsdOSThread(int processId, Map<PsThreadColumns, String> threadMap) {
45          super(processId);
46          updateAttributes(threadMap);
47      }
48  
49      public FreeBsdOSThread(int processId, int threadId) {
50          super(processId);
51          this.threadId = threadId;
52          updateAttributes();
53      }
54  
55      @Override
56      public int getThreadId() {
57          return this.threadId;
58      }
59  
60      @Override
61      public String getName() {
62          return this.name;
63      }
64  
65      @Override
66      public OSProcess.State getState() {
67          return this.state;
68      }
69  
70      @Override
71      public long getStartMemoryAddress() {
72          return this.startMemoryAddress;
73      }
74  
75      @Override
76      public long getContextSwitches() {
77          return this.contextSwitches;
78      }
79  
80      @Override
81      public long getMinorFaults() {
82          return this.minorFaults;
83      }
84  
85      @Override
86      public long getMajorFaults() {
87          return this.majorFaults;
88      }
89  
90      @Override
91      public long getKernelTime() {
92          return this.kernelTime;
93      }
94  
95      @Override
96      public long getUserTime() {
97          return this.userTime;
98      }
99  
100     @Override
101     public long getUpTime() {
102         return this.upTime;
103     }
104 
105     @Override
106     public long getStartTime() {
107         return this.startTime;
108     }
109 
110     @Override
111     public int getPriority() {
112         return this.priority;
113     }
114 
115     @Override
116     public boolean updateAttributes() {
117         List<String> threadList = ExecutingCommand
118                 .runNative("ps -awwxo " + FreeBsdOSProcess.PS_THREAD_COLUMNS + " -H -p " + getOwningProcessId());
119         // there is no switch for thread in ps command, hence filtering.
120         String lwpStr = Integer.toString(this.threadId);
121         for (String psOutput : threadList) {
122             Map<PsThreadColumns, String> threadMap = ParseUtil.stringToEnumMap(PsThreadColumns.class, psOutput.trim(),
123                     ' ');
124             if (threadMap.containsKey(PsThreadColumns.PRI) && lwpStr.equals(threadMap.get(PsThreadColumns.LWP))) {
125                 return updateAttributes(threadMap);
126             }
127         }
128         this.state = INVALID;
129         return false;
130     }
131 
132     private boolean updateAttributes(Map<PsThreadColumns, String> threadMap) {
133         this.name = threadMap.get(PsThreadColumns.TDNAME);
134         this.threadId = ParseUtil.parseIntOrDefault(threadMap.get(PsThreadColumns.LWP), 0);
135         switch (threadMap.get(PsThreadColumns.STATE).charAt(0)) {
136         case 'R':
137             this.state = RUNNING;
138             break;
139         case 'I':
140         case 'S':
141             this.state = SLEEPING;
142             break;
143         case 'D':
144         case 'L':
145         case 'U':
146             this.state = WAITING;
147             break;
148         case 'Z':
149             this.state = ZOMBIE;
150             break;
151         case 'T':
152             this.state = STOPPED;
153             break;
154         default:
155             this.state = OTHER;
156             break;
157         }
158         long elapsedTime = ParseUtil.parseDHMSOrDefault(threadMap.get(PsThreadColumns.ETIMES), 0L);
159         // Avoid divide by zero for processes up less than a second
160         this.upTime = elapsedTime < 1L ? 1L : elapsedTime;
161         long now = System.currentTimeMillis();
162         this.startTime = now - this.upTime;
163         this.kernelTime = ParseUtil.parseDHMSOrDefault(threadMap.get(PsThreadColumns.SYSTIME), 0L);
164         this.userTime = ParseUtil.parseDHMSOrDefault(threadMap.get(PsThreadColumns.TIME), 0L) - this.kernelTime;
165         this.startMemoryAddress = ParseUtil.hexStringToLong(threadMap.get(PsThreadColumns.TDADDR), 0L);
166         long nonVoluntaryContextSwitches = ParseUtil.parseLongOrDefault(threadMap.get(PsThreadColumns.NIVCSW), 0L);
167         long voluntaryContextSwitches = ParseUtil.parseLongOrDefault(threadMap.get(PsThreadColumns.NVCSW), 0L);
168         this.contextSwitches = voluntaryContextSwitches + nonVoluntaryContextSwitches;
169         this.majorFaults = ParseUtil.parseLongOrDefault(threadMap.get(PsThreadColumns.MAJFLT), 0L);
170         this.minorFaults = ParseUtil.parseLongOrDefault(threadMap.get(PsThreadColumns.MINFLT), 0L);
171         this.priority = ParseUtil.parseIntOrDefault(threadMap.get(PsThreadColumns.PRI), 0);
172         return true;
173     }
174 }