static void invokeAndWait(@NotNull ModalityState modalityState, final @NotNull Runnable runnable) {
    ApplicationManager.getApplication().assertIsNonDispatchThread();

    final AtomicReference<Runnable> runnableRef = new AtomicReference<>(runnable);
    final Semaphore semaphore = new Semaphore();
    semaphore.down();
    final Ref<Throwable> exception = Ref.create();
    Runnable runnable1 = new Runnable() {
      @Override
      public void run() {
        Runnable runnable = runnableRef.getAndSet(null);
        if (runnable == null) {
          return;
        }
        try {
          runnable.run();
        }
        catch (Throwable e) {
          exception.set(e);
        }
        finally {
          semaphore.up();
        }
      }

      @Override
      public @NonNls String toString() {
        Runnable runnable = runnableRef.get();
        return "InvokeAndWait[" + (runnable == null ? "(cancelled)" : runnable.toString()) + "]";
      }
    };
    invokeLater(modalityState, Conditions.alwaysFalse(), runnable1);
    try {
      while (!semaphore.waitFor(ConcurrencyUtil.DEFAULT_TIMEOUT_MS)) {
        ProgressManager.checkCanceled();
      }
    }
    catch (Throwable e) {
      runnableRef.set(null);
      throw e;
    }
    if (!exception.isNull()) {
      Throwable cause = exception.get();
      if (SystemProperties.getBooleanProperty("invoke.later.wrap.error", true)) {
        // wrap everything to keep the current thread stacktrace
        // also TC ComparisonFailure feature depends on this
        throw new RuntimeException(cause);
      }
      else {
        ExceptionUtil.rethrow(cause);
      }
    }
  }
static void invokeAndWait(@NotNull ModalityState modalityState, final @NotNull Runnable runnable)