@Override
  public int execute(
      final OverthereExecutionOutputHandler stdoutHandler,
      final OverthereExecutionOutputHandler stderrHandler,
      final CmdLine commandLine) {
    final OverthereProcess process = startProcess(commandLine);
    Thread stdoutReaderThread = null;
    Thread stderrReaderThread = null;
    final CountDownLatch latch = new CountDownLatch(2);
    try {
      stdoutReaderThread =
          getThread("stdout", commandLine.toString(), stdoutHandler, process.getStdout(), latch);
      stdoutReaderThread.start();

      stderrReaderThread =
          getThread("stderr", commandLine.toString(), stderrHandler, process.getStderr(), latch);
      stderrReaderThread.start();

      try {
        latch.await();
        return process.waitFor();
      } catch (InterruptedException exc) {
        Thread.currentThread().interrupt();

        logger.info("Execution interrupted, destroying the process.");
        process.destroy();

        throw new RuntimeIOException("Execution interrupted", exc);
      }
    } finally {
      quietlyJoinThread(stdoutReaderThread);
      quietlyJoinThread(stderrReaderThread);
    }
  }
 private void quietlyJoinThread(final Thread thread) {
   if (thread != null) {
     try {
       // interrupt the thread in case it is stuck waiting for output that will never come
       thread.interrupt();
       thread.join();
     } catch (InterruptedException ignored) {
       Thread.currentThread().interrupt();
     }
   }
 }