private void startProcess(Target target, Parameters configuration, Pair<Target, Parameters> key) {
    ProgramRunner runner =
        new DefaultProgramRunner() {
          @NotNull
          public String getRunnerId() {
            return "MyRunner";
          }

          public boolean canRun(@NotNull String executorId, @NotNull RunProfile profile) {
            return true;
          }
        };
    Executor executor = DefaultRunExecutor.getRunExecutorInstance();
    ProcessHandler processHandler = null;
    try {
      RunProfileState state = getRunProfileState(target, configuration, executor);
      ExecutionResult result = state.execute(executor, runner);
      //noinspection ConstantConditions
      processHandler = result.getProcessHandler();
    } catch (Exception e) {
      dropProcessInfo(key, ExceptionUtil.getUserStackTrace(e, LOG), processHandler);
      return;
    }
    processHandler.addProcessListener(getProcessListener(key));
    processHandler.startNotify();
  }
 boolean isEnabled() {
   ProcessHandler processHandler = myDescriptor.getProcessHandler();
   boolean isTerminating = processHandler != null && processHandler.isProcessTerminating();
   boolean isStarting =
       ExecutorRegistry.getInstance()
           .isStarting(myEnvironment.getProject(), myExecutor.getId(), myRunner.getRunnerId());
   return !isStarting && !isTerminating;
 }
 public static void restartIfActive(@NotNull RunContentDescriptor descriptor) {
   ProcessHandler processHandler = descriptor.getProcessHandler();
   if (processHandler != null
       && processHandler.isStartNotified()
       && !processHandler.isProcessTerminating()
       && !processHandler.isProcessTerminated()) {
     restart(descriptor);
   }
 }
 private static boolean isTerminated(final Content content) {
   final RunContentDescriptor descriptor = getRunContentDescriptorByContent(content);
   if (descriptor == null) {
     return true;
   } else {
     final ProcessHandler processHandler = descriptor.getProcessHandler();
     return processHandler == null || processHandler.isProcessTerminated();
   }
 }
  @Override
  public void update(final AnActionEvent event) {
    final Presentation presentation = event.getPresentation();
    String name = myEnvironment.getRunProfile().getName();
    ProcessHandler processHandler = myDescriptor.getProcessHandler();
    final boolean isRunning = processHandler != null && !processHandler.isProcessTerminated();

    presentation.setText(ExecutionBundle.message("rerun.configuration.action.name", name));
    presentation.setIcon(isRunning ? AllIcons.Actions.Restart : myExecutor.getIcon());
    presentation.setEnabled(isEnabled());
  }
  private void initConsoleUI(Process process) {
    // Init console view
    myConsoleView = createConsoleView();
    myConsoleView.setBorder(new SideBorder(UIUtil.getBorderColor(), SideBorder.LEFT));

    myProcessHandler = createProcessHandler(process, myProvider.getCommandLineString());

    myConsoleExecuteActionHandler = createConsoleExecuteActionHandler();

    ProcessTerminatedListener.attach(myProcessHandler);

    myProcessHandler.addProcessListener(
        new ProcessAdapter() {
          @Override
          public void processTerminated(ProcessEvent event) {
            finishConsole();
          }
        });

    // Attach to process
    myConsoleView.attachToProcess(myProcessHandler);

    // Runner creating
    final Executor defaultExecutor =
        ExecutorRegistry.getInstance().getExecutorById(DefaultRunExecutor.EXECUTOR_ID);
    final DefaultActionGroup toolbarActions = new DefaultActionGroup();
    final ActionToolbar actionToolbar =
        ActionManager.getInstance()
            .createActionToolbar(ActionPlaces.UNKNOWN, toolbarActions, false);

    // Runner creating
    final JPanel panel = new JPanel(new BorderLayout());
    panel.add(actionToolbar.getComponent(), BorderLayout.WEST);
    panel.add(myConsoleView.getComponent(), BorderLayout.CENTER);

    actionToolbar.setTargetComponent(panel);

    final RunContentDescriptor contentDescriptor =
        new RunContentDescriptor(
            myConsoleView, myProcessHandler, panel, constructConsoleTitle(myConsoleTitle));

    // tool bar actions
    final List<AnAction> actions =
        fillToolBarActions(toolbarActions, defaultExecutor, contentDescriptor);
    registerActionShortcuts(actions, getLanguageConsole().getConsoleEditor().getComponent());
    registerActionShortcuts(actions, panel);
    panel.updateUI();
    showConsole(defaultExecutor, contentDescriptor);

    // Run
    myProcessHandler.startNotify();
  }
 public void release(@NotNull Target target, @Nullable Parameters configuration) {
   ArrayList<ProcessHandler> handlers = new ArrayList<ProcessHandler>();
   synchronized (myProcMap) {
     for (Pair<Target, Parameters> pair : myProcMap.keySet()) {
       if (pair.first == target && (configuration == null || pair.second == configuration)) {
         ContainerUtil.addIfNotNull(myProcMap.get(pair).handler, handlers);
       }
     }
   }
   for (ProcessHandler handler : handlers) {
     handler.destroyProcess();
   }
   fireModificationCountChanged();
 }
 public void stopAll(boolean wait) {
   ArrayList<ProcessHandler> allHandlers = new ArrayList<ProcessHandler>();
   synchronized (myProcMap) {
     for (Info o : myProcMap.values()) {
       ContainerUtil.addIfNotNull(o.handler, allHandlers);
     }
   }
   for (ProcessHandler handler : allHandlers) {
     handler.destroyProcess();
   }
   if (wait) {
     for (ProcessHandler handler : allHandlers) {
       handler.waitFor();
     }
   }
 }
  public void waitProcess(@NotNull final ProcessHandler processHandler) {
    Alarm alarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD, getTestRootDisposable());

    final boolean[] isRunning = {true};
    alarm.addRequest(
        new Runnable() {
          @Override
          public void run() {
            boolean b;
            synchronized (isRunning) {
              b = isRunning[0];
            }
            if (b) {
              processHandler.destroyProcess();
              LOG.error("process was running over " + myTimeout / 1000 + " seconds. Interrupted. ");
            }
          }
        },
        myTimeout);
    processHandler.waitFor();
    synchronized (isRunning) {
      isRunning[0] = false;
    }
    Disposer.dispose(alarm);
  }
 @NotNull
 public List<RunContentDescriptor> getRunningDescriptors(
     @NotNull Condition<RunnerAndConfigurationSettings> condition) {
   List<RunContentDescriptor> result = new SmartList<>();
   for (Trinity<RunContentDescriptor, RunnerAndConfigurationSettings, Executor> trinity :
       myRunningConfigurations) {
     if (trinity.getSecond() != null && condition.value(trinity.getSecond())) {
       ProcessHandler processHandler = trinity.getFirst().getProcessHandler();
       if (processHandler != null /*&& !processHandler.isProcessTerminating()*/
           && !processHandler.isProcessTerminated()) {
         result.add(trinity.getFirst());
       }
     }
   }
   return result;
 }
 public void update(final AnActionEvent e) {
   final EditorEx editor = myLanguageConsole.getConsoleEditor();
   final Lookup lookup = LookupManager.getActiveLookup(editor);
   e.getPresentation()
       .setEnabled(
           !editor.isRendererMode()
               && !myProcessHandler.isProcessTerminated()
               && (lookup == null || !(lookup.isCompletion() && lookup.isFocused())));
 }
 public void attachToProcess(
     @NotNull final ProcessHandler handler,
     @NotNull final RunConfigurationBase configuration,
     final RunnerSettings runnerSettings) {
   handler.addProcessListener(
       new ProcessAdapter() {
         public void processTerminated(final ProcessEvent event) {
           processGatheredCoverage(configuration, runnerSettings);
         }
       });
 }
 protected void assertOutput(String className, String expected, final Module module)
     throws ExecutionException {
   final StringBuffer sb = new StringBuffer();
   ProcessHandler process =
       runProcess(
           className,
           module,
           DefaultRunExecutor.class,
           new ProcessAdapter() {
             @Override
             public void onTextAvailable(ProcessEvent event, Key outputType) {
               if (ProcessOutputTypes.SYSTEM != outputType) {
                 sb.append(event.getText());
               }
             }
           },
           ProgramRunner.PROGRAM_RUNNER_EP.findExtension(DefaultJavaProgramRunner.class));
   process.waitFor();
   assertEquals(expected.trim(), StringUtil.convertLineSeparators(sb.toString().trim()));
 }
  private String constructConsoleTitle(final @NotNull String consoleTitle) {
    if (shouldAddNumberToTitle()) {
      List<RunContentDescriptor> consoles =
          ExecutionHelper.collectConsolesByDisplayName(
              myProject,
              new NotNullFunction<String, Boolean>() {
                @NotNull
                @Override
                public Boolean fun(String dom) {
                  return dom.contains(consoleTitle);
                }
              });
      int max = 0;
      for (RunContentDescriptor dsc : consoles) {
        ProcessHandler handler = dsc.getProcessHandler();
        if (handler != null && !handler.isProcessTerminated()) {
          if (max == 0) {
            max = 1;
          }
          try {
            int num =
                Integer.parseInt(
                    dsc.getDisplayName()
                        .substring(consoleTitle.length() + 1, dsc.getDisplayName().length() - 1));
            if (num > max) {
              max = num;
            }
          } catch (Exception e) {
            // skip
          }
        }
      }
      if (max >= 1) {
        return consoleTitle + "(" + (max + 1) + ")";
      }
    }

    return consoleTitle;
  }
  private static boolean askForClosingDebugSessions(@NotNull Project project) {
    final List<Pair<ProcessHandler, RunContentDescriptor>> pairs =
        new ArrayList<Pair<ProcessHandler, RunContentDescriptor>>();

    for (Project p : ProjectManager.getInstance().getOpenProjects()) {
      final ProcessHandler[] processes = ExecutionManager.getInstance(p).getRunningProcesses();

      for (ProcessHandler process : processes) {
        if (!process.isProcessTerminated()) {
          final AndroidSessionInfo info =
              process.getUserData(AndroidDebugRunner.ANDROID_SESSION_INFO);
          if (info != null) {
            pairs.add(Pair.create(process, info.getDescriptor()));
          }
        }
      }
    }

    if (pairs.size() == 0) {
      return true;
    }

    final StringBuilder s = new StringBuilder();

    for (Pair<ProcessHandler, RunContentDescriptor> pair : pairs) {
      if (s.length() > 0) {
        s.append('\n');
      }
      s.append(pair.getSecond().getDisplayName());
    }

    final int r =
        Messages.showYesNoDialog(
            project,
            AndroidBundle.message("android.debug.sessions.will.be.closed", s),
            AndroidBundle.message("android.disable.adb.service.title"),
            Messages.getQuestionIcon());
    return r == Messages.YES;
  }
    private boolean closeQuery() {
      final RunContentDescriptor descriptor = getRunContentDescriptorByContent(myContent);

      if (descriptor == null) {
        return true;
      }

      final ProcessHandler processHandler = descriptor.getProcessHandler();
      if (processHandler == null
          || processHandler.isProcessTerminated()
          || processHandler.isProcessTerminating()) {
        return true;
      }
      final boolean destroyProcess;
      if (processHandler.isSilentlyDestroyOnClose()
          || Boolean.TRUE.equals(
              processHandler.getUserData(ProcessHandler.SILENTLY_DESTROY_ON_CLOSE))) {
        destroyProcess = true;
      } else {
        // todo[nik] this is a temporary solution for the following problem: some configurations
        // should not allow user to choose between 'terminating' and 'detaching'
        final boolean useDefault =
            Boolean.TRUE.equals(
                processHandler.getUserData(ALWAYS_USE_DEFAULT_STOPPING_BEHAVIOUR_KEY));
        final TerminateRemoteProcessDialog terminateDialog =
            new TerminateRemoteProcessDialog(
                myProject,
                descriptor.getDisplayName(),
                processHandler.detachIsDefault(),
                useDefault);
        terminateDialog.show();
        if (terminateDialog.getExitCode() != DialogWrapper.OK_EXIT_CODE) return false;
        destroyProcess = terminateDialog.forceTermination();
      }
      if (destroyProcess) {
        processHandler.destroyProcess();
      } else {
        processHandler.detachProcess();
      }
      waitForProcess(descriptor);
      return true;
    }
 @Override
 public void removeDebugProcessListener(
     final ProcessHandler processHandler, final DebugProcessListener listener) {
   DebugProcessImpl debugProcess = getDebugProcess(processHandler);
   if (debugProcess != null) {
     debugProcess.removeDebugProcessListener(listener);
   } else {
     processHandler.addProcessListener(
         new ProcessAdapter() {
           @Override
           public void startNotified(ProcessEvent event) {
             DebugProcessImpl debugProcess = getDebugProcess(processHandler);
             if (debugProcess != null) {
               debugProcess.removeDebugProcessListener(listener);
             }
             processHandler.removeProcessListener(this);
           }
         });
   }
 }
    @Override
    public void startNotify() {
      addProcessListener(
          new ProcessAdapter() {
            @Override
            public void startNotified(ProcessEvent event) {
              try {
                myWaitFor.setTerminationCallback(
                    new Consumer<Integer>() {
                      @Override
                      public void consume(Integer integer) {
                        notifyProcessTerminated(integer);
                      }
                    });
              } finally {
                removeProcessListener(this);
              }
            }
          });

      super.startNotify();
    }
  private static void stop(@Nullable RunContentDescriptor descriptor) {
    ProcessHandler processHandler = descriptor != null ? descriptor.getProcessHandler() : null;
    if (processHandler == null) {
      return;
    }

    if (processHandler instanceof KillableProcess && processHandler.isProcessTerminating()) {
      ((KillableProcess) processHandler).killProcess();
      return;
    }

    if (!processHandler.isProcessTerminated()) {
      if (processHandler.detachIsDefault()) {
        processHandler.detachProcess();
      } else {
        processHandler.destroyProcess();
      }
    }
  }
 private boolean isProcessTerminated() {
   return myServerProcessHandler.isProcessTerminating()
       || myServerProcessHandler.isProcessTerminated();
 }
 @Override
 public void attachToProcess(final ProcessHandler processHandler) {
   super.attachToProcess(processHandler);
   processHandler.addProcessListener(new MyProcessListener());
 }
  public void showRunContent(
      @NotNull final Executor executor, final RunContentDescriptor descriptor) {
    if (ApplicationManager.getApplication().isUnitTestMode()) return;

    final ContentManager contentManager = getContentManagerForRunner(executor);
    RunContentDescriptor oldDescriptor =
        chooseReuseContentForDescriptor(contentManager, descriptor);

    final Content content;

    if (oldDescriptor != null) {
      content = oldDescriptor.getAttachedContent();
      getSyncPublisher().contentRemoved(oldDescriptor, executor);
      oldDescriptor.dispose(); // is of the same category, can be reused
    } else {
      content = createNewContent(contentManager, descriptor, executor);
      final Icon icon = descriptor.getIcon();
      content.setIcon(icon == null ? executor.getToolWindowIcon() : icon);
    }

    content.setComponent(descriptor.getComponent());
    content.putUserData(DESCRIPTOR_KEY, descriptor);
    final ProcessHandler processHandler = descriptor.getProcessHandler();
    if (processHandler != null) {
      final ProcessAdapter processAdapter =
          new ProcessAdapter() {
            public void startNotified(final ProcessEvent event) {
              LaterInvocator.invokeLater(
                  new Runnable() {
                    public void run() {
                      final Icon icon = descriptor.getIcon();
                      content.setIcon(icon == null ? executor.getToolWindowIcon() : icon);
                    }
                  });
            }

            public void processTerminated(final ProcessEvent event) {
              LaterInvocator.invokeLater(
                  new Runnable() {
                    public void run() {
                      final Icon icon = descriptor.getIcon();
                      content.setIcon(
                          icon == null
                              ? executor.getDisabledIcon()
                              : IconLoader.getTransparentIcon(icon));
                    }
                  });
            }
          };
      processHandler.addProcessListener(processAdapter);
      final Disposable disposer = content.getDisposer();
      if (disposer != null) {
        Disposer.register(
            disposer,
            new Disposable() {
              public void dispose() {
                processHandler.removeProcessListener(processAdapter);
              }
            });
      }
    }
    content.setDisplayName(descriptor.getDisplayName());
    descriptor.setAttachedContent(content);
    content.getManager().setSelectedContent(content);

    ApplicationManager.getApplication()
        .invokeLater(
            new Runnable() {
              public void run() {
                ToolWindow window =
                    ToolWindowManager.getInstance(myProject)
                        .getToolWindow(executor.getToolWindowId());
                // let's activate tool window, but don't move focus
                //
                // window.show() isn't valid here, because it will not
                // mark the window as "last activated" windows and thus
                // some action like navigation up/down in stactrace wont
                // work correctly
                window.activate(null, false, false);
              }
            });
  }
  @NotNull
  @Override
  public JsonResponse handle(@NotNull UnityTestStatePostRequest request) {
    UUID uuid = UUID.fromString(request.uuid);
    Unity3dTestSession session = Unity3dTestSessionManager.getInstance().findSession(uuid);
    if (session == null) {
      return JsonResponse.asError("no session");
    }

    GeneralTestEventsProcessor processor = session.getProcessor();
    ProcessHandler processHandler = session.getProcessHandler();

    String name = request.name;
    switch (request.type) {
      case TestStarted:
        processor.onTestStarted(new TestStartedEvent(name, null));
        break;
      case TestIgnored:
        processor.onTestIgnored(
            new TestIgnoredEvent(name, StringUtil.notNullize(request.message), request.stackTrace));
        break;
      case TestFailed:
        processor.onTestFailure(
            new TestFailedEvent(
                name,
                StringUtil.notNullize(request.message),
                request.stackTrace,
                false,
                null,
                null));
        break;
      case TestOutput:
        boolean stdOut = "Log".equals(request.messageType) || "Warning".equals(request.messageType);
        StringBuilder builder = new StringBuilder(request.message);
        if (!stdOut) {
          builder.append("\n");
          String[] strings = StringUtil.splitByLines(request.stackTrace);
          for (String line : strings) {
            builder.append("  at ").append(line).append("\n");
          }
        }
        processor.onTestOutput(new TestOutputEvent(name, builder.toString(), stdOut));
        break;
      case TestFinished:
        long time = (long) (request.time * 1000L);
        processor.onTestFinished(new TestFinishedEvent(name, time));
        break;
      case SuiteStarted:
        processor.onSuiteStarted(new TestSuiteStartedEvent(name, null));
        break;
      case SuiteFinished:
        processor.onSuiteFinished(new TestSuiteFinishedEvent(name));
        break;
      case RunFinished:
        processor.onFinishTesting();
        processHandler.destroyProcess();
        break;
    }

    return JsonResponse.asSuccess(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;
  }
 private void reportInternal(String message, Key key) {
   myProcessHandler.notifyTextAvailable(message + "\n", key);
 }
 public static boolean isProcessRunning(@Nullable RunContentDescriptor descriptor) {
   ProcessHandler processHandler = descriptor == null ? null : descriptor.getProcessHandler();
   return processHandler != null && !processHandler.isProcessTerminated();
 }
  @Override
  public void startRunProfile(
      @NotNull final RunProfileStarter starter,
      @NotNull final RunProfileState state,
      @NotNull final ExecutionEnvironment environment) {
    final Project project = environment.getProject();
    RunContentDescriptor reuseContent = getContentManager().getReuseContent(environment);
    if (reuseContent != null) {
      reuseContent.setExecutionId(environment.getExecutionId());
      environment.setContentToReuse(reuseContent);
    }

    final Executor executor = environment.getExecutor();
    project
        .getMessageBus()
        .syncPublisher(EXECUTION_TOPIC)
        .processStartScheduled(executor.getId(), environment);

    Runnable startRunnable;
    startRunnable =
        () -> {
          if (project.isDisposed()) {
            return;
          }

          RunProfile profile = environment.getRunProfile();
          boolean started = false;
          try {
            project
                .getMessageBus()
                .syncPublisher(EXECUTION_TOPIC)
                .processStarting(executor.getId(), environment);

            final RunContentDescriptor descriptor = starter.execute(state, environment);
            if (descriptor != null) {
              final Trinity<RunContentDescriptor, RunnerAndConfigurationSettings, Executor>
                  trinity =
                      Trinity.create(
                          descriptor, environment.getRunnerAndConfigurationSettings(), executor);
              myRunningConfigurations.add(trinity);
              Disposer.register(descriptor, () -> myRunningConfigurations.remove(trinity));
              getContentManager()
                  .showRunContent(executor, descriptor, environment.getContentToReuse());
              final ProcessHandler processHandler = descriptor.getProcessHandler();
              if (processHandler != null) {
                if (!processHandler.isStartNotified()) {
                  processHandler.startNotify();
                }
                project
                    .getMessageBus()
                    .syncPublisher(EXECUTION_TOPIC)
                    .processStarted(executor.getId(), environment, processHandler);
                started = true;

                ProcessExecutionListener listener =
                    new ProcessExecutionListener(
                        project, executor.getId(), environment, processHandler, descriptor);
                processHandler.addProcessListener(listener);

                // Since we cannot guarantee that the listener is added before process handled is
                // start notified,
                // we have to make sure the process termination events are delivered to the clients.
                // Here we check the current process state and manually deliver events, while
                // the ProcessExecutionListener guarantees each such event is only delivered once
                // either by this code, or by the ProcessHandler.

                boolean terminating = processHandler.isProcessTerminating();
                boolean terminated = processHandler.isProcessTerminated();
                if (terminating || terminated) {
                  listener.processWillTerminate(
                      new ProcessEvent(processHandler), false /*doesn't matter*/);

                  if (terminated) {
                    //noinspection ConstantConditions
                    int exitCode = processHandler.getExitCode();
                    listener.processTerminated(new ProcessEvent(processHandler, exitCode));
                  }
                }
              }
              environment.setContentToReuse(descriptor);
            }
          } catch (ProcessCanceledException e) {
            LOG.info(e);
          } catch (ExecutionException e) {
            ExecutionUtil.handleExecutionError(project, executor.getToolWindowId(), profile, e);
            LOG.info(e);
          } finally {
            if (!started) {
              project
                  .getMessageBus()
                  .syncPublisher(EXECUTION_TOPIC)
                  .processNotStarted(executor.getId(), environment);
            }
          }
        };

    if (ApplicationManager.getApplication().isUnitTestMode() && !myForceCompilationInTests) {
      startRunnable.run();
    } else {
      compileAndRun(
          () -> TransactionGuard.submitTransaction(project, startRunnable),
          environment,
          state,
          () -> {
            if (!project.isDisposed()) {
              project
                  .getMessageBus()
                  .syncPublisher(EXECUTION_TOPIC)
                  .processNotStarted(executor.getId(), environment);
            }
          });
    }
  }