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