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 bfe8dd65e02f..0d9aa3f2e38b 100644 --- a/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java +++ b/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java @@ -21,6 +21,7 @@ import com.intellij.execution.ExecutionResult; import com.intellij.execution.Executor; import com.intellij.execution.configurations.*; import com.intellij.execution.executors.DefaultRunExecutor; +import com.intellij.execution.process.CapturingProcessAdapter; import com.intellij.execution.process.ProcessAdapter; import com.intellij.execution.process.ProcessEvent; import com.intellij.execution.process.ProcessHandler; @@ -28,23 +29,30 @@ import com.intellij.execution.runners.*; import com.intellij.execution.ui.ExecutionConsole; import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.icons.AllIcons; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CustomShortcutSet; -import com.intellij.openapi.actionSystem.Presentation; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; +import com.intellij.unscramble.AnalyzeStacktraceUtil; +import com.intellij.unscramble.ThreadDumpConsoleFactory; +import com.intellij.unscramble.ThreadDumpParser; +import com.intellij.unscramble.ThreadState; +import com.intellij.util.text.DateFormatUtil; import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; +import java.util.List; /** * @author spleaner */ public class DefaultJavaProgramRunner extends JavaPatchableProgramRunner { + private final static String ourWiseThreadDumpProperty = "idea.java.run.wise.thread.dump"; + @Override public boolean canRun(@NotNull final String executorId, @NotNull final RunProfile profile) { return executorId.equals(DefaultRunExecutor.EXECUTOR_ID) && @@ -166,11 +174,78 @@ public class DefaultJavaProgramRunner extends JavaPatchableProgramRunner { public void actionPerformed(final AnActionEvent e) { ProcessProxy proxy = ProcessProxyFactory.getInstance().getAttachedProxy(myProcessHandler); if (proxy != null) { + final WiseDumpThreadsListener wiseListener = Boolean.TRUE.equals(Boolean.getBoolean(ourWiseThreadDumpProperty)) ? + new WiseDumpThreadsListener(PlatformDataKeys.PROJECT.getData(e.getDataContext()), myProcessHandler) : null; + proxy.sendBreak(); + + if (wiseListener != null) { + wiseListener.after(); + } } } } + private static class WiseDumpThreadsListener { + private final Project myProject; + private final ProcessHandler myProcessHandler; + private final CapturingProcessAdapter myListener; + + public WiseDumpThreadsListener(final Project project, final ProcessHandler processHandler) { + myProject = project; + myProcessHandler = processHandler; + + myListener = new CapturingProcessAdapter(); + myProcessHandler.addProcessListener(myListener); + } + + public void after() { + if (myProject == null) { + myProcessHandler.removeProcessListener(myListener); + return; + } + ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { + @Override + public void run() { + if (myProcessHandler.isProcessTerminated() || myProcessHandler.isProcessTerminating()) return; + List threadStates = null; + final long start = System.currentTimeMillis(); + while ((System.currentTimeMillis() - start) < 1000) { + final String stdout = myListener.getOutput().getStdout(); + threadStates = ThreadDumpParser.parse(stdout); + if (threadStates == null || threadStates.isEmpty()) { + try { + Thread.sleep(50); + } + catch (InterruptedException e1) { + // + } + threadStates = null; + continue; + } + break; + } + myProcessHandler.removeProcessListener(myListener); + if (threadStates != null && ! threadStates.isEmpty()) { + showThreadDump(myListener.getOutput().getStdout(), threadStates); + } + } + + }); + } + + private void showThreadDump(final String out, final List threadStates) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + AnalyzeStacktraceUtil.addConsole(myProject, threadStates.size() > 1 ? + new ThreadDumpConsoleFactory(myProject, threadStates) : null, + " " + DateFormatUtil.formatDateTime(System.currentTimeMillis()), out); + } + }, ModalityState.NON_MODAL); + } + } + protected static class SoftExitAction extends LauncherBasedAction { public SoftExitAction(final ProcessHandler processHandler) { super(ExecutionBundle.message("run.configuration.exit.action.name"), null, AllIcons.Actions.Exit, processHandler); diff --git a/java/java-impl/src/com/intellij/unscramble/ThreadDumpConsoleFactory.java b/java/java-impl/src/com/intellij/unscramble/ThreadDumpConsoleFactory.java new file mode 100644 index 000000000000..94fa4f24575b --- /dev/null +++ b/java/java-impl/src/com/intellij/unscramble/ThreadDumpConsoleFactory.java @@ -0,0 +1,40 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.unscramble; + +import com.intellij.execution.ui.ConsoleView; +import com.intellij.openapi.actionSystem.DefaultActionGroup; +import com.intellij.openapi.project.Project; + +import javax.swing.*; +import java.util.List; + +/** +* Created by Irina.Chernushina on 7/13/13. +*/ +public class ThreadDumpConsoleFactory implements AnalyzeStacktraceUtil.ConsoleFactory { + private final Project myProject; + private final List myThreadDump; + + public ThreadDumpConsoleFactory(Project project, List threadDump) { + myProject = project; + myThreadDump = threadDump; + } + + public JComponent createConsoleComponent(ConsoleView consoleView, DefaultActionGroup toolbarActions) { + return new ThreadDumpPanel(myProject, consoleView, toolbarActions, myThreadDump); + } +} diff --git a/java/java-impl/src/com/intellij/unscramble/UnscrambleDialog.java b/java/java-impl/src/com/intellij/unscramble/UnscrambleDialog.java index 2627fd298b4e..37311251a2c0 100644 --- a/java/java-impl/src/com/intellij/unscramble/UnscrambleDialog.java +++ b/java/java-impl/src/com/intellij/unscramble/UnscrambleDialog.java @@ -15,12 +15,10 @@ */ package com.intellij.unscramble; -import com.intellij.execution.ui.ConsoleView; import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.icons.AllIcons; import com.intellij.ide.IdeBundle; import com.intellij.ide.util.PropertiesComponent; -import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.fileChooser.FileChooser; import com.intellij.openapi.fileChooser.FileChooserDescriptor; @@ -410,11 +408,7 @@ public class UnscrambleDialog extends DialogWrapper { message = IdeBundle.message("unscramble.unscrambled.deadlock.tab"); icon = AllIcons.Debugger.KillProcess; } - return AnalyzeStacktraceUtil.addConsole(project, threadDump.size() > 1 ? new AnalyzeStacktraceUtil.ConsoleFactory() { - public JComponent createConsoleComponent(ConsoleView consoleView, DefaultActionGroup toolbarActions) { - return new ThreadDumpPanel(project, consoleView, toolbarActions, threadDump); - } - } : null, message, unscrambledTrace, icon); + return AnalyzeStacktraceUtil.addConsole(project, threadDump.size() > 1 ? new ThreadDumpConsoleFactory(project, threadDump) : null, message, unscrambledTrace, icon); } protected String getDimensionServiceKey(){