001 package edu.rice.cs.cunit.record.graph;
002
003 import com.sun.jdi.ObjectReference;
004 import com.sun.jdi.StackFrame;
005 import com.sun.jdi.ThreadReference;
006 import edu.rice.cs.cunit.record.IThreadInfo;
007
008 import java.util.*;
009
010 /**
011 * Information about a thread.
012 * Essentially captures the information that a ThreadReference contains, but this class allows the information to be
013 * stored so that the monitored VM can be resumed.
014 *
015 * @author Mathias Ricken
016 */
017 public class ThreadInfo implements IThreadInfo {
018 /**
019 * Unique ID of thread.
020 */
021 long _threadID;
022
023 /**
024 * Thread Status.
025 */
026 int _status;
027
028 /**
029 * Name of the thread.
030 */
031 String _name;
032
033 /**
034 * Unique id of the lock the thread is waiting for, or null if none.
035 */
036 Long _contendedLockId;
037
038 /**
039 * Set of the unique ids of locks owned.
040 */
041 Set<Long> _ownedLockIds;
042
043 /**
044 * List of state frame entries.
045 */
046 LinkedList<StackFrameInfo> _stackFrame;
047
048 /**
049 * Constructor for thread info.
050 * @param uniqueId thread's unique id
051 * @param status thread status
052 * @param name thread name
053 * @param contendedLockId id of contended lock
054 * @param ownedLockIds set of ids of ownned locks
055 * @param stackFrame list of state frame infos
056 */
057 public ThreadInfo(long uniqueId,
058 int status,
059 String name,
060 Long contendedLockId,
061 Set<Long> ownedLockIds,
062 List<StackFrameInfo> stackFrame) {
063 _threadID = uniqueId;
064 _status = status;
065 _name = name;
066 _contendedLockId = contendedLockId;
067 _ownedLockIds = new HashSet<Long>(ownedLockIds);
068 _stackFrame = new LinkedList<StackFrameInfo>(stackFrame);
069 }
070
071 /**
072 * Constructor for thread info.
073 * @param tRef Thread Reference
074 */
075 public ThreadInfo(ThreadReference tRef) {
076 if (null==tRef) {
077 _threadID = 0;
078 _status = ThreadReference.THREAD_STATUS_UNKNOWN;
079 _name = "null";
080 _contendedLockId = null;
081 _ownedLockIds = new HashSet<Long>();
082 _stackFrame = new LinkedList<StackFrameInfo>();
083 }
084 else {
085 _threadID = tRef.uniqueID();
086 try {
087 _status = tRef.status();
088 }
089 catch(Exception e) {
090 _status = ThreadReference.THREAD_STATUS_UNKNOWN;
091 }
092 try {
093 _name = tRef.name();
094 }
095 catch(Exception e) {
096 _name = "???";
097 }
098 try {
099 ObjectReference objRef = tRef.currentContendedMonitor();
100 if (objRef!=null) {
101 _contendedLockId = objRef.uniqueID();
102 }
103 else {
104 _contendedLockId = null;
105 }
106 }
107 catch(Exception e) {
108 _contendedLockId = null;
109 }
110 try {
111 _ownedLockIds = new HashSet<Long>(tRef.ownedMonitors().size());
112 for (ObjectReference or:tRef.ownedMonitors()) {
113 _ownedLockIds.add(or.uniqueID());
114 }
115 }
116 catch(Exception e) {
117 _ownedLockIds = new HashSet<Long>();
118 }
119 try {
120 _stackFrame = new LinkedList<StackFrameInfo>();
121 for (StackFrame sf:tRef.frames()) {
122 _stackFrame.addFirst(new StackFrameInfo(sf));
123 }
124 }
125 catch(Exception e) {
126 _stackFrame = new LinkedList<StackFrameInfo>();
127 }
128 }
129 }
130
131 /**
132 * Returns the unique id of this thread.
133 * @return unique id
134 */
135 public long getThreadID() {
136 return _threadID;
137 }
138
139 /**
140 * Returns the status of the thread.
141 * @return status
142 */
143 public int getStatus() {
144 return _status;
145 }
146
147 /**
148 * Sets the status of the thread.
149 * @param status new status
150 */
151 public void setStatus(int status) {
152 _status = status;
153 }
154
155 /**
156 * Returns the name of the thread.
157 * @return name
158 */
159 public String getName() {
160 return _name;
161 }
162
163 /**
164 * Returns the id of the contended lock, or null if none.
165 * @return id of the contended lock, or null if none
166 */
167 public Long getContendedLockID() {
168 return _contendedLockId;
169 }
170
171 /**
172 * Sets the id of the contented lock, or null if none.
173 * @param contendedLockId new lock id, or null if none
174 */
175 public void setContendedLockId(Long contendedLockId) {
176 _contendedLockId = contendedLockId;
177 }
178
179 /**
180 * Returns a set with the ids of the owned locks.
181 * @return list with lock ids
182 */
183 public Set<Long> getOwnedLockIDs() {
184 return _ownedLockIds;
185 }
186
187 /**
188 * Returns a list with state frame information.
189 * @return list with state frame info
190 */
191 public List<StackFrameInfo> getStackFrame() {
192 return _stackFrame;
193 }
194
195 /**
196 * Returns a string representation of the object.
197 * @return a string representation of the object.
198 */
199 public String toString() {
200 StringBuilder sb = new StringBuilder();
201 sb.append(_threadID);
202 sb.append(": ");
203 sb.append(_name);
204 sb.append(", ");
205 switch(_status) {
206 case ThreadReference.THREAD_STATUS_MONITOR:
207 sb.append("MONITOR WAITING");
208 break;
209 case ThreadReference.THREAD_STATUS_NOT_STARTED:
210 sb.append("NOT STARTED");
211 break;
212 case ThreadReference.THREAD_STATUS_RUNNING:
213 sb.append("RUNNING");
214 break;
215 case ThreadReference.THREAD_STATUS_SLEEPING :
216 sb.append("SLEEPING");
217 break;
218 case ThreadReference.THREAD_STATUS_WAIT:
219 sb.append("WAITING");
220 break;
221 case ThreadReference.THREAD_STATUS_ZOMBIE:
222 sb.append("ZOMBIE");
223 break;
224 default:
225 sb.append("unknown");
226 break;
227 }
228 return sb.toString();
229 }
230
231 /**
232 * Returns a very verbose string representation of the object.
233 * @param lockInfo map from unique ids to lock information
234 * @return a verbose string representation of the object.
235 */
236 public String toStringExtended(Map<Long, LockInfo> lockInfo) {
237 StringBuilder sb = new StringBuilder();
238 sb.append(_threadID);
239 sb.append(": ");
240 sb.append(_name);
241 sb.append(", ");
242 switch(_status) {
243 case ThreadReference.THREAD_STATUS_MONITOR:
244 sb.append("MONITOR WAITING");
245 break;
246 case ThreadReference.THREAD_STATUS_NOT_STARTED:
247 sb.append("NOT STARTED");
248 break;
249 case ThreadReference.THREAD_STATUS_RUNNING:
250 sb.append("RUNNING");
251 break;
252 case ThreadReference.THREAD_STATUS_SLEEPING :
253 sb.append("SLEEPING");
254 break;
255 case ThreadReference.THREAD_STATUS_WAIT:
256 sb.append("WAITING");
257 break;
258 case ThreadReference.THREAD_STATUS_ZOMBIE:
259 sb.append("ZOMBIE");
260 break;
261 default:
262 sb.append("unknown");
263 break;
264 }
265 if (null!=_stackFrame) {
266 if (_stackFrame.size()>0) {
267 sb.append(", at ");
268 sb.append(_stackFrame.get(0).getSourcePath());
269 sb.append(":");
270 sb.append(_stackFrame.get(0).getLineNumber());
271 }
272 sb.append(")\nStack:\n");
273 for(StackFrameInfo sfi:_stackFrame) {
274 sb.append(sfi.toString());
275 sb.append("\n");
276 }
277 }
278 sb.append("\n");
279 sb.append("Owned locks:\n");
280 if (_ownedLockIds.size()==0) {
281 sb.append("none\n");
282 }
283 else {
284 for(Long id:_ownedLockIds) {
285 LockInfo li = lockInfo.get(id);
286 if (li != null) {
287 sb.append(li);
288 }
289 else {
290 sb.append("null (id=");
291 sb.append(id);
292 }
293 sb.append("\n");
294 }
295 }
296 sb.append("Contended lock:\n");
297 if (_contendedLockId==null) {
298 sb.append("none");
299 }
300 else {
301 LockInfo li = lockInfo.get(_contendedLockId);
302 if (li != null) {
303 sb.append(lockInfo.get(li));
304 }
305 else {
306 sb.append("null (id=");
307 sb.append(_contendedLockId);
308 }
309 }
310 return sb.toString();
311 }
312
313 /**
314 * Returns a compact string representation of the object.
315 * @return a compact string representation of the object.
316 */
317 public String toStringVerbose() {
318 StringBuilder sb = new StringBuilder();
319 sb.append(toString());
320 sb.append("\n");
321 sb.append("Contended: ");
322 sb.append(getContendedLockID());
323 sb.append("\n");
324 sb.append("Owned:");
325 for(Long id: getOwnedLockIDs()) {
326 sb.append("\t");
327 sb.append(id);
328 }
329 return sb.toString();
330 }
331 }