private void stopThread() {
   isDisposed = true;
   synchronized (documentsToCommit) {
     documentsToCommit.clear();
   }
   cancel("Stop thread");
   wakeUpQueue();
   while (!threadFinished) {
     wakeUpQueue();
     synchronized (documentsToCommit) {
       try {
         documentsToCommit.wait(10);
       } catch (InterruptedException ignored) {
       }
     }
   }
 }
 public void disable(@NonNls Object reason) {
   // write action has just started, all commits are useless
   cancel(reason);
   myEnabled = false;
   log("Disabled", null, false, reason);
 }
  @Override
  public void run() {
    threadFinished = false;
    while (!isDisposed) {
      try {
        boolean success = false;
        Document document = null;
        Project project = null;
        ProgressIndicator indicator = null;
        try {
          CommitTask task;
          synchronized (documentsToCommit) {
            if (!myEnabled || documentsToCommit.isEmpty()) {
              documentsToCommit.wait();
              continue;
            }
            task = documentsToCommit.pullFirst();
            document = task.document;
            indicator = task.indicator;
            project = task.project;

            log("Pulled", document, false, indicator);

            CommitStage commitStage = getCommitStage(document);
            Document[] uncommitted = null;
            if (commitStage != CommitStage.QUEUED_TO_COMMIT
                || project.isDisposed()
                || !ArrayUtil.contains(
                    document,
                    uncommitted =
                        PsiDocumentManager.getInstance(project).getUncommittedDocuments())) {
              List<Document> documents = uncommitted == null ? null : Arrays.asList(uncommitted);
              log("Abandon and proceeding to next", document, false, commitStage, documents);
              continue;
            }
            if (indicator.isRunning()) {
              useIndicator(indicator);
              document.putUserData(COMMIT_PROGRESS, indicator);
            } else {
              success = true; // document has been marked as removed, e.g. by synchronous commit
            }
          }

          Runnable finishRunnable = null;
          if (!success && !indicator.isCanceled()) {
            try {
              finishRunnable = commit(document, project, null, indicator, false, task.reason);
              success = finishRunnable != null;
              log("DCT.commit returned", document, false, finishRunnable, indicator);
            } finally {
              document.putUserData(COMMIT_PROGRESS, null);
            }
          }

          synchronized (documentsToCommit) {
            if (indicator.isCanceled()) {
              success = false;
            }
            if (success) {
              assert !ApplicationManager.getApplication().isDispatchThread();
              UIUtil.invokeLaterIfNeeded(finishRunnable);
              log(
                  "Invoked later finishRunnable",
                  document,
                  false,
                  success,
                  finishRunnable,
                  indicator);
            }
          }
        } catch (ProcessCanceledException e) {
          cancel(e); // leave queue unchanged
          log("PCE", document, false, e);
          success = false;
        } catch (InterruptedException e) {
          // app must be closing
          int i = 0;
          log("IE", document, false, e);
          cancel(e);
        } catch (Throwable e) {
          LOG.error(e);
          cancel(e);
        }
        synchronized (documentsToCommit) {
          if (!success && indicator.isRunning()) { // running means sync commit has not intervened
            // reset status for queue back successfully
            changeCommitStage(
                document, CommitStage.WAITING_FOR_PSI_APPLY, CommitStage.QUEUED_TO_COMMIT, false);
            changeCommitStage(document, CommitStage.COMMITTED, CommitStage.QUEUED_TO_COMMIT, false);
            doQueue(document, project, CommitStage.QUEUED_TO_COMMIT, "re-added on failure");
          }
        }
      } catch (Throwable e) {
        e.printStackTrace();
        // LOG.error(e);
      }
    }
    threadFinished = true;
    // ping the thread waiting for close
    wakeUpQueue();
    log("Good bye", null, false);
  }