0
|
1 /*
|
|
2 * Copyright 2002-2005 Sun Microsystems, Inc. All Rights Reserved.
|
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
4 *
|
|
5 * This code is free software; you can redistribute it and/or modify it
|
|
6 * under the terms of the GNU General Public License version 2 only, as
|
|
7 * published by the Free Software Foundation.
|
|
8 *
|
|
9 * This code is distributed in the hope that it will be useful, but WITHOUT
|
|
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
12 * version 2 for more details (a copy is included in the LICENSE file that
|
|
13 * accompanied this code).
|
|
14 *
|
|
15 * You should have received a copy of the GNU General Public License version
|
|
16 * 2 along with this work; if not, write to the Free Software Foundation,
|
|
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
18 *
|
|
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
|
20 * CA 95054 USA or visit www.sun.com if you need additional information or
|
|
21 * have any questions.
|
|
22 *
|
|
23 */
|
|
24
|
|
25 package sun.jvm.hotspot.jdi;
|
|
26
|
|
27 import sun.jvm.hotspot.debugger.OopHandle;
|
|
28 import sun.jvm.hotspot.runtime.VMObject;
|
|
29 import sun.jvm.hotspot.runtime.JavaThread;
|
|
30 import sun.jvm.hotspot.runtime.OSThread;
|
|
31 //import sun.jvm.hotspot.runtime.StackFrameStream;
|
|
32 import sun.jvm.hotspot.runtime.JavaVFrame;
|
|
33 import sun.jvm.hotspot.runtime.JavaThreadState;
|
|
34 import sun.jvm.hotspot.runtime.MonitorInfo;
|
|
35 import sun.jvm.hotspot.runtime.ObjectMonitor;
|
|
36 import sun.jvm.hotspot.oops.Oop;
|
|
37 import sun.jvm.hotspot.oops.ObjectHeap;
|
|
38 import sun.jvm.hotspot.oops.Instance;
|
|
39 import sun.jvm.hotspot.oops.OopUtilities;
|
|
40 import sun.jvm.hotspot.oops.Klass;
|
|
41 import sun.jvm.hotspot.utilities.Assert;
|
|
42 import com.sun.jdi.*;
|
|
43 import java.util.*;
|
|
44
|
|
45 public class ThreadReferenceImpl extends ObjectReferenceImpl
|
|
46 implements ThreadReference, /* imports */ JVMTIThreadState {
|
|
47
|
|
48 private JavaThread myJavaThread;
|
|
49 private ArrayList frames; // StackFrames
|
|
50 private List ownedMonitors; // List<ObjectReferenceImpl>
|
|
51 private List ownedMonitorsInfo; // List<MonitorInfo>
|
|
52 private ObjectReferenceImpl currentContendingMonitor;
|
|
53
|
|
54 ThreadReferenceImpl(VirtualMachine aVm, sun.jvm.hotspot.runtime.JavaThread aRef) {
|
|
55 // We are given a JavaThread and save it in our myJavaThread field.
|
|
56 // But, our parent class is an ObjectReferenceImpl so we need an Oop
|
|
57 // for it. JavaThread is a wrapper around a Thread Oop so we get
|
|
58 // that Oop and give it to our super.
|
|
59 // We can get it back again by calling ref().
|
|
60 super(aVm, (Instance)aRef.getThreadObj());
|
|
61 myJavaThread = aRef;
|
|
62 }
|
|
63
|
|
64 ThreadReferenceImpl(VirtualMachine vm, Instance oRef) {
|
|
65 // Instance must be of type java.lang.Thread
|
|
66 super(vm, oRef);
|
|
67
|
|
68 // JavaThread retrieved from java.lang.Thread instance may be null.
|
|
69 // This is the case for threads not-started and for zombies. Wherever
|
|
70 // appropriate, check for null instead of resulting in NullPointerException.
|
|
71 myJavaThread = OopUtilities.threadOopGetJavaThread(oRef);
|
|
72 }
|
|
73
|
|
74 // return value may be null. refer to the comment in constructor.
|
|
75 JavaThread getJavaThread() {
|
|
76 return myJavaThread;
|
|
77 }
|
|
78
|
|
79 protected String description() {
|
|
80 return "ThreadReference " + uniqueID();
|
|
81 }
|
|
82
|
|
83 /**
|
|
84 * Note that we only cache the name string while suspended because
|
|
85 * it can change via Thread.setName arbitrarily
|
|
86 */
|
|
87 public String name() {
|
|
88 return OopUtilities.threadOopGetName(ref());
|
|
89 }
|
|
90
|
|
91 public void suspend() {
|
|
92 vm.throwNotReadOnlyException("ThreadReference.suspend()");
|
|
93 }
|
|
94
|
|
95 public void resume() {
|
|
96 vm.throwNotReadOnlyException("ThreadReference.resume()");
|
|
97 }
|
|
98
|
|
99 public int suspendCount() {
|
|
100 // all threads are "suspended" when we attach to process or core.
|
|
101 // we interpret this as one suspend.
|
|
102 return 1;
|
|
103 }
|
|
104
|
|
105 public void stop(ObjectReference throwable) throws InvalidTypeException {
|
|
106 vm.throwNotReadOnlyException("ThreadReference.stop()");
|
|
107 }
|
|
108
|
|
109 public void interrupt() {
|
|
110 vm.throwNotReadOnlyException("ThreadReference.interrupt()");
|
|
111 }
|
|
112
|
|
113 // refer to jvmtiEnv::GetThreadState
|
|
114 private int jvmtiGetThreadState() {
|
|
115 // get most state bits
|
|
116 int state = OopUtilities.threadOopGetThreadStatus(ref());
|
|
117 // add more state bits
|
|
118 if (myJavaThread != null) {
|
|
119 JavaThreadState jts = myJavaThread.getThreadState();
|
|
120 if (myJavaThread.isBeingExtSuspended()) {
|
|
121 state |= JVMTI_THREAD_STATE_SUSPENDED;
|
|
122 }
|
|
123 if (jts == JavaThreadState.IN_NATIVE) {
|
|
124 state |= JVMTI_THREAD_STATE_IN_NATIVE;
|
|
125 }
|
|
126 OSThread osThread = myJavaThread.getOSThread();
|
|
127 if (osThread != null && osThread.interrupted()) {
|
|
128 state |= JVMTI_THREAD_STATE_INTERRUPTED;
|
|
129 }
|
|
130 }
|
|
131 return state;
|
|
132 }
|
|
133
|
|
134 public int status() {
|
|
135 int state = jvmtiGetThreadState();
|
|
136 int status = THREAD_STATUS_UNKNOWN;
|
|
137 // refer to map2jdwpThreadStatus in util.c (back-end)
|
|
138 if (! ((state & JVMTI_THREAD_STATE_ALIVE) != 0) ) {
|
|
139 if ((state & JVMTI_THREAD_STATE_TERMINATED) != 0) {
|
|
140 status = THREAD_STATUS_ZOMBIE;
|
|
141 } else {
|
|
142 status = THREAD_STATUS_NOT_STARTED;
|
|
143 }
|
|
144 } else {
|
|
145 if ((state & JVMTI_THREAD_STATE_SLEEPING) != 0) {
|
|
146 status = THREAD_STATUS_SLEEPING;
|
|
147 } else if ((state & JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER) != 0) {
|
|
148 status = THREAD_STATUS_MONITOR;
|
|
149 } else if ((state & JVMTI_THREAD_STATE_WAITING) != 0) {
|
|
150 status = THREAD_STATUS_WAIT;
|
|
151 } else if ((state & JVMTI_THREAD_STATE_RUNNABLE) != 0) {
|
|
152 status = THREAD_STATUS_RUNNING;
|
|
153 }
|
|
154 }
|
|
155 return status;
|
|
156 }
|
|
157
|
|
158 public boolean isSuspended() { //fixme jjh
|
|
159 // If we want to support doing this for a VM which was being
|
|
160 // debugged, then we need to fix this.
|
|
161 // In the meantime, we will say all threads are suspended,
|
|
162 // otherwise, some things won't work, like the jdb 'up' cmd.
|
|
163 return true;
|
|
164 }
|
|
165
|
|
166 public boolean isAtBreakpoint() { //fixme jjh
|
|
167 // If we want to support doing this for a VM which was being
|
|
168 // debugged, then we need to fix this.
|
|
169 return false;
|
|
170 }
|
|
171
|
|
172 public ThreadGroupReference threadGroup() {
|
|
173 return (ThreadGroupReferenceImpl)vm.threadGroupMirror(
|
|
174 (Instance)OopUtilities.threadOopGetThreadGroup(ref()));
|
|
175 }
|
|
176
|
|
177 public int frameCount() throws IncompatibleThreadStateException { //fixme jjh
|
|
178 privateFrames(0, -1);
|
|
179 return frames.size();
|
|
180 }
|
|
181
|
|
182 public List frames() throws IncompatibleThreadStateException {
|
|
183 return privateFrames(0, -1);
|
|
184 }
|
|
185
|
|
186 public StackFrame frame(int index) throws IncompatibleThreadStateException {
|
|
187 List list = privateFrames(index, 1);
|
|
188 return (StackFrame)list.get(0);
|
|
189 }
|
|
190
|
|
191 public List frames(int start, int length)
|
|
192 throws IncompatibleThreadStateException {
|
|
193 if (length < 0) {
|
|
194 throw new IndexOutOfBoundsException(
|
|
195 "length must be greater than or equal to zero");
|
|
196 }
|
|
197 return privateFrames(start, length);
|
|
198 }
|
|
199
|
|
200 /**
|
|
201 * Private version of frames() allows "-1" to specify all
|
|
202 * remaining frames.
|
|
203 */
|
|
204
|
|
205 private List privateFrames(int start, int length)
|
|
206 throws IncompatibleThreadStateException {
|
|
207 if (myJavaThread == null) {
|
|
208 // for zombies and yet-to-be-started threads we need to throw exception
|
|
209 throw new IncompatibleThreadStateException();
|
|
210 }
|
|
211 if (frames == null) {
|
|
212 frames = new ArrayList(10);
|
|
213 JavaVFrame myvf = myJavaThread.getLastJavaVFrameDbg();
|
|
214 while (myvf != null) {
|
|
215 StackFrame myFrame = new StackFrameImpl(vm, this, myvf);
|
|
216 //fixme jjh null should be a Location
|
|
217 frames.add(myFrame);
|
|
218 myvf = (JavaVFrame)myvf.javaSender();
|
|
219 }
|
|
220 }
|
|
221
|
|
222 List retVal;
|
|
223 if (frames.size() == 0) {
|
|
224 retVal = new ArrayList(0);
|
|
225 } else {
|
|
226 int toIndex = start + length;
|
|
227 if (length == -1) {
|
|
228 toIndex = frames.size();
|
|
229 }
|
|
230 retVal = frames.subList(start, toIndex);
|
|
231 }
|
|
232 return Collections.unmodifiableList(retVal);
|
|
233 }
|
|
234
|
|
235 // refer to JvmtiEnvBase::get_owned_monitors
|
|
236 public List ownedMonitors() throws IncompatibleThreadStateException {
|
|
237 if (vm.canGetOwnedMonitorInfo() == false) {
|
|
238 throw new UnsupportedOperationException();
|
|
239 }
|
|
240
|
|
241 if (myJavaThread == null) {
|
|
242 throw new IncompatibleThreadStateException();
|
|
243 }
|
|
244
|
|
245 if (ownedMonitors != null) {
|
|
246 return ownedMonitors;
|
|
247 }
|
|
248
|
|
249 ownedMonitorsWithStackDepth();
|
|
250
|
|
251 for (Iterator omi = ownedMonitorsInfo.iterator(); omi.hasNext(); ) {
|
|
252 //FIXME : Change the MonitorInfoImpl cast to com.sun.jdi.MonitorInfo
|
|
253 // when hotspot start building with jdk1.6.
|
|
254 ownedMonitors.add(((MonitorInfoImpl)omi.next()).monitor());
|
|
255 }
|
|
256
|
|
257 return ownedMonitors;
|
|
258 }
|
|
259
|
|
260 // new method since 1.6.
|
|
261 // Real body will be supplied later.
|
|
262 public List ownedMonitorsAndFrames() throws IncompatibleThreadStateException {
|
|
263 if (!vm.canGetMonitorFrameInfo()) {
|
|
264 throw new UnsupportedOperationException(
|
|
265 "target does not support getting Monitor Frame Info");
|
|
266 }
|
|
267
|
|
268 if (myJavaThread == null) {
|
|
269 throw new IncompatibleThreadStateException();
|
|
270 }
|
|
271
|
|
272 if (ownedMonitorsInfo != null) {
|
|
273 return ownedMonitorsInfo;
|
|
274 }
|
|
275
|
|
276 ownedMonitorsWithStackDepth();
|
|
277 return ownedMonitorsInfo;
|
|
278 }
|
|
279
|
|
280 private void ownedMonitorsWithStackDepth() {
|
|
281
|
|
282 ownedMonitorsInfo = new ArrayList();
|
|
283 List lockedObjects = new ArrayList(); // List<OopHandle>
|
|
284 List stackDepth = new ArrayList(); // List<int>
|
|
285 ObjectMonitor waitingMonitor = myJavaThread.getCurrentWaitingMonitor();
|
|
286 ObjectMonitor pendingMonitor = myJavaThread.getCurrentPendingMonitor();
|
|
287 OopHandle waitingObj = null;
|
|
288 if (waitingMonitor != null) {
|
|
289 // save object of current wait() call (if any) for later comparison
|
|
290 waitingObj = waitingMonitor.object();
|
|
291 }
|
|
292 OopHandle pendingObj = null;
|
|
293 if (pendingMonitor != null) {
|
|
294 // save object of current enter() call (if any) for later comparison
|
|
295 pendingObj = pendingMonitor.object();
|
|
296 }
|
|
297
|
|
298 JavaVFrame frame = myJavaThread.getLastJavaVFrameDbg();
|
|
299 int depth=0;
|
|
300 while (frame != null) {
|
|
301 List frameMonitors = frame.getMonitors(); // List<MonitorInfo>
|
|
302 for (Iterator miItr = frameMonitors.iterator(); miItr.hasNext(); ) {
|
|
303 sun.jvm.hotspot.runtime.MonitorInfo mi = (sun.jvm.hotspot.runtime.MonitorInfo) miItr.next();
|
|
304 OopHandle obj = mi.owner();
|
|
305 if (obj == null) {
|
|
306 // this monitor doesn't have an owning object so skip it
|
|
307 continue;
|
|
308 }
|
|
309
|
|
310 if (obj.equals(waitingObj)) {
|
|
311 // the thread is waiting on this monitor so it isn't really owned
|
|
312 continue;
|
|
313 }
|
|
314
|
|
315 if (obj.equals(pendingObj)) {
|
|
316 // the thread is pending on this monitor so it isn't really owned
|
|
317 continue;
|
|
318 }
|
|
319
|
|
320 boolean found = false;
|
|
321 for (Iterator loItr = lockedObjects.iterator(); loItr.hasNext(); ) {
|
|
322 // check for recursive locks
|
|
323 if (obj.equals(loItr.next())) {
|
|
324 found = true;
|
|
325 break;
|
|
326 }
|
|
327 }
|
|
328 if (found) {
|
|
329 // already have this object so don't include it
|
|
330 continue;
|
|
331 }
|
|
332 // add the owning object to our list
|
|
333 lockedObjects.add(obj);
|
|
334 stackDepth.add(new Integer(depth));
|
|
335 }
|
|
336 frame = (JavaVFrame) frame.javaSender();
|
|
337 depth++;
|
|
338 }
|
|
339
|
|
340 // now convert List<OopHandle> to List<ObjectReference>
|
|
341 ObjectHeap heap = vm.saObjectHeap();
|
|
342 Iterator stk = stackDepth.iterator();
|
|
343 for (Iterator loItr = lockedObjects.iterator(); loItr.hasNext(); ) {
|
|
344 Oop obj = heap.newOop((OopHandle)loItr.next());
|
|
345 ownedMonitorsInfo.add(new MonitorInfoImpl(vm, vm.objectMirror(obj), this,
|
|
346 ((Integer)stk.next()).intValue()));
|
|
347 }
|
|
348 }
|
|
349
|
|
350 // refer to JvmtiEnvBase::get_current_contended_monitor
|
|
351 public ObjectReference currentContendedMonitor()
|
|
352 throws IncompatibleThreadStateException {
|
|
353 if (vm.canGetCurrentContendedMonitor() == false) {
|
|
354 throw new UnsupportedOperationException();
|
|
355 }
|
|
356
|
|
357 if (myJavaThread == null) {
|
|
358 throw new IncompatibleThreadStateException();
|
|
359 }
|
|
360 ObjectMonitor mon = myJavaThread.getCurrentWaitingMonitor();
|
|
361 if (mon == null) {
|
|
362 // thread is not doing an Object.wait() call
|
|
363 mon = myJavaThread.getCurrentPendingMonitor();
|
|
364 if (mon != null) {
|
|
365 OopHandle handle = mon.object();
|
|
366 // If obj == NULL, then ObjectMonitor is raw which doesn't count
|
|
367 // as contended for this API
|
|
368 return vm.objectMirror(vm.saObjectHeap().newOop(handle));
|
|
369 } else {
|
|
370 // no contended ObjectMonitor
|
|
371 return null;
|
|
372 }
|
|
373 } else {
|
|
374 // thread is doing an Object.wait() call
|
|
375 OopHandle handle = mon.object();
|
|
376 if (Assert.ASSERTS_ENABLED) {
|
|
377 Assert.that(handle != null, "Object.wait() should have an object");
|
|
378 }
|
|
379 Oop obj = vm.saObjectHeap().newOop(handle);
|
|
380 return vm.objectMirror(obj);
|
|
381 }
|
|
382 }
|
|
383
|
|
384
|
|
385 public void popFrames(StackFrame frame) throws IncompatibleThreadStateException {
|
|
386 vm.throwNotReadOnlyException("ThreadReference.popFrames()");
|
|
387 }
|
|
388
|
|
389 public void forceEarlyReturn(Value returnValue) throws IncompatibleThreadStateException {
|
|
390 vm.throwNotReadOnlyException("ThreadReference.forceEarlyReturn()");
|
|
391 }
|
|
392
|
|
393 public String toString() {
|
|
394 return "instance of " + referenceType().name() +
|
|
395 "(name='" + name() + "', " + "id=" + uniqueID() + ")";
|
|
396 }
|
|
397 }
|