/* * 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. */ 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; }