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