1 /* 2 * Copyright (c) 2003, 2017, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.management; 27 28 import java.lang.management.ManagementFactory; 29 import java.lang.management.ThreadInfo; 30 import java.lang.management.ThreadMXBean; 31 import javax.management.ObjectName; 32 33 /** 34 * Implementation for java.lang.management.ThreadMXBean as well as providing the 35 * supporting method for com.sun.management.ThreadMXBean. 36 * The supporting method for com.sun.management.ThreadMXBean can be moved to 37 * jdk.management in the future. 38 */ 39 40 public class ThreadImpl implements ThreadMXBean { 41 private final VMManagement jvm; 42 43 // default for thread contention monitoring is disabled. 44 private boolean contentionMonitoringEnabled = false; 45 private boolean cpuTimeEnabled; 46 private boolean allocatedMemoryEnabled; 47 48 /** 49 * Constructor of ThreadImpl class. 50 */ 51 protected ThreadImpl(VMManagement vm) { 52 this.jvm = vm; 53 this.cpuTimeEnabled = jvm.isThreadCpuTimeEnabled(); 54 this.allocatedMemoryEnabled = jvm.isThreadAllocatedMemoryEnabled(); 55 } 56 57 @Override 58 public int getThreadCount() { 59 return jvm.getLiveThreadCount(); 60 } 61 62 @Override 63 public int getPeakThreadCount() { 64 return jvm.getPeakThreadCount(); 65 } 66 67 @Override 68 public long getTotalStartedThreadCount() { 69 return jvm.getTotalThreadCount(); 70 } 71 72 @Override 73 public int getDaemonThreadCount() { 74 return jvm.getDaemonThreadCount(); 75 } 76 77 @Override 78 public boolean isThreadContentionMonitoringSupported() { 79 return jvm.isThreadContentionMonitoringSupported(); 80 } 81 82 @Override 83 public synchronized boolean isThreadContentionMonitoringEnabled() { 84 if (!isThreadContentionMonitoringSupported()) { 85 throw new UnsupportedOperationException( 86 "Thread contention monitoring is not supported."); 87 } 88 return contentionMonitoringEnabled; 89 } 90 91 @Override 92 public boolean isThreadCpuTimeSupported() { 93 return jvm.isOtherThreadCpuTimeSupported(); 94 } 95 96 @Override 97 public boolean isCurrentThreadCpuTimeSupported() { 98 return jvm.isCurrentThreadCpuTimeSupported(); 99 } 100 101 protected boolean isThreadAllocatedMemorySupported() { 102 return jvm.isThreadAllocatedMemorySupported(); 103 } 104 105 @Override 106 public boolean isThreadCpuTimeEnabled() { 107 if (!isThreadCpuTimeSupported() && 108 !isCurrentThreadCpuTimeSupported()) { 109 throw new UnsupportedOperationException( 110 "Thread CPU time measurement is not supported"); 111 } 112 return cpuTimeEnabled; 113 } 114 115 protected boolean isThreadAllocatedMemoryEnabled() { 116 if (!isThreadAllocatedMemorySupported()) { 117 throw new UnsupportedOperationException( 118 "Thread allocated memory measurement is not supported"); 119 } 120 return allocatedMemoryEnabled; 121 } 122 123 @Override 124 public long[] getAllThreadIds() { 125 Util.checkMonitorAccess(); 126 127 Thread[] threads = getThreads(); 128 int length = threads.length; 129 long[] ids = new long[length]; 130 for (int i = 0; i < length; i++) { 131 Thread t = threads[i]; 132 ids[i] = t.getId(); 133 } 134 return ids; 135 } 136 137 @Override 138 public ThreadInfo getThreadInfo(long id) { 139 long[] ids = new long[1]; 140 ids[0] = id; 141 final ThreadInfo[] infos = getThreadInfo(ids, 0); 142 return infos[0]; 143 } 144 145 @Override 146 public ThreadInfo getThreadInfo(long id, int maxDepth) { 147 long[] ids = new long[1]; 148 ids[0] = id; 149 final ThreadInfo[] infos = getThreadInfo(ids, maxDepth); 150 return infos[0]; 151 } 152 153 @Override 154 public ThreadInfo[] getThreadInfo(long[] ids) { 155 return getThreadInfo(ids, 0); 156 } 157 158 private void verifyThreadIds(long[] ids) { 159 if (ids == null) { 160 throw new NullPointerException("Null ids parameter."); 161 } 162 163 for (int i = 0; i < ids.length; i++) { 164 if (ids[i] <= 0) { 165 throw new IllegalArgumentException( 166 "Invalid thread ID parameter: " + ids[i]); 167 } 168 } 169 } 170 171 @Override 172 public ThreadInfo[] getThreadInfo(long[] ids, int maxDepth) { 173 verifyThreadIds(ids); 174 175 if (maxDepth < 0) { 176 throw new IllegalArgumentException( 177 "Invalid maxDepth parameter: " + maxDepth); 178 } 179 180 // ids has been verified to be non-null 181 // an empty array of ids should return an empty array of ThreadInfos 182 if (ids.length == 0) return new ThreadInfo[0]; 183 184 Util.checkMonitorAccess(); 185 186 ThreadInfo[] infos = new ThreadInfo[ids.length]; // nulls 187 if (maxDepth == Integer.MAX_VALUE) { 188 getThreadInfo1(ids, -1, infos); 189 } else { 190 getThreadInfo1(ids, maxDepth, infos); 191 } 192 return infos; 193 } 194 195 @Override 196 public void setThreadContentionMonitoringEnabled(boolean enable) { 197 if (!isThreadContentionMonitoringSupported()) { 198 throw new UnsupportedOperationException( 199 "Thread contention monitoring is not supported"); 200 } 201 202 Util.checkControlAccess(); 203 204 synchronized (this) { 205 if (contentionMonitoringEnabled != enable) { 206 if (enable) { 207 // if reeabled, reset contention time statistics 208 // for all threads 209 resetContentionTimes0(0); 210 } 211 212 // update the VM of the state change 213 setThreadContentionMonitoringEnabled0(enable); 214 215 contentionMonitoringEnabled = enable; 216 } 217 } 218 } 219 220 private boolean verifyCurrentThreadCpuTime() { 221 // check if Thread CPU time measurement is supported. 222 if (!isCurrentThreadCpuTimeSupported()) { 223 throw new UnsupportedOperationException( 224 "Current thread CPU time measurement is not supported."); 225 } 226 return isThreadCpuTimeEnabled(); 227 } 228 229 @Override 230 public long getCurrentThreadCpuTime() { 231 if (verifyCurrentThreadCpuTime()) { 232 return getThreadTotalCpuTime0(0); 233 } 234 return -1; 235 } 236 237 @Override 238 public long getThreadCpuTime(long id) { 239 long[] ids = new long[1]; 240 ids[0] = id; 241 final long[] times = getThreadCpuTime(ids); 242 return times[0]; 243 } 244 245 private boolean verifyThreadCpuTime(long[] ids) { 246 verifyThreadIds(ids); 247 248 // check if Thread CPU time measurement is supported. 249 if (!isThreadCpuTimeSupported() && 250 !isCurrentThreadCpuTimeSupported()) { 251 throw new UnsupportedOperationException( 252 "Thread CPU time measurement is not supported."); 253 } 254 255 if (!isThreadCpuTimeSupported()) { 256 // support current thread only 257 for (int i = 0; i < ids.length; i++) { 258 if (ids[i] != Thread.currentThread().getId()) { 259 throw new UnsupportedOperationException( 260 "Thread CPU time measurement is only supported" + 261 " for the current thread."); 262 } 263 } 264 } 265 266 return isThreadCpuTimeEnabled(); 267 } 268 269 protected long[] getThreadCpuTime(long[] ids) { 270 boolean verified = verifyThreadCpuTime(ids); 271 272 int length = ids.length; 273 long[] times = new long[length]; 274 java.util.Arrays.fill(times, -1); 275 276 if (verified) { 277 if (length == 1) { 278 long id = ids[0]; 279 if (id == Thread.currentThread().getId()) { 280 id = 0; 281 } 282 times[0] = getThreadTotalCpuTime0(id); 283 } else { 284 getThreadTotalCpuTime1(ids, times); 285 } 286 } 287 return times; 288 } 289 290 @Override 291 public long getCurrentThreadUserTime() { 292 if (verifyCurrentThreadCpuTime()) { 293 return getThreadUserCpuTime0(0); 294 } 295 return -1; 296 } 297 298 @Override 299 public long getThreadUserTime(long id) { 300 long[] ids = new long[1]; 301 ids[0] = id; 302 final long[] times = getThreadUserTime(ids); 303 return times[0]; 304 } 305 306 protected long[] getThreadUserTime(long[] ids) { 307 boolean verified = verifyThreadCpuTime(ids); 308 309 int length = ids.length; 310 long[] times = new long[length]; 311 java.util.Arrays.fill(times, -1); 312 313 if (verified) { 314 if (length == 1) { 315 long id = ids[0]; 316 if (id == Thread.currentThread().getId()) { 317 id = 0; 318 } 319 times[0] = getThreadUserCpuTime0(id); 320 } else { 321 getThreadUserCpuTime1(ids, times); 322 } 323 } 324 return times; 325 } 326 327 @Override 328 public void setThreadCpuTimeEnabled(boolean enable) { 329 if (!isThreadCpuTimeSupported() && 330 !isCurrentThreadCpuTimeSupported()) { 331 throw new UnsupportedOperationException( 332 "Thread CPU time measurement is not supported"); 333 } 334 335 Util.checkControlAccess(); 336 synchronized (this) { 337 if (cpuTimeEnabled != enable) { 338 // notify VM of the state change 339 setThreadCpuTimeEnabled0(enable); 340 cpuTimeEnabled = enable; 341 } 342 } 343 } 344 345 protected long getThreadAllocatedBytes(long id) { 346 long[] ids = new long[1]; 347 ids[0] = id; 348 final long[] sizes = getThreadAllocatedBytes(ids); 349 return sizes[0]; 350 } 351 352 private boolean verifyThreadAllocatedMemory(long[] ids) { 353 verifyThreadIds(ids); 354 355 // check if Thread allocated memory measurement is supported. 356 if (!isThreadAllocatedMemorySupported()) { 357 throw new UnsupportedOperationException( 358 "Thread allocated memory measurement is not supported."); 359 } 360 361 return isThreadAllocatedMemoryEnabled(); 362 } 363 364 protected long[] getThreadAllocatedBytes(long[] ids) { 365 boolean verified = verifyThreadAllocatedMemory(ids); 366 367 long[] sizes = new long[ids.length]; 368 java.util.Arrays.fill(sizes, -1); 369 370 if (verified) { 371 getThreadAllocatedMemory1(ids, sizes); 372 } 373 return sizes; 374 } 375 376 protected void setThreadAllocatedMemoryEnabled(boolean enable) { 377 if (!isThreadAllocatedMemorySupported()) { 378 throw new UnsupportedOperationException( 379 "Thread allocated memory measurement is not supported."); 380 } 381 382 Util.checkControlAccess(); 383 synchronized (this) { 384 if (allocatedMemoryEnabled != enable) { 385 // notify VM of the state change 386 setThreadAllocatedMemoryEnabled0(enable); 387 allocatedMemoryEnabled = enable; 388 } 389 } 390 } 391 392 @Override 393 public long[] findMonitorDeadlockedThreads() { 394 Util.checkMonitorAccess(); 395 396 Thread[] threads = findMonitorDeadlockedThreads0(); 397 if (threads == null) { 398 return null; 399 } 400 401 long[] ids = new long[threads.length]; 402 for (int i = 0; i < threads.length; i++) { 403 Thread t = threads[i]; 404 ids[i] = t.getId(); 405 } 406 return ids; 407 } 408 409 @Override 410 public long[] findDeadlockedThreads() { 411 if (!isSynchronizerUsageSupported()) { 412 throw new UnsupportedOperationException( 413 "Monitoring of Synchronizer Usage is not supported."); 414 } 415 416 Util.checkMonitorAccess(); 417 418 Thread[] threads = findDeadlockedThreads0(); 419 if (threads == null) { 420 return null; 421 } 422 423 long[] ids = new long[threads.length]; 424 for (int i = 0; i < threads.length; i++) { 425 Thread t = threads[i]; 426 ids[i] = t.getId(); 427 } 428 return ids; 429 } 430 431 @Override 432 public void resetPeakThreadCount() { 433 Util.checkControlAccess(); 434 resetPeakThreadCount0(); 435 } 436 437 @Override 438 public boolean isObjectMonitorUsageSupported() { 439 return jvm.isObjectMonitorUsageSupported(); 440 } 441 442 @Override 443 public boolean isSynchronizerUsageSupported() { 444 return jvm.isSynchronizerUsageSupported(); 445 } 446 447 private void verifyDumpThreads(boolean lockedMonitors, 448 boolean lockedSynchronizers) { 449 if (lockedMonitors && !isObjectMonitorUsageSupported()) { 450 throw new UnsupportedOperationException( 451 "Monitoring of Object Monitor Usage is not supported."); 452 } 453 454 if (lockedSynchronizers && !isSynchronizerUsageSupported()) { 455 throw new UnsupportedOperationException( 456 "Monitoring of Synchronizer Usage is not supported."); 457 } 458 459 Util.checkMonitorAccess(); 460 } 461 462 @Override 463 public ThreadInfo[] getThreadInfo(long[] ids, 464 boolean lockedMonitors, 465 boolean lockedSynchronizers) { 466 return dumpThreads0(ids, lockedMonitors, lockedSynchronizers, 467 Integer.MAX_VALUE); 468 } 469 470 public ThreadInfo[] getThreadInfo(long[] ids, 471 boolean lockedMonitors, 472 boolean lockedSynchronizers, 473 int maxDepth) { 474 if (maxDepth < 0) { 475 throw new IllegalArgumentException( 476 "Invalid maxDepth parameter: " + maxDepth); 477 } 478 verifyThreadIds(ids); 479 // ids has been verified to be non-null 480 // an empty array of ids should return an empty array of ThreadInfos 481 if (ids.length == 0) return new ThreadInfo[0]; 482 483 verifyDumpThreads(lockedMonitors, lockedSynchronizers); 484 return dumpThreads0(ids, lockedMonitors, lockedSynchronizers, maxDepth); 485 } 486 487 @Override 488 public ThreadInfo[] dumpAllThreads(boolean lockedMonitors, 489 boolean lockedSynchronizers) { 490 return dumpAllThreads(lockedMonitors, lockedSynchronizers, 491 Integer.MAX_VALUE); 492 } 493 494 public ThreadInfo[] dumpAllThreads(boolean lockedMonitors, 495 boolean lockedSynchronizers, 496 int maxDepth) { 497 if (maxDepth < 0) { 498 throw new IllegalArgumentException( 499 "Invalid maxDepth parameter: " + maxDepth); 500 } 501 verifyDumpThreads(lockedMonitors, lockedSynchronizers); 502 return dumpThreads0(null, lockedMonitors, lockedSynchronizers, maxDepth); 503 } 504 505 // VM support where maxDepth == -1 to request entire stack dump 506 private static native Thread[] getThreads(); 507 private static native void getThreadInfo1(long[] ids, 508 int maxDepth, 509 ThreadInfo[] result); 510 private static native long getThreadTotalCpuTime0(long id); 511 private static native void getThreadTotalCpuTime1(long[] ids, long[] result); 512 private static native long getThreadUserCpuTime0(long id); 513 private static native void getThreadUserCpuTime1(long[] ids, long[] result); 514 private static native void getThreadAllocatedMemory1(long[] ids, long[] result); 515 private static native void setThreadCpuTimeEnabled0(boolean enable); 516 private static native void setThreadAllocatedMemoryEnabled0(boolean enable); 517 private static native void setThreadContentionMonitoringEnabled0(boolean enable); 518 private static native Thread[] findMonitorDeadlockedThreads0(); 519 private static native Thread[] findDeadlockedThreads0(); 520 private static native void resetPeakThreadCount0(); 521 private static native ThreadInfo[] dumpThreads0(long[] ids, 522 boolean lockedMonitors, 523 boolean lockedSynchronizers, 524 int maxDepth); 525 526 // tid == 0 to reset contention times for all threads 527 private static native void resetContentionTimes0(long tid); 528 529 @Override 530 public ObjectName getObjectName() { 531 return Util.newObjectName(ManagementFactory.THREAD_MXBEAN_NAME); 532 } 533 534 }