public static void runNow(Runnable r, long timeout, TimeUnit unit)
			throws UnableToSwingException {

		if (isInHeadlessMode() || SystemUtilities.isEventDispatchThread()) {
			doRun(r, true, SWING_RUN_ERROR_MSG);
			return;
		}

		/*
		 	We use the CyclicBarrier to force this thread and the Swing thread to wait for each
		 	other.  This allows the calling thread to know if/when the Swing thread starts and 
		 	the Swing thread to know if the calling thread timed-out.
		 */
		CyclicBarrier start = new CyclicBarrier(2);
		CyclicBarrier end = new CyclicBarrier(2);

		runLater(() -> {

			if (!waitFor(start)) {
				return; // interrupted or timed-out
			}

			try {
				r.run();
			}
			finally {
				waitFor(end);
			}

		});

		if (!waitFor(start, timeout, unit)) {
			// Special case: if the wait() returns false, then it was interrupted.  If the 
			// timeout occurred, an exception would have been thrown.   Interrupts are expected, 
			// so just exit.
			return;
		}

		waitFor(end);
	}
Calls the given runnable on the Swing thread

<p>This method will throw an exception if the Swing thread is not available within the
given timeout.  This method is useful for preventing deadlocks.

@param r the runnable
@param timeout the timeout value
@param unit the time unit of the timeout value
@throws UnableToSwingException if the timeout was reach waiting for the Swing thread 
@see #runNow(Supplier) if you need to return a value from the Swing thread.
Ghidra/Framework/Utility/src/main/java/ghidra/util/Swing.java