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