GT-2875 - Unswingable - review fixes

This commit is contained in:
dragonmacher 2019-05-21 14:51:32 -04:00
parent 5e8340b7f8
commit 31f3cca1a5
27 changed files with 100 additions and 79 deletions

View file

@ -16,9 +16,7 @@
package ghidra.util;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
@ -159,51 +157,39 @@ public class Swing {
throws UnableToSwingException {
if (isInHeadlessMode() || SystemUtilities.isEventDispatchThread()) {
doRunSwing(r, true, SWING_RUN_ERROR_MSG);
doRun(r, true, SWING_RUN_ERROR_MSG);
return;
}
CountDownLatch start = new CountDownLatch(1);
CountDownLatch end = new CountDownLatch(1);
AtomicBoolean timedOut = new AtomicBoolean();
/*
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);
doRunSwing(() -> {
runLater(() -> {
start.countDown();
if (!waitFor(start)) {
return; // must have timed-out
}
try {
if (timedOut.get()) {
// timed-out waiting for Swing lock, but eventually did get the lock; too late now
return;
}
r.run();
}
finally {
end.countDown();
waitFor(end);
}
}, false, SWING_RUN_ERROR_MSG);
});
try {
timedOut.set(!start.await(timeout, unit));
}
catch (InterruptedException e) {
// handled below
}
if (timedOut.get()) {
if (!waitFor(start, timeout, unit)) {
throw new UnableToSwingException(
"Timed-out waiting for Swing thread lock in " + timeout + " " + unit);
}
// we've started; wait for the runnable with no timeout
try {
end.await();
}
catch (InterruptedException e) {
// we sometimes interrupt our tasks intentionally, so don't report it
}
waitFor(end);
}
/**
@ -213,7 +199,7 @@ public class Swing {
* @param r the runnable
*/
public static void runLater(Runnable r) {
doRunSwing(r, false, SWING_RUN_ERROR_MSG);
doRun(r, false, SWING_RUN_ERROR_MSG);
}
public static void runIfSwingOrRunLater(Runnable r) {
@ -230,33 +216,60 @@ public class Swing {
}
}
private static boolean waitFor(CyclicBarrier barrier, long timeout, TimeUnit unit) {
try {
barrier.await(timeout, unit);
return true;
}
catch (InterruptedException | BrokenBarrierException | TimeoutException e) {
// our Swing tasks may be interrupted from the framework
}
// timed-out or was interrupted
return false;
}
private static boolean waitFor(CyclicBarrier barrier) {
try {
barrier.await();
return true;
}
catch (InterruptedException | BrokenBarrierException e) {
// our Swing tasks may be interrupted from the framework
}
return false;
}
private static boolean isInHeadlessMode() {
return SystemUtilities.isInHeadlessMode();
}
private static void doRunSwing(Runnable r, boolean wait, String errorMessage) {
private static void doRun(Runnable r, boolean wait, String errorMessage) {
if (isInHeadlessMode()) {
r.run();
return;
}
if (wait) {
if (SwingUtilities.isEventDispatchThread()) {
r.run();
return;
}
try {
SwingUtilities.invokeAndWait(r);
}
catch (InterruptedException e) {
// we sometimes interrupt our tasks intentionally, so don't report it
}
catch (InvocationTargetException e) {
Msg.error(Swing.class, errorMessage + "\nException Message: " + e.getMessage(), e);
}
}
else {
if (!wait) {
SwingUtilities.invokeLater(r);
return;
}
if (SwingUtilities.isEventDispatchThread()) {
r.run();
return;
}
try {
SwingUtilities.invokeAndWait(r);
}
catch (InterruptedException e) {
// we sometimes interrupt our tasks intentionally, so don't report it
}
catch (InvocationTargetException e) {
Msg.error(Swing.class, errorMessage + "\nException Message: " + e.getMessage(), e);
}
}

View file

@ -0,0 +1,53 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package utility.function;
/**
* A generic functional interface that is more semantically sound than {@link Runnable}. Use
* anywhere you wish to have a generic callback function.
*/
@FunctionalInterface
public interface Callback {
/**
* Creates a dummy callback function. This is useful to avoid using <tt>null</tt>.
* @return a dummy callback function
*/
public static Callback dummy() {
return () -> {
// no-op
};
}
/**
* Returns the given callback object if it is not <tt>null</tt>. Otherwise, a {@link #dummy()}
* callback is returned. This is useful to avoid using <tt>null</tt>.
*
* @param c the callback function to check for <tt>null</tt>
* @return a non-null callback function
*/
public static Callback dummyIfNull(Callback c) {
if (c == null) {
return dummy();
}
return c;
}
/**
* The method that will be called.
*/
public void call();
}

View file

@ -0,0 +1,33 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package utility.function;
/**
* A generic functional interface that is more semantically sound than {@link Runnable}. Use
* anywhere you wish to have a generic callback function and you need to throw an exception.
*
* @param <E> the exception of your choice
*/
@FunctionalInterface
public interface ExceptionalCallback<E extends Exception> {
/**
* The method that will be called
*
* @throws Exception if the call throws an exception
*/
public void call() throws E;
}

View file

@ -0,0 +1,35 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package utility.function;
/**
* A generic functional interface that allows you to consume an item and potentially throw
* an exception.
*
* @param <T> the input type
* @param <E> the exception of your choice
*/
@FunctionalInterface
public interface ExceptionalConsumer<T, E extends Exception> {
/**
* The method that will be called
*
* @param t the input
* @throws E if the call throws an exception
*/
public void accept(T t) throws E;
}

View file

@ -0,0 +1,37 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package utility.function;
/**
* A generic functional interface that allows you to consume an item, return a result,
* and potentially throw an exception.
*
* @param <I> the input type
* @param <R> the result type
* @param <E> the exception of your choice
*/
@FunctionalInterface
public interface ExceptionalFunction<I, R, E extends Exception> {
/**
* The method that will be called
*
* @param i the input
* @return the result of the call
* @throws E if the call throws an exception
*/
public R apply(I i) throws E;
}