From fbf3359e13e58b64ac3b5f7980a919e59da5f8a5 Mon Sep 17 00:00:00 2001 From: Egor Ushakov Date: Mon, 22 Oct 2018 17:37:04 +0300 Subject: [PATCH] IDEA-142157 "Dump Threads" action in Run panel should open dump view --- .../impl/DefaultJavaProgramRunner.java | 55 ++++++++++++++++--- .../util/resources/misc/registry.properties | 2 + 2 files changed, 48 insertions(+), 9 deletions(-) diff --git a/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java b/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java index 9d547f5d3b01..3aa4a67769bf 100644 --- a/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java +++ b/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java @@ -22,10 +22,13 @@ import com.intellij.openapi.actionSystem.CustomShortcutSet; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.io.StreamUtil; import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.unscramble.AnalyzeStacktraceUtil; import com.intellij.unscramble.ThreadDumpConsoleFactory; import com.intellij.unscramble.ThreadDumpParser; @@ -36,11 +39,16 @@ import com.intellij.util.text.DateFormatUtil; import com.intellij.xdebugger.XDebugProcess; import com.intellij.xdebugger.XDebuggerManager; import com.intellij.xdebugger.XDebuggerManagerListener; +import com.sun.tools.attach.AttachNotSupportedException; +import com.sun.tools.attach.VirtualMachine; import org.jetbrains.annotations.NotNull; +import sun.tools.attach.HotSpotVirtualMachine; import javax.swing.*; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; +import java.io.IOException; +import java.io.InputStream; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -49,6 +57,7 @@ import java.util.concurrent.atomic.AtomicBoolean; * @author spleaner */ public class DefaultJavaProgramRunner extends JavaPatchableProgramRunner { + private static final Logger LOG = Logger.getInstance(DefaultJavaProgramRunner.class); private final static String ourWiseThreadDumpProperty = "idea.java.run.wise.thread.dump"; public static final String DEFAULT_JAVA_RUNNER_ID = "Run"; @@ -200,9 +209,37 @@ public class DefaultJavaProgramRunner extends JavaPatchableProgramRunner { } @Override - protected void perform(AnActionEvent e, ProcessProxy proxy) { + protected void perform(AnActionEvent event, ProcessProxy proxy) { + if (Registry.is("execution.dump.threads.using.attach") && myProcessHandler instanceof BaseProcessHandler) { + // try vm attach first + VirtualMachine vm = null; + try { + vm = VirtualMachine.attach(String.valueOf(OSProcessUtil.getProcessID(((BaseProcessHandler)myProcessHandler).getProcess()))); + InputStream inputStream = ((HotSpotVirtualMachine)vm).remoteDataDump(); + String text = StreamUtil.readText(inputStream, CharsetToolkit.UTF8_CHARSET); + List threads = ThreadDumpParser.parse(text); + showThreadDump(text, threads, event.getProject()); + return; + } + catch (AttachNotSupportedException e) { + LOG.debug(e); + } + catch (Exception e) { + LOG.warn(e); + } + finally { + if (vm != null) { + try { + vm.detach(); + } + catch (IOException ignored) { + } + } + } + } + boolean wise = Boolean.getBoolean(ourWiseThreadDumpProperty); - WiseDumpThreadsListener wiseListener = wise ? new WiseDumpThreadsListener(e.getProject(), myProcessHandler) : null; + WiseDumpThreadsListener wiseListener = wise ? new WiseDumpThreadsListener(event.getProject(), myProcessHandler) : null; proxy.sendBreak(); @@ -321,17 +358,17 @@ public class DefaultJavaProgramRunner extends JavaPatchableProgramRunner { } myProcessHandler.removeProcessListener(myListener); if (threadStates != null && ! threadStates.isEmpty()) { - showThreadDump(myListener.getOutput().getStdout(), threadStates); + showThreadDump(myListener.getOutput().getStdout(), threadStates, myProject); } }); } + } - private void showThreadDump(String out, List states) { - AnalyzeStacktraceUtil.ConsoleFactory factory = states.size() > 1 ? new ThreadDumpConsoleFactory(myProject, states) : null; - String title = " " + DateFormatUtil.formatDateTime(System.currentTimeMillis()); - ApplicationManager.getApplication().invokeLater( - () -> AnalyzeStacktraceUtil.addConsole(myProject, factory, title, out), ModalityState.NON_MODAL); - } + private static void showThreadDump(String out, List states, Project project) { + AnalyzeStacktraceUtil.ConsoleFactory factory = states.size() > 1 ? new ThreadDumpConsoleFactory(project, states) : null; + String title = "Dump " + DateFormatUtil.formatDateTime(System.currentTimeMillis()); + ApplicationManager.getApplication().invokeLater( + () -> AnalyzeStacktraceUtil.addConsole(project, factory, title, out), ModalityState.NON_MODAL); } protected static class SoftExitAction extends ProxyBasedAction { diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index a89e16ac1142..c43b9760c9cf 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -432,6 +432,8 @@ debugger.attach.to.process.action=true execution.java.always.debug=false execution.java.always.debug.description=Always run java processes with the debug agent +execution.dump.threads.using.attach=true +execution.dump.threads.using.attach.description=Use Java attach API to dump threads index.run.configuration.jre=false index.run.configuration.jre.restartRequired=true