< prev index next >

src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java

Print this page

        

*** 50,61 **** --- 50,63 ---- import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; + import java.util.HashMap; import java.util.HashSet; import java.util.List; + import java.util.Map; import java.util.ServiceLoader; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.LinkedBlockingQueue;
*** 473,482 **** --- 475,485 ---- */ @SuppressWarnings("try") private void compile(String classPath) throws IOException { final String[] entries = classPath.split(File.pathSeparator); long start = System.currentTimeMillis(); + Map<Thread, StackTraceElement[]> initialThreads = Thread.getAllStackTraces(); try { // compile dummy method to get compiler initialized outside of the // config debug override. HotSpotResolvedJavaMethod dummyMethod = (HotSpotResolvedJavaMethod) JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess().lookupJavaMethod(
*** 547,557 **** break; } classFileCounter++; ! if (className.startsWith("jdk.management.") || className.startsWith("jdk.internal.cmm.*")) { continue; } try { // Load and initialize class --- 550,566 ---- break; } classFileCounter++; ! if (className.startsWith("jdk.management.") || ! className.startsWith("jdk.internal.cmm.*") || ! // GR-5881: The class initializer for ! // sun.tools.jconsole.OutputViewer ! // spawns non-daemon threads for redirecting sysout and syserr. ! // These threads tend to cause deadlock at VM exit ! className.startsWith("sun.tools.jconsole.")) { continue; } try { // Load and initialize class
*** 641,650 **** --- 650,686 ---- TTY.println("CompileTheWorld : Done (%d classes, %d methods, %d ms elapsed, %d ms compile time, %d bytes of memory used)", classFileCounter, compiledMethodsCounter.get(), elapsedTime, compileTime.get(), memoryUsed.get()); } else { TTY.println("CompileTheWorld : Done (%d classes, %d methods, %d ms, %d bytes of memory used)", classFileCounter, compiledMethodsCounter.get(), compileTime.get(), memoryUsed.get()); } + + // Apart from the main thread, there should be only be daemon threads + // alive now. If not, then a class initializer has probably started + // a thread that could cause a deadlock while trying to exit the VM. + // One known example of this is sun.tools.jconsole.OutputViewer which + // spawns threads to redirect sysout and syserr. To help debug such + // scenarios, the stacks of potentially problematic threads are dumped. + Map<Thread, StackTraceElement[]> suspiciousThreads = new HashMap<>(); + for (Map.Entry<Thread, StackTraceElement[]> e : Thread.getAllStackTraces().entrySet()) { + Thread thread = e.getKey(); + if (thread != Thread.currentThread() && !initialThreads.containsKey(thread) && !thread.isDaemon() && thread.isAlive()) { + suspiciousThreads.put(thread, e.getValue()); + } + } + if (!suspiciousThreads.isEmpty()) { + TTY.println("--- Non-daemon threads started during CTW ---"); + for (Map.Entry<Thread, StackTraceElement[]> e : suspiciousThreads.entrySet()) { + Thread thread = e.getKey(); + if (thread.isAlive()) { + TTY.println(thread.toString() + " " + thread.getState()); + for (StackTraceElement ste : e.getValue()) { + TTY.println("\tat " + ste); + } + } + } + TTY.println("---------------------------------------------"); + } } private synchronized void startThreads() { running = true; // Wake up any waiting threads
< prev index next >