@Override
                public void run() {
                  boolean keepRunning = myKeepRunning;
                  try {
                    final JavacRemoteProto.Message result = compile(context, sessionId, options, files, cp, platformCp, modulePath, upgradeModulePath, srcPath, outs, new CanceledStatus() {
                      @Override
                      public boolean isCanceled() {
                        return Boolean.TRUE.equals(myCanceled.get(sessionId));
                      }
                    });
                    context.channel().writeAndFlush(result).awaitUninterruptibly();
                  }
                  catch (Throwable throwable) {
                    // in case of unexpected exception exit, to ensure the process is not stuck in a problematic state
                    keepRunning = false;
                    throwable.printStackTrace(System.err);
                    try {
                      // attempt to report via proto
                      context.channel().writeAndFlush(JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createFailure(throwable.getMessage(), throwable)));
                    }
                    catch (Throwable ignored) {
                    }
                  }
                  finally {
                    myCanceled.remove(sessionId); // state cleanup
                    if (keepRunning) {
                      JavacMain.clearCompilerZipFileCache();
                      //noinspection CallToSystemGC
                      System.gc();
                    }
                    else {
                      // in this mode this is only one-time compilation process that should stop after build is complete
                      ExternalJavacProcess.this.stop();
                    }
                    Thread.interrupted(); // reset interrupted status
                  }
                }
@Override
                public void run()