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();
     }
   }
 }
  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 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;
    }
  @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);
  }