mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Task Launcher - updated timeout feature to ignore interruptions
This commit is contained in:
parent
fb2a4a0363
commit
2cf9f7dded
11 changed files with 240 additions and 344 deletions
|
@ -101,6 +101,36 @@ public class Swing {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the given runnable on the Swing thread in the future by putting the request on
|
||||
* the back of the event queue.
|
||||
*
|
||||
* @param r the runnable
|
||||
*/
|
||||
public static void runLater(Runnable r) {
|
||||
doRun(r, false, SWING_RUN_ERROR_MSG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the given runnable now if the caller is on the Swing thread. Otherwise, the
|
||||
* runnable will be posted later.
|
||||
*
|
||||
* @param r the runnable
|
||||
*/
|
||||
public static void runIfSwingOrRunLater(Runnable r) {
|
||||
if (isInHeadlessMode()) {
|
||||
r.run();
|
||||
return;
|
||||
}
|
||||
|
||||
if (SwingUtilities.isEventDispatchThread()) {
|
||||
r.run();
|
||||
}
|
||||
else {
|
||||
SwingUtilities.invokeLater(r);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the given suppler on the Swing thread, blocking with a
|
||||
* {@link SwingUtilities#invokeAndWait(Runnable)} if not on the Swing thread.
|
||||
|
@ -136,8 +166,29 @@ public class Swing {
|
|||
runNow(r, SWING_TIMEOUT_SECONDS_VALUE, TimeUnit.SECONDS);
|
||||
}
|
||||
catch (UnableToSwingException e) {
|
||||
throw new RuntimeException("Timed-out waiting to run a Swing task--potential deadlock!",
|
||||
e);
|
||||
|
||||
//
|
||||
// Special Cases: if we are in production mode, then this is most likely a deadlock.
|
||||
// In that case, log the thread state. In development mode, it is possible for this
|
||||
// to happen while debugging. In that case, log a message, and then post the work
|
||||
// to be done without a timeout.
|
||||
//
|
||||
String warning = "Timed-out waiting to run a Swing task--potential deadlock!";
|
||||
if (SystemUtilities.isInReleaseMode()) {
|
||||
Throwable threadDump = ReflectionUtilities.createJavaFilteredThrowable();
|
||||
Msg.error(Swing.class, warning + "\nThreads State:\n" + threadDump);
|
||||
throw new RuntimeException(warning, e);
|
||||
}
|
||||
|
||||
//
|
||||
// dev or testing mode
|
||||
//
|
||||
|
||||
// note: using Swing.class for the originator does not work (presumably it conflicts
|
||||
// with another logger sharing its name. So, use the full name here.
|
||||
String originator = Swing.class.getName();
|
||||
Msg.debug(originator, warning + " Ignore this message if debugging");
|
||||
doRun(r, true, SWING_RUN_ERROR_MSG);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -172,7 +223,7 @@ public class Swing {
|
|||
runLater(() -> {
|
||||
|
||||
if (!waitFor(start)) {
|
||||
return; // must have timed-out
|
||||
return; // interrupted or timed-out
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -185,53 +236,36 @@ public class Swing {
|
|||
});
|
||||
|
||||
if (!waitFor(start, timeout, unit)) {
|
||||
throw new UnableToSwingException(
|
||||
"Timed-out waiting for Swing thread lock in " + 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 in the future by putting the request on
|
||||
* the back of the event queue.
|
||||
*
|
||||
* @param r the runnable
|
||||
*/
|
||||
public static void runLater(Runnable r) {
|
||||
doRun(r, false, SWING_RUN_ERROR_MSG);
|
||||
}
|
||||
private static boolean waitFor(CyclicBarrier barrier, long timeout, TimeUnit unit)
|
||||
throws UnableToSwingException {
|
||||
|
||||
public static void runIfSwingOrRunLater(Runnable r) {
|
||||
if (isInHeadlessMode()) {
|
||||
r.run();
|
||||
return;
|
||||
}
|
||||
|
||||
if (SwingUtilities.isEventDispatchThread()) {
|
||||
r.run();
|
||||
}
|
||||
else {
|
||||
SwingUtilities.invokeLater(r);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean waitFor(CyclicBarrier barrier, long timeout, TimeUnit unit) {
|
||||
|
||||
try {
|
||||
barrier.await(timeout, unit);
|
||||
return true;
|
||||
}
|
||||
catch (InterruptedException | BrokenBarrierException | TimeoutException e) {
|
||||
catch (InterruptedException e) {
|
||||
// our Swing tasks may be interrupted from the framework
|
||||
}
|
||||
|
||||
catch (BrokenBarrierException | TimeoutException e) {
|
||||
throw new UnableToSwingException(
|
||||
"Timed-out waiting for Swing thread lock in " + timeout + " " + unit);
|
||||
}
|
||||
|
||||
// timed-out or was interrupted
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean waitFor(CyclicBarrier barrier) {
|
||||
|
||||
|
||||
try {
|
||||
barrier.await();
|
||||
return true;
|
||||
|
|
|
@ -18,6 +18,7 @@ package utilities.util.reflection;
|
|||
import java.io.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import ghidra.util.exception.AssertException;
|
||||
|
@ -158,8 +159,8 @@ public class ReflectionUtilities {
|
|||
* Get the first field specification contained within containingClass which has the type classType.
|
||||
* This method is only really useful if it is known that only a single field of
|
||||
* classType exists within the containingClass hierarchy.
|
||||
* @param classType
|
||||
* @param containingClass
|
||||
* @param classType the class
|
||||
* @param containingClass the class that contains a field of the given type
|
||||
* @return field which corresponds to type classType or null
|
||||
*/
|
||||
public static Field locateFieldByTypeOnClass(Class<?> classType, Class<?> containingClass) {
|
||||
|
@ -255,12 +256,11 @@ public class ReflectionUtilities {
|
|||
|
||||
/**
|
||||
* Finds the first occurrence of the given pattern and then stops filtering when it finds
|
||||
* something that is not that pattern.
|
||||
* something that is not that pattern
|
||||
*
|
||||
* @param trace the trace to update
|
||||
* @param patterns the non-regex patterns used to perform a
|
||||
* {@link String#contains(CharSequence)} on each {@link StackTraceElement}
|
||||
* line.
|
||||
* @param pattern the non-regex patterns used to perform a
|
||||
* {@link String#contains(CharSequence)} on each {@link StackTraceElement} line
|
||||
* @return the updated trace
|
||||
*/
|
||||
public static StackTraceElement[] movePastStackTracePattern(StackTraceElement[] trace,
|
||||
|
@ -355,6 +355,7 @@ public class ReflectionUtilities {
|
|||
* lines (e.g., AWT, Swing, Security, etc).
|
||||
* This can be useful for emitting diagnostic stack traces with reduced noise.
|
||||
*
|
||||
* @param t the throwable to filter
|
||||
* @return the throwable
|
||||
*/
|
||||
public static Throwable filterJavaThrowable(Throwable t) {
|
||||
|
@ -375,6 +376,26 @@ public class ReflectionUtilities {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string which is a printout of a stack trace for each thread running in the
|
||||
* current JVM
|
||||
* @return the stack trace string
|
||||
*/
|
||||
public static String createStackTraceForAllThreads() {
|
||||
Map<Thread, StackTraceElement[]> allStackTraces = Thread.getAllStackTraces();
|
||||
Set<Entry<Thread, StackTraceElement[]>> entrySet = allStackTraces.entrySet();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (Entry<Thread, StackTraceElement[]> entry : entrySet) {
|
||||
builder.append("Thread: " + entry.getKey().getName()).append('\n');
|
||||
StackTraceElement[] value = entry.getValue();
|
||||
for (StackTraceElement stackTraceElement : value) {
|
||||
builder.append('\t').append("at ").append(stackTraceElement).append('\n');
|
||||
}
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ordered set of interfaces and classes that are shared amongst the items in
|
||||
* the list.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue