001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package gnu.java.lang.management;
014
015import java.lang.management.LockInfo;
016import java.lang.management.MonitorInfo;
017import java.lang.management.ThreadInfo;
018import java.lang.reflect.Constructor;
019import java.lang.reflect.InvocationTargetException;
020
021import org.jikesrvm.scheduler.JMXSupport;
022import org.jikesrvm.scheduler.RVMThread;
023import org.jikesrvm.util.UnimplementedError;
024
025final class VMThreadMXBeanImpl {
026
027  /**
028   * Returns the ids of deadlocked threads occurring due
029   * to either monitor or ownable synchronizer ownership.
030   * Only called if ownable synchronizer monitoring is
031   * supported.
032   *
033   * @return an array of thread identifiers.
034   */
035  static long[] findDeadlockedThreads() {
036    throw new UnimplementedError();
037  }
038
039  /**
040   * Returns the ids of deadlocked threads occurring due
041   * to monitor ownership.
042   *
043   * @return an array of thread identifiers.
044   */
045  static long[] findMonitorDeadlockedThreads() {
046    throw new UnimplementedError();
047  }
048
049  /**
050   * Returns the identifiers of all live threads.
051   *
052   * @return an array of thread identifiers.
053   */
054  static long[] getAllThreadIds() {
055    return JMXSupport.getAllLiveThreadIds();
056  }
057
058  /**
059   * Returns the number of nanoseconds of CPU time
060   * the current thread has used, if supported.
061   *
062   * @return the number of nanoseconds.
063   */
064  static long getCurrentThreadCpuTime() {
065    return getThreadCpuTime(getIDForCurrentThread());
066  }
067
068  private static long getIDForCurrentThread() {
069    return RVMThread.getCurrentThread().getJavaLangThread().getId();
070  }
071
072  /**
073   * Returns the number of nanoseconds of user time
074   * the current thread has used, if supported.
075   *
076   * @return the number of nanoseconds.
077   */
078  static long getCurrentThreadUserTime() {
079    return getThreadUserTime(getIDForCurrentThread());
080  }
081
082  /**
083   * Returns the number of live daemon threads.
084   *
085   * @return the number of live daemon threads.
086   */
087  static int getDaemonThreadCount() {
088    return JMXSupport.getLiveDaemonCount();
089  }
090
091  /**
092   * Fills out the information on ownable synchronizers
093   * in the given {@link java.lang.management.ThreadInfo}
094   * object if supported.
095   *
096   * @param info the object to fill in.
097   */
098  static void getLockInfo(ThreadInfo info) {
099    throw new UnimplementedError();
100  }
101
102  /**
103   * Fills out the information on monitor usage
104   * in the given {@link java.lang.management.ThreadInfo}
105   * object if supported.
106   *
107   * @param info the object to fill in.
108   */
109  static void getMonitorInfo(ThreadInfo info) {
110    throw new UnimplementedError();
111  }
112
113  /**
114   * Returns the current peak number of live threads.
115   *
116   * @return the current peak.
117   */
118  static int getPeakThreadCount() {
119    return JMXSupport.getPeakThreadCount();
120  }
121
122  /**
123   * Returns the current number of live threads.
124   *
125   * @return the current number of live threads.
126   */
127  static int getThreadCount() {
128    return JMXSupport.getLiveThreadCount();
129  }
130
131  /**
132   * Returns the number of nanoseconds of CPU time
133   * the given thread has used, if supported.
134   *
135   * @param id the id of the thread to probe.
136   * @return the number of nanoseconds.
137   */
138  static long getThreadCpuTime(long id) {
139    throw new UnimplementedError();
140  }
141
142  /**
143   * Returns a {@link java.lang.management.ThreadInfo}
144   * object for the given thread id with a stack trace to
145   * the given depth (0 for empty, Integer.MAX_VALUE for
146   * full).
147   *
148   * @param id the id of the thread whose info should be returned.
149   * @param maxDepth the depth of the stack trace.
150   * @return a {@link java.lang.management.ThreadInfo} instance.
151   */
152  static ThreadInfo getThreadInfoForId(long id, int maxDepth) {
153    Thread thread = getThreadForId(id);
154    Constructor<ThreadInfo> cons = null;
155    try {
156      // ensure class is at least resolved
157      Class.forName("java.lang.management.ThreadInfo");
158
159      cons = ThreadInfo.class.getDeclaredConstructor(Long.TYPE, String.class,
160                Thread.State.class, Long.TYPE,
161                Long.TYPE, String.class,
162                Long.TYPE, String.class,
163                Long.TYPE, Long.TYPE,
164                Boolean.TYPE,Boolean.TYPE,
165                StackTraceElement[].class, MonitorInfo[].class,
166                LockInfo[].class);
167
168
169      cons.setAccessible(true);
170      RVMThread rvmThread = JikesRVMSupport.getThread(thread);
171      long blockedCount = 0; // TODO number of times blocked for Java monitors
172      long blockedTime = 0; // TODO total time blocked for Java monitors
173      long waitingCount = JMXSupport.getWaitingCount(rvmThread);
174      long waitingTime = JMXSupport.getWaitingTime(rvmThread);
175      boolean inNative = JMXSupport.isInNative(rvmThread);
176      boolean suspended = JMXSupport.isSuspended(rvmThread);
177
178      StackTraceElement[] stackTrace;
179      if (maxDepth == 0) {
180        stackTrace = null;
181      } else {
182        stackTrace = JMXSupport.getStackTraceForThread(rvmThread);
183        int newMax = Math.min(stackTrace.length, maxDepth);
184        StackTraceElement[] reducedStackTrace = new StackTraceElement[newMax];
185        int srcPos = stackTrace.length - newMax;
186        System.arraycopy(stackTrace, srcPos, reducedStackTrace,
187            0, newMax);
188        stackTrace = reducedStackTrace;
189      }
190
191      MonitorInfo[] emptyMonitorInfo = new MonitorInfo[0];
192      LockInfo[] emptyLockInfo = new LockInfo[0];
193      return cons.newInstance(id, thread.getName(), thread.getState(),
194           blockedCount, blockedTime,
195           null, -1, null, waitingCount,
196           waitingTime,
197           inNative,
198           suspended, stackTrace, emptyMonitorInfo, emptyLockInfo);
199    } catch (NoSuchMethodException e) {
200      throw (Error) new InternalError("Couldn't get ThreadInfo constructor").initCause(e);
201    } catch (InstantiationException e) {
202      throw (Error) new InternalError("Couldn't create ThreadInfo").initCause(e);
203    } catch (IllegalAccessException e) {
204      throw (Error) new InternalError("Couldn't access ThreadInfo").initCause(e);
205    } catch (InvocationTargetException e) {
206      throw (Error) new InternalError("ThreadInfo's constructor threw an exception").initCause(e);
207    } catch (ClassNotFoundException e) {
208      throw (Error) new InternalError("Problem resolving ThreadInfo").initCause(e);
209    }
210  }
211
212  /**
213   * Returns the Thread instance for the given
214   * thread id.
215   *
216   * @param id the id of the thread to find.
217   * @return the Thread.
218   */
219  private static Thread getThreadForId(long id) {
220    return JMXSupport.getThreadForId(id);
221  }
222
223  /**
224   * Returns the number of nanoseconds of user time
225   * the given thread has used, if supported.
226   *
227   * @param id the id of the thread to probe.
228   * @return the number of nanoseconds.
229   */
230  static long getThreadUserTime(long id) {
231    throw new UnimplementedError();
232  }
233
234  /**
235   * Returns the number of threads started.
236   *
237   * @return the number of started threads.
238   */
239  static long getTotalStartedThreadCount() {
240    return JMXSupport.getStartedThreadCount();
241  }
242
243  /**
244   * Resets the peak thread count.
245   */
246  static void resetPeakThreadCount() {
247    JMXSupport.resetPeakThreadCount();
248  }
249
250}