1
2
3
4
5 package oshi.software.os.linux;
6
7 import java.util.Locale;
8 import java.util.Map;
9
10 import oshi.annotation.concurrent.ThreadSafe;
11 import oshi.driver.linux.proc.ProcessStat;
12 import oshi.software.common.AbstractOSThread;
13 import oshi.software.os.OSProcess.State;
14 import oshi.util.FileUtil;
15 import oshi.util.ParseUtil;
16 import oshi.util.platform.linux.ProcPath;
17
18
19
20
21 @ThreadSafe
22 public class LinuxOSThread extends AbstractOSThread {
23
24 private static final int[] PROC_TASK_STAT_ORDERS = new int[LinuxOSThread.ThreadPidStat.values().length];
25 static {
26 for (LinuxOSThread.ThreadPidStat stat : LinuxOSThread.ThreadPidStat.values()) {
27
28
29 PROC_TASK_STAT_ORDERS[stat.ordinal()] = stat.getOrder() - 1;
30 }
31 }
32
33 private final int threadId;
34 private String name;
35 private State state = State.INVALID;
36 private long minorFaults;
37 private long majorFaults;
38 private long startMemoryAddress;
39 private long contextSwitches;
40 private long kernelTime;
41 private long userTime;
42 private long startTime;
43 private long upTime;
44 private int priority;
45
46 public LinuxOSThread(int processId, int tid) {
47 super(processId);
48 this.threadId = tid;
49 updateAttributes();
50 }
51
52 @Override
53 public int getThreadId() {
54 return this.threadId;
55 }
56
57 @Override
58 public String getName() {
59 return this.name;
60 }
61
62 @Override
63 public State getState() {
64 return this.state;
65 }
66
67 @Override
68 public long getStartTime() {
69 return this.startTime;
70 }
71
72 @Override
73 public long getStartMemoryAddress() {
74 return this.startMemoryAddress;
75 }
76
77 @Override
78 public long getContextSwitches() {
79 return this.contextSwitches;
80 }
81
82 @Override
83 public long getMinorFaults() {
84 return this.minorFaults;
85 }
86
87 @Override
88 public long getMajorFaults() {
89 return this.majorFaults;
90 }
91
92 @Override
93 public long getKernelTime() {
94 return this.kernelTime;
95 }
96
97 @Override
98 public long getUserTime() {
99 return this.userTime;
100 }
101
102 @Override
103 public long getUpTime() {
104 return this.upTime;
105 }
106
107 @Override
108 public int getPriority() {
109 return this.priority;
110 }
111
112 @Override
113 public boolean updateAttributes() {
114 this.name = FileUtil.getStringFromFile(
115 String.format(Locale.ROOT, ProcPath.TASK_COMM, this.getOwningProcessId(), this.threadId));
116 Map<String, String> status = FileUtil.getKeyValueMapFromFile(
117 String.format(Locale.ROOT, ProcPath.TASK_STATUS, this.getOwningProcessId(), this.threadId), ":");
118 String stat = FileUtil.getStringFromFile(
119 String.format(Locale.ROOT, ProcPath.TASK_STAT, this.getOwningProcessId(), this.threadId));
120 if (stat.isEmpty()) {
121 this.state = State.INVALID;
122 return false;
123 }
124 long now = System.currentTimeMillis();
125 long[] statArray = ParseUtil.parseStringToLongArray(stat, PROC_TASK_STAT_ORDERS,
126 ProcessStat.PROC_PID_STAT_LENGTH, ' ');
127
128
129
130
131 this.startTime = (LinuxOperatingSystem.BOOTTIME * LinuxOperatingSystem.getHz()
132 + statArray[LinuxOSThread.ThreadPidStat.START_TIME.ordinal()]) * 1000L / LinuxOperatingSystem.getHz();
133
134
135
136 if (this.startTime >= now) {
137 this.startTime = now - 1;
138 }
139 this.minorFaults = statArray[ThreadPidStat.MINOR_FAULTS.ordinal()];
140 this.majorFaults = statArray[ThreadPidStat.MAJOR_FAULT.ordinal()];
141 this.startMemoryAddress = statArray[ThreadPidStat.START_CODE.ordinal()];
142 long voluntaryContextSwitches = ParseUtil.parseLongOrDefault(status.get("voluntary_ctxt_switches"), 0L);
143 long nonVoluntaryContextSwitches = ParseUtil.parseLongOrDefault(status.get("nonvoluntary_ctxt_switches"), 0L);
144 this.contextSwitches = voluntaryContextSwitches + nonVoluntaryContextSwitches;
145 this.state = ProcessStat.getState(status.getOrDefault("State", "U").charAt(0));
146 this.kernelTime = statArray[ThreadPidStat.KERNEL_TIME.ordinal()] * 1000L / LinuxOperatingSystem.getHz();
147 this.userTime = statArray[ThreadPidStat.USER_TIME.ordinal()] * 1000L / LinuxOperatingSystem.getHz();
148 this.upTime = now - startTime;
149 this.priority = (int) statArray[ThreadPidStat.PRIORITY.ordinal()];
150 return true;
151 }
152
153
154
155
156
157 private enum ThreadPidStat {
158
159
160 PPID(4), MINOR_FAULTS(10), MAJOR_FAULT(12), USER_TIME(14), KERNEL_TIME(15), PRIORITY(18), THREAD_COUNT(20),
161 START_TIME(22), VSZ(23), RSS(24), START_CODE(26);
162
163 private final int order;
164
165 ThreadPidStat(int order) {
166 this.order = order;
167 }
168
169 public int getOrder() {
170 return this.order;
171 }
172 }
173 }