diff options
Diffstat (limited to 'libjava/classpath/java/lang/management/ThreadInfo.java')
-rw-r--r-- | libjava/classpath/java/lang/management/ThreadInfo.java | 431 |
1 files changed, 374 insertions, 57 deletions
diff --git a/libjava/classpath/java/lang/management/ThreadInfo.java b/libjava/classpath/java/lang/management/ThreadInfo.java index 428aca3fac8..884f5af5e9e 100644 --- a/libjava/classpath/java/lang/management/ThreadInfo.java +++ b/libjava/classpath/java/lang/management/ThreadInfo.java @@ -37,6 +37,8 @@ exception statement from your version. */ package java.lang.management; +import java.util.Arrays; + import javax.management.openmbean.ArrayType; import javax.management.openmbean.CompositeData; import javax.management.openmbean.CompositeType; @@ -68,6 +70,8 @@ import javax.management.openmbean.SimpleType; * monitor, upon which the thread described here is blocked.</li> * <li>The stack trace of the thread (if requested on creation * of this object</li> + * <li>The current locks held on object monitors by the thread.</li> + * <li>The current locks held on ownable synchronizers by the thread.</li> * </ul> * <li><strong>Synchronization Statistics</strong> * <ul> @@ -165,11 +169,28 @@ public class ThreadInfo private StackTraceElement[] trace; /** + * The array of information on monitors locked by the thread. + */ + private MonitorInfo[] lockedMonitors; + + /** + * The array of information on ownable synchronizers locked + * by the thread. + */ + private LockInfo[] lockedSynchronizers; + + /** * Cache a local reference to the thread management bean. */ private static ThreadMXBean bean = null; /** + * Cache the {@link javax.management.openmbean.CompositeType} + * for the {@link StackTraceElement}. + */ + private static CompositeType seType; + + /** * Constructs a new {@link ThreadInfo} corresponding * to the thread specified. * @@ -200,13 +221,57 @@ public class ThreadInfo long waitedTime, boolean isInNative, boolean isSuspended, StackTraceElement[] trace) { + this(thread, blockedCount, blockedTime, lock, lockOwner, waitedCount, + waitedTime, isInNative, isSuspended, trace, new MonitorInfo[]{}, + new LockInfo[]{}); + } + + /** + * Constructs a new {@link ThreadInfo} corresponding + * to the thread specified. + * + * @param thread the thread on which the new instance + * will be based. + * @param blockedCount the number of times the thread + * has been blocked. + * @param blockedTime the accumulated number of milliseconds + * the specified thread has been blocked + * (only used with contention monitoring enabled) + * @param lock the monitor lock the thread is waiting for + * (only used if blocked) + * @param lockOwner the thread which owns the monitor lock, or + * <code>null</code> if it doesn't have an owner + * (only used if blocked) + * @param waitedCount the number of times the thread has been in a + * waiting state. + * @param waitedTime the accumulated number of milliseconds the + * specified thread has been waiting + * (only used with contention monitoring enabled) + * @param isInNative true if the thread is in a native method. + * @param isSuspended true if the thread is suspended. + * @param trace the stack trace of the thread to a pre-determined + * depth (see VMThreadMXBeanImpl) + * @param lockedMonitors an array of {@link MonitorInfo} objects + * representing locks held on object monitors + * by the thread. + * @param lockedSynchronizers an array of {@link LockInfo} objects + * representing locks held on ownable + * synchronizers by the thread. + * @since 1.6 + */ + private ThreadInfo(Thread thread, long blockedCount, long blockedTime, + Object lock, Thread lockOwner, long waitedCount, + long waitedTime, boolean isInNative, boolean isSuspended, + StackTraceElement[] trace, MonitorInfo[] lockedMonitors, + LockInfo[] lockedSynchronizers) + { this(thread.getId(), thread.getName(), thread.getState(), blockedCount, blockedTime, lock == null ? null : lock.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(lock)), lockOwner == null ? -1 : lockOwner.getId(), lockOwner == null ? null : lockOwner.getName(), waitedCount, waitedTime, isInNative, isSuspended, - trace); + trace, lockedMonitors, lockedSynchronizers); } /** @@ -248,6 +313,59 @@ public class ThreadInfo long waitedTime, boolean isInNative, boolean isSuspended, StackTraceElement[] trace) { + this(threadId, threadName, threadState, blockedCount, blockedTime, + lockName, lockOwnerId, lockOwnerName, waitedCount, waitedTime, + isInNative, isSuspended, trace, new MonitorInfo[]{}, new LockInfo[]{}); + } + + /** + * Constructs a new {@link ThreadInfo} corresponding + * to the thread details specified. + * + * @param threadId the id of the thread on which this + * new instance will be based. + * @param threadName the name of the thread on which + * this new instance will be based. + * @param threadState the state of the thread on which + * this new instance will be based. + * @param blockedCount the number of times the thread + * has been blocked. + * @param blockedTime the accumulated number of milliseconds + * the specified thread has been blocked + * (only used with contention monitoring enabled) + * @param lockName the name of the monitor lock the thread is waiting for + * (only used if blocked) + * @param lockOwnerId the id of the thread which owns the monitor + * lock, or <code>-1</code> if it doesn't have an owner + * (only used if blocked) + * @param lockOwnerName the name of the thread which owns the monitor + * lock, or <code>null</code> if it doesn't have an + * owner (only used if blocked) + * @param waitedCount the number of times the thread has been in a + * waiting state. + * @param waitedTime the accumulated number of milliseconds the + * specified thread has been waiting + * (only used with contention monitoring enabled) + * @param isInNative true if the thread is in a native method. + * @param isSuspended true if the thread is suspended. + * @param trace the stack trace of the thread to a pre-determined + * depth (see VMThreadMXBeanImpl) + * @param lockedMonitors an array of {@link MonitorInfo} objects + * representing locks held on object monitors + * by the thread. + * @param lockedSynchronizers an array of {@link LockInfo} objects + * representing locks held on ownable + * synchronizers by the thread. + * + * @since 1.6 + */ + private ThreadInfo(long threadId, String threadName, Thread.State threadState, + long blockedCount, long blockedTime, String lockName, + long lockOwnerId, String lockOwnerName, long waitedCount, + long waitedTime, boolean isInNative, boolean isSuspended, + StackTraceElement[] trace, MonitorInfo[] lockedMonitors, + LockInfo[] lockedSynchronizers) + { this.threadId = threadId; this.threadName = threadName; this.threadState = threadState; @@ -261,6 +379,8 @@ public class ThreadInfo this.isInNative = isInNative; this.isSuspended = isSuspended; this.trace = trace; + this.lockedMonitors = lockedMonitors; + this.lockedSynchronizers = lockedSynchronizers; } /** @@ -287,6 +407,44 @@ public class ThreadInfo } /** + * Returns the {@link javax.management.openmbean.CompositeType} for + * a {@link StackTraceElement}. + * + * @return the type for the stack trace element. + */ + static CompositeType getStackTraceType() + { + if (seType == null) + try + { + seType = new CompositeType(StackTraceElement.class.getName(), + "An element of a stack trace", + new String[] { "className", "methodName", + "fileName", "lineNumber", + "nativeMethod" + }, + new String[] { "Name of the class", + "Name of the method", + "Name of the source code file", + "Line number", + "True if this is a native method" + }, + new OpenType[] { + SimpleType.STRING, SimpleType.STRING, + SimpleType.STRING, SimpleType.INTEGER, + SimpleType.BOOLEAN + }); + } + catch (OpenDataException e) + { + throw new IllegalStateException("Something went wrong in creating " + + "the composite data type for the " + + "stack trace element.", e); + } + return seType; + } + + /** * <p> * Returns a {@link ThreadInfo} instance using the values * given in the supplied @@ -336,70 +494,133 @@ public class ThreadInfo if (data == null) return null; CompositeType type = data.getCompositeType(); - checkAttribute(type, "threadId", SimpleType.LONG); - checkAttribute(type, "threadName", SimpleType.STRING); - checkAttribute(type, "threadState", SimpleType.STRING); - checkAttribute(type, "suspended", SimpleType.BOOLEAN); - checkAttribute(type, "inNative", SimpleType.BOOLEAN); - checkAttribute(type, "blockedCount", SimpleType.LONG); - checkAttribute(type, "blockedTime", SimpleType.LONG); - checkAttribute(type, "waitedCount", SimpleType.LONG); - checkAttribute(type, "waitedTime", SimpleType.LONG); - checkAttribute(type, "lockName", SimpleType.STRING); - checkAttribute(type, "lockOwnerId", SimpleType.LONG); - checkAttribute(type, "lockOwnerName", SimpleType.STRING); + checkAttribute(type, "ThreadId", SimpleType.LONG); + checkAttribute(type, "ThreadName", SimpleType.STRING); + checkAttribute(type, "ThreadState", SimpleType.STRING); + checkAttribute(type, "Suspended", SimpleType.BOOLEAN); + checkAttribute(type, "InNative", SimpleType.BOOLEAN); + checkAttribute(type, "BlockedCount", SimpleType.LONG); + checkAttribute(type, "BlockedTime", SimpleType.LONG); + checkAttribute(type, "WaitedCount", SimpleType.LONG); + checkAttribute(type, "WaitedTime", SimpleType.LONG); + checkAttribute(type, "LockName", SimpleType.STRING); + checkAttribute(type, "LockOwnerId", SimpleType.LONG); + checkAttribute(type, "LockOwnerName", SimpleType.STRING); try { - CompositeType seType = - new CompositeType(StackTraceElement.class.getName(), - "An element of a stack trace", - new String[] { "className", "methodName", - "fileName", "lineNumber", - "nativeMethod" - }, - new String[] { "Name of the class", - "Name of the method", - "Name of the source code file", - "Line number", - "True if this is a native method" - }, - new OpenType[] { - SimpleType.STRING, SimpleType.STRING, - SimpleType.STRING, SimpleType.INTEGER, - SimpleType.BOOLEAN - }); - checkAttribute(type, "stackTrace", new ArrayType(1, seType)); + checkAttribute(type, "StackTrace", + new ArrayType(1, getStackTraceType())); + } + catch (OpenDataException e) + { + throw new IllegalStateException("Something went wrong in creating " + + "the array for the stack trace element.", + e); + } + OpenType foundType = type.getType("LockedMonitors"); + if (foundType != null) + try + { + CompositeType mType = new CompositeType(MonitorInfo.class.getName(), + "Information on a object monitor lock", + new String[] { "ClassName", + "IdentityHashCode", + "LockedStackDepth", + "LockedStackFrame" + }, + new String[] { "Name of the class", + "Identity hash code " + + "of the class", + "Stack depth at time " + + "of lock", + "Stack frame at time " + + "of lock", + }, + new OpenType[] { + SimpleType.STRING, SimpleType.INTEGER, + SimpleType.INTEGER, getStackTraceType() + }); + if (!(foundType.equals(new ArrayType(1, mType)))) + throw new IllegalArgumentException("Field LockedMonitors is not of " + + "type " + mType.getClassName()); + } + catch (OpenDataException e) + { + throw new IllegalStateException("Something went wrong in creating " + + "the composite data type for the " + + "object monitor information array.", e); } + foundType = type.getType("LockedSynchronizers"); + if (foundType != null) + try + { + CompositeType lType = new CompositeType(LockInfo.class.getName(), + "Information on a lock", + new String[] { "ClassName", + "IdentityHashCode" + }, + new String[] { "Name of the class", + "Identity hash code " + + "of the class" + }, + new OpenType[] { + SimpleType.STRING, SimpleType.INTEGER + }); + if (!(foundType.equals(new ArrayType(1, lType)))) + throw new IllegalArgumentException("Field LockedSynchronizers is not of " + + "type " + lType.getClassName()); + } catch (OpenDataException e) { throw new IllegalStateException("Something went wrong in creating " + "the composite data type for the " + - "stack trace element.", e); + "ownable synchronizerinformation array.", e); } - CompositeData[] dTraces = (CompositeData[]) data.get("stackTrace"); + CompositeData[] dTraces = (CompositeData[]) data.get("StackTrace"); StackTraceElement[] traces = new StackTraceElement[dTraces.length]; for (int a = 0; a < dTraces.length; ++a) /* FIXME: We can't use the boolean as there is no available constructor. */ traces[a] = - new StackTraceElement((String) dTraces[a].get("className"), - (String) dTraces[a].get("methodName"), - (String) dTraces[a].get("fileName"), + new StackTraceElement((String) dTraces[a].get("ClassName"), + (String) dTraces[a].get("MethodName"), + (String) dTraces[a].get("FileName"), ((Integer) - dTraces[a].get("lineNumber")).intValue()); - return new ThreadInfo(((Long) data.get("threadId")).longValue(), - (String) data.get("threadName"), - Thread.State.valueOf((String) data.get("threadState")), - ((Long) data.get("blockedCount")).longValue(), - ((Long) data.get("blockedTime")).longValue(), - (String) data.get("lockName"), - ((Long) data.get("lockOwnerId")).longValue(), - (String) data.get("lockOwnerName"), - ((Long) data.get("waitedCount")).longValue(), - ((Long) data.get("waitedTime")).longValue(), - ((Boolean) data.get("inNative")).booleanValue(), - ((Boolean) data.get("suspended")).booleanValue(), - traces); + dTraces[a].get("LineNumber")).intValue()); + MonitorInfo[] mInfo; + if (data.containsKey("LockedMonitors")) + { + CompositeData[] dmInfos = (CompositeData[]) data.get("LockedMonitors"); + mInfo = new MonitorInfo[dmInfos.length]; + for (int a = 0; a < dmInfos.length; ++a) + mInfo[a] = MonitorInfo.from(dmInfos[a]); + } + else + mInfo = new MonitorInfo[]{}; + LockInfo[] lInfo; + if (data.containsKey("LockedSynchronizers")) + { + CompositeData[] dlInfos = (CompositeData[]) data.get("LockedSynchronizers"); + lInfo = new LockInfo[dlInfos.length]; + for (int a = 0; a < dlInfos.length; ++a) + lInfo[a] = new LockInfo((String) dlInfos[a].get("ClassName"), + (Integer) dlInfos[a].get("IdentityHashCode")); + } + else + lInfo = new LockInfo[]{}; + return new ThreadInfo(((Long) data.get("ThreadId")).longValue(), + (String) data.get("ThreadName"), + Thread.State.valueOf((String) data.get("ThreadState")), + ((Long) data.get("BlockedCount")).longValue(), + ((Long) data.get("BlockedTime")).longValue(), + (String) data.get("LockName"), + ((Long) data.get("LockOwnerId")).longValue(), + (String) data.get("LockOwnerName"), + ((Long) data.get("WaitedCount")).longValue(), + ((Long) data.get("WaitedTime")).longValue(), + ((Boolean) data.get("InNative")).booleanValue(), + ((Boolean) data.get("Suspended")).booleanValue(), + traces, mInfo, lInfo); } /** @@ -459,9 +680,74 @@ public class ThreadInfo } /** + * Returns an array of {@link MonitorInfo} objects representing + * information on the locks on object monitors held by the thread. + * If no locks are held, or such information was not requested + * on creating this {@link ThreadInfo} object, a zero-length + * array will be returned. + * + * @return information on object monitors locked by this thread. + */ + public MonitorInfo[] getLockedMonitors() + { + return lockedMonitors; + } + + /** + * Returns an array of {@link LockInfo} objects representing + * information on the locks on ownable synchronizers held by the thread. + * If no locks are held, or such information was not requested + * on creating this {@link ThreadInfo} object, a zero-length + * array will be returned. + * + * @return information on ownable synchronizers locked by this thread. + */ + public LockInfo[] getLockedSynchronizers() + { + return lockedSynchronizers; + } + + /** + * <p> + * Returns a {@link LockInfo} object representing the + * lock on which this thread is blocked. If the thread + * is not blocked, this method returns <code>null</code>. + * </p> + * <p> + * The thread may be blocked due to one of three reasons: + * </p> + * <ol> + * <li>The thread is in the <code>BLOCKED</code> state + * waiting to acquire an object monitor in order to enter + * a synchronized method or block.</li> + * <li>The thread is in the <code>WAITING</code> or + * <code>TIMED_WAITING</code> state due to a call to + * {@link java.lang.Object#wait()}.</li> + * <li>The thread is in the <code>WAITING</code> or + * <code>TIMED_WAITING</code> state due to a call + * to {@link java.util.concurrent.locks.LockSupport#park()}. + * The lock is the return value of + * {@link java.util.concurrent.locks.LockSupport#getBlocker()}.</li> + * </ol> + * + * @return a {@link LockInfo} object representing the lock on + * which the thread is blocked, or <code>null</code> if + * the thread isn't blocked. + * @since 1.6 + * @see #getLockName() + */ + public LockInfo getLockInfo() + { + String lockName = getLockName(); + int at = lockName.indexOf('@'); + return new LockInfo(lockName.substring(0, at), + Integer.decode(lockName.substring(at + 1))); + } + + /** * <p> * Returns a {@link java.lang.String} representation of - * the monitor lock on which this thread is blocked. If + * the lock on which this thread is blocked. If * the thread is not blocked, this method returns * <code>null</code>. * </p> @@ -477,7 +763,8 @@ public class ThreadInfo * and * <code>Integer.toHexString(System.identityHashCode(l))</code>. * The value is only unique to the extent that the identity - * hash code is also unique. + * hash code is also unique. The value is the same as would + * be returned by <code>getLockInfo().toString()</code> * </p> * * @return a string representing the lock on which this @@ -486,7 +773,7 @@ public class ThreadInfo */ public String getLockName() { - if (threadState != Thread.State.BLOCKED) + if (!isThreadBlocked()) return null; return lockName; } @@ -504,7 +791,7 @@ public class ThreadInfo */ public long getLockOwnerId() { - if (threadState != Thread.State.BLOCKED) + if (!isThreadBlocked()) return -1; return lockOwnerId; } @@ -522,7 +809,7 @@ public class ThreadInfo */ public String getLockOwnerName() { - if (threadState != Thread.State.BLOCKED) + if (!isThreadBlocked()) return null; return lockOwnerName; } @@ -697,10 +984,40 @@ public class ThreadInfo ", waitedCount=" + waitedCount + ", isInNative=" + isInNative + ", isSuspended=" + isSuspended + - (threadState == Thread.State.BLOCKED ? + (isThreadBlocked() ? ", lockOwnerId=" + lockOwnerId + ", lockOwnerName=" + lockOwnerName : "") + + ", lockedMonitors=" + Arrays.toString(lockedMonitors) + + ", lockedSynchronizers=" + Arrays.toString(lockedSynchronizers) + "]"; } + /** + * <p> + * Returns true if the thread is in a blocked state. + * The thread is regarded as blocked if: + * </p> + * <ol> + * <li>The thread is in the <code>BLOCKED</code> state + * waiting to acquire an object monitor in order to enter + * a synchronized method or block.</li> + * <li>The thread is in the <code>WAITING</code> or + * <code>TIMED_WAITING</code> state due to a call to + * {@link java.lang.Object#wait()}.</li> + * <li>The thread is in the <code>WAITING</code> or + * <code>TIMED_WAITING</code> state due to a call + * to {@link java.util.concurrent.locks.LockSupport#park()}. + * The lock is the return value of + * {@link java.util.concurrent.locks.LockSupport#getBlocker()}.</li> + * </ol> + * + * @return true if the thread is blocked. + */ + private boolean isThreadBlocked() + { + return (threadState == Thread.State.BLOCKED || + threadState == Thread.State.WAITING || + threadState == Thread.State.TIMED_WAITING); + } + } |