/*
* Copyright (c) 2004, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
package sun.jvm.hotspot.utilities.soql;
import java.util.*;
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.oops.*;
import sun.jvm.hotspot.runtime.*;
Wraps a JavaThread instance in the target VM.
/**
* Wraps a JavaThread instance in the target VM.
*/
public class JSJavaThread extends JSJavaInstance {
public JSJavaThread(Instance threadOop, JSJavaFactory fac) {
super(threadOop, fac);
// JavaThread retrieved from java.lang.Thread instance may be null.
// This is the case for threads not-started and for zombies. Wherever
// appropriate, check for null instead of resulting in NullPointerException.
this.jthread = OopUtilities.threadOopGetJavaThread(threadOop);
}
public JSJavaThread(JavaThread jt, JSJavaFactory fac) {
super((Instance) jt.getThreadObj(), fac);
this.jthread = jt;
}
public String toString() {
String name = getName();
StringBuffer buf = new StringBuffer();
buf.append("Thread (address=");
buf.append(getOop().getHandle());
buf.append(", name=");
if (name != null) {
buf.append(name);
} else {
buf.append("<unnamed>");
}
buf.append(')');
return buf.toString();
}
protected Object getFieldValue(String name) {
if (name.equals("name")) {
return getName();
} else if (name.equals("frames")) {
return getFrames();
} else if (name.equals("monitors")) {
return getOwnedMonitors();
} else {
return super.getFieldValue(name);
}
}
protected String[] getFieldNames() {
String[] flds = super.getFieldNames();
String[] res = new String[flds.length + 2];
System.arraycopy(flds, 0, res, 0, flds.length);
res[flds.length] = "frames";
res[flds.length + 1] = "monitors";
return res;
}
protected boolean hasField(String name) {
if (name.equals("frames") || name.equals("monitors")) {
return true;
} else {
return super.hasField(name);
}
}
//-- Internals only below this point
private String getName() {
return OopUtilities.threadOopGetName(getOop());
}
private synchronized JSList getFrames() {
if (framesCache == null) {
final List list = new ArrayList(0);
if (jthread != null) {
JavaVFrame jvf = jthread.getLastJavaVFrameDbg();
while (jvf != null) {
list.add(jvf);
jvf = jvf.javaSender();
}
}
framesCache = factory.newJSList(list);
}
return framesCache;
}
private synchronized JSList getOwnedMonitors() {
if (monitorsCache == null) {
final List ownedMonitors = new ArrayList(0);
if (jthread != null) {
List lockedObjects = new ArrayList(); // List<OopHandle>
ObjectMonitor waitingMonitor = jthread.getCurrentWaitingMonitor();
OopHandle waitingObj = null;
if (waitingMonitor != null) {
// save object of current wait() call (if any) for later comparison
waitingObj = waitingMonitor.object();
}
ObjectMonitor pendingMonitor = jthread.getCurrentPendingMonitor();
OopHandle pendingObj = null;
if (pendingMonitor != null) {
// save object of current enter() call (if any) for later comparison
pendingObj = pendingMonitor.object();
}
JavaVFrame frame = jthread.getLastJavaVFrameDbg();
while (frame != null) {
List frameMonitors = frame.getMonitors(); // List<MonitorInfo>
for (Iterator miItr = frameMonitors.iterator(); miItr.hasNext(); ) {
MonitorInfo mi = (MonitorInfo) miItr.next();
if (mi.eliminated() && frame.isCompiledFrame()) {
continue; // skip eliminated monitor
}
OopHandle obj = mi.owner();
if (obj == null) {
// this monitor doesn't have an owning object so skip it
continue;
}
if (obj.equals(waitingObj)) {
// the thread is waiting on this monitor so it isn't really owned
continue;
}
if (obj.equals(pendingObj)) {
// the thread is pending on this monitor so it isn't really owned
continue;
}
boolean found = false;
for (Iterator loItr = lockedObjects.iterator(); loItr.hasNext(); ) {
// check for recursive locks
if (obj.equals(loItr.next())) {
found = true;
break;
}
}
if (found) {
// already have this object so don't include it
continue;
}
// add the owning object to our list
lockedObjects.add(obj);
}
frame = (JavaVFrame) frame.javaSender();
}
// now convert List<OopHandle> to List<Oop>
ObjectHeap heap = VM.getVM().getObjectHeap();
for (Iterator loItr = lockedObjects.iterator(); loItr.hasNext(); ) {
ownedMonitors.add(heap.newOop((OopHandle)loItr.next()));
}
}
monitorsCache = factory.newJSList(ownedMonitors);
}
return monitorsCache;
}
private JavaThread jthread;
private JSList framesCache;
private JSList monitorsCache;
}