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    }