@Override public void changeEvent(DebuggerContextImpl newContext, DebuggerSession.Event event) { final DebuggerSession session = newContext.getDebuggerSession(); if (event == DebuggerSession.Event.PAUSE && myDebuggerStateManager.myDebuggerSession != session) { // if paused in non-active session; switch current session myDebuggerStateManager.setState( newContext, session != null ? session.getState() : DebuggerSession.State.DISPOSED, event, null); return; } if (myDebuggerStateManager.myDebuggerSession == session) { myDebuggerStateManager.fireStateChanged(newContext, event); } if (event == DebuggerSession.Event.ATTACHED) { myDispatcher.getMulticaster().sessionAttached(session); } else if (event == DebuggerSession.Event.DETACHED) { myDispatcher.getMulticaster().sessionDetached(session); } else if (event == DebuggerSession.Event.DISPOSE) { dispose(session); if (myDebuggerStateManager.myDebuggerSession == session) { myDebuggerStateManager.setState( DebuggerContextImpl.EMPTY_CONTEXT, DebuggerSession.State.DISPOSED, DebuggerSession.Event.DISPOSE, null); } } }
@Override @Nullable public DebuggerSession attachVirtualMachine(@NotNull DebugEnvironment environment) throws ExecutionException { ApplicationManager.getApplication().assertIsDispatchThread(); final DebugProcessEvents debugProcess = new DebugProcessEvents(myProject); debugProcess.addDebugProcessListener( new DebugProcessAdapter() { @Override public void processAttached(final DebugProcess process) { process.removeDebugProcessListener(this); for (Function<DebugProcess, PositionManager> factory : myCustomPositionManagerFactories) { final PositionManager positionManager = factory.fun(process); if (positionManager != null) { process.appendPositionManager(positionManager); } } for (PositionManagerFactory factory : Extensions.getExtensions(PositionManagerFactory.EP_NAME, myProject)) { final PositionManager manager = factory.createPositionManager(debugProcess); if (manager != null) { process.appendPositionManager(manager); } } } @Override public void processDetached(final DebugProcess process, final boolean closedByUser) { debugProcess.removeDebugProcessListener(this); } @Override public void attachException( final RunProfileState state, final ExecutionException exception, final RemoteConnection remoteConnection) { debugProcess.removeDebugProcessListener(this); } }); DebuggerSession session = DebuggerSession.create(environment.getSessionName(), debugProcess, environment); ExecutionResult executionResult = session.getProcess().getExecutionResult(); if (executionResult == null) { return null; } session.getContextManager().addListener(mySessionListener); getContextManager() .setState( DebuggerContextUtil.createDebuggerContext( session, session.getContextManager().getContext().getSuspendContext()), session.getState(), DebuggerSession.Event.CONTEXT, null); final ProcessHandler processHandler = executionResult.getProcessHandler(); synchronized (mySessions) { mySessions.put(processHandler, session); } if (!(processHandler instanceof RemoteDebugProcessHandler)) { // add listener only to non-remote process handler: // on Unix systems destroying process does not cause VMDeathEvent to be generated, // so we need to call debugProcess.stop() explicitly for graceful termination. // RemoteProcessHandler on the other hand will call debugProcess.stop() as a part of // destroyProcess() and detachProcess() implementation, // so we shouldn't add the listener to avoid calling stop() twice processHandler.addProcessListener( new ProcessAdapter() { @Override public void processWillTerminate(ProcessEvent event, boolean willBeDestroyed) { final DebugProcessImpl debugProcess = getDebugProcess(event.getProcessHandler()); if (debugProcess != null) { // if current thread is a "debugger manager thread", stop will execute synchronously // it is KillableColoredProcessHandler responsibility to terminate VM debugProcess.stop( willBeDestroyed && !(event.getProcessHandler() instanceof KillableColoredProcessHandler)); // wait at most 10 seconds: the problem is that debugProcess.stop() can hang if // there are troubles in the debuggee // if processWillTerminate() is called from AWT thread debugProcess.waitFor() will // block it and the whole app will hang if (!DebuggerManagerThreadImpl.isManagerThread()) { if (SwingUtilities.isEventDispatchThread()) { ProgressManager.getInstance() .runProcessWithProgressSynchronously( new Runnable() { @Override public void run() { ProgressManager.getInstance() .getProgressIndicator() .setIndeterminate(true); debugProcess.waitFor(10000); } }, "Waiting For Debugger Response", false, debugProcess.getProject()); } else { debugProcess.waitFor(10000); } } } } }); } myDispatcher.getMulticaster().sessionCreated(session); return session; }