View Javadoc
1   /*
2    * Copyright 2021-2022 The OSHI Project Contributors
3    * SPDX-License-Identifier: MIT
4    */
5   package oshi.software.os.unix.openbsd;
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.openbsd.OpenBsdOSProcess.PsThreadColumns;
22  import oshi.util.ExecutingCommand;
23  import oshi.util.ParseUtil;
24  
25  /**
26   * OSThread implementation
27   */
28  @ThreadSafe
29  public class OpenBsdOSThread 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 OpenBsdOSThread(int processId, Map<PsThreadColumns, String> threadMap) {
45          super(processId);
46          updateAttributes(threadMap);
47      }
48  
49      public OpenBsdOSThread(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         String psCommand = "ps -aHwwxo " + OpenBsdOSProcess.PS_THREAD_COLUMNS + " -p " + getOwningProcessId();
118         // there is no switch for thread in ps command, hence filtering.
119         List<String> threadList = ExecutingCommand.runNative(psCommand);
120         String tidStr = 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.ARGS) && tidStr.equals(threadMap.get(PsThreadColumns.TID))) {
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.threadId = ParseUtil.parseIntOrDefault(threadMap.get(PsThreadColumns.TID), 0);
134         switch (threadMap.get(PsThreadColumns.STATE).charAt(0)) {
135         case 'R':
136             this.state = RUNNING;
137             break;
138         case 'I':
139         case 'S':
140             this.state = SLEEPING;
141             break;
142         case 'D':
143         case 'L':
144         case 'U':
145             this.state = WAITING;
146             break;
147         case 'Z':
148             this.state = ZOMBIE;
149             break;
150         case 'T':
151             this.state = STOPPED;
152             break;
153         default:
154             this.state = OTHER;
155             break;
156         }
157         // Avoid divide by zero for processes up less than a second
158         long elapsedTime = ParseUtil.parseDHMSOrDefault(threadMap.get(PsThreadColumns.ETIME), 0L);
159         this.upTime = elapsedTime < 1L ? 1L : elapsedTime;
160         long now = System.currentTimeMillis();
161         this.startTime = now - this.upTime;
162         // ps does not provide kerneltime on OpenBSD
163         this.kernelTime = 0L;
164         this.userTime = ParseUtil.parseDHMSOrDefault(threadMap.get(PsThreadColumns.CPUTIME), 0L);
165         this.startMemoryAddress = 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         this.name = threadMap.get(PsThreadColumns.ARGS);
173         return true;
174     }
175 }