mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
GP-249 - Task Dialog - fixed issue with task dialog appearing over user input dialog; fixed spin/sleep code
This commit is contained in:
parent
22fd0a24a3
commit
dc7e45762d
8 changed files with 172 additions and 185 deletions
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,51 +15,54 @@
|
|||
*/
|
||||
package generic.cache;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.util.timer.GTimer;
|
||||
import ghidra.util.timer.GTimerMonitor;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* A thread-safe pool class that knows how to create instances as needed. When clients are done
|
||||
* with the pooled item they then call {@link #release(Object)}.
|
||||
* A thread-safe pool that knows how to create instances as needed. When clients are done
|
||||
* with the pooled item they then call {@link #release(Object)}, thus enabling them to be
|
||||
* re-used in the future.
|
||||
*
|
||||
* <p>Calling {@link #setCleanupTimeout(long)} with a non-negative value will start a timer when
|
||||
* {@link #release(Object)} is called to {@link BasicFactory#dispose(Object)} any objects in the
|
||||
* pool. By default, the cleanup timer does not run.
|
||||
*
|
||||
* <p>Once {@link #dispose()} has been called on this class, items created or released will no
|
||||
* longer be pooled.
|
||||
*
|
||||
* @param <T> the type of object to pool
|
||||
*/
|
||||
public class CachingPool<T> {
|
||||
|
||||
private static final long TIMEOUT = 0;
|
||||
// Use -1 to signal the cleanup timer should not be used
|
||||
private static final long TIMEOUT = -1;
|
||||
|
||||
private AtomicBoolean isDisposed = new AtomicBoolean(false);
|
||||
private boolean isDisposed;
|
||||
private BasicFactory<T> factory;
|
||||
private Deque<T> cache = new ArrayDeque<T>();
|
||||
|
||||
private long disposeTimeout = TIMEOUT;
|
||||
private GTimerMonitor timerMonitor;
|
||||
private Runnable cleanupRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (CachingPool.this) {
|
||||
for (T t : cache) {
|
||||
factory.dispose(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new pool that uses the given factory to create new items as needed
|
||||
*
|
||||
* @param factory the factory used to create new items
|
||||
*/
|
||||
public CachingPool(BasicFactory<T> factory) {
|
||||
if (factory == null) {
|
||||
throw new IllegalArgumentException("factory cannot be null");
|
||||
}
|
||||
this.factory = factory;
|
||||
this.factory = Objects.requireNonNull(factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time to wait for released items to be automatically disposed. The
|
||||
* default is {@link #TIMEOUT}.
|
||||
*
|
||||
* Sets the time to wait for released items to be disposed by this pool by calling
|
||||
* {@link BasicFactory#dispose(Object)}. A negative timeout value signals to disable
|
||||
* the cleanup task.
|
||||
*
|
||||
* <p>When clients call {@link #get()}, the timer will not be running. It will be restarted
|
||||
* again once {@link #release(Object)} has been called.
|
||||
*
|
||||
* @param timeout the new timeout.
|
||||
*/
|
||||
public void setCleanupTimeout(long timeout) {
|
||||
|
@ -68,47 +70,60 @@ public class CachingPool<T> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns a cached or new {@link T}
|
||||
*
|
||||
* @return a cached or new {@link T}
|
||||
* Returns a cached or new {@code T}
|
||||
*
|
||||
* @return a cached or new {@code T}
|
||||
* @throws Exception if there is a problem instantiating a new instance
|
||||
*/
|
||||
public synchronized T get() throws Exception {
|
||||
cancel();
|
||||
if (cache.isEmpty()) {
|
||||
stopCleanupTimer();
|
||||
if (cache.isEmpty() || isDisposed) {
|
||||
return factory.create();
|
||||
}
|
||||
return cache.pop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals that the given object is no longer being used. The object will be placed back into
|
||||
* the pool until it is disposed via the cleanup timer, if it is running.
|
||||
* @param t the item to release
|
||||
*/
|
||||
public synchronized void release(T t) {
|
||||
restart();
|
||||
if (isDisposed.get()) {
|
||||
restartCleanupTimer();
|
||||
if (isDisposed) {
|
||||
factory.dispose(t);
|
||||
return;
|
||||
}
|
||||
cache.push(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers all pooled object to be disposed via this pool's factory. Future calls to
|
||||
* {@link #get()} will still create new objects, but the internal cache will no longer be used.
|
||||
*/
|
||||
public synchronized void dispose() {
|
||||
cancel();
|
||||
isDisposed.set(true);
|
||||
stopCleanupTimer();
|
||||
isDisposed = true;
|
||||
|
||||
disposeCachedItems();
|
||||
}
|
||||
|
||||
private synchronized void disposeCachedItems() {
|
||||
for (T t : cache) {
|
||||
factory.dispose(t);
|
||||
}
|
||||
}
|
||||
|
||||
private void cancel() {
|
||||
private void stopCleanupTimer() {
|
||||
if (timerMonitor != null) {
|
||||
timerMonitor.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private void restart() {
|
||||
private void restartCleanupTimer() {
|
||||
if (timerMonitor != null) {
|
||||
timerMonitor.cancel();
|
||||
}
|
||||
timerMonitor = GTimer.scheduleRunnable(disposeTimeout, cleanupRunnable);
|
||||
timerMonitor = GTimer.scheduleRunnable(disposeTimeout, this::disposeCachedItems);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,23 +15,32 @@
|
|||
*/
|
||||
package ghidra.util.timer;
|
||||
|
||||
import ghidra.util.Msg;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import ghidra.util.Msg;
|
||||
|
||||
/**
|
||||
* A class to schedule {@link Runnable}s to run after some delay, optionally repeating. This class
|
||||
* uses a {@link Timer} internally to schedule work. Clients of this class are given a monitor
|
||||
* that allows them to check on the state of the runnable, as well as to cancel the runnable.
|
||||
*/
|
||||
public class GTimer {
|
||||
private static Timer timer;
|
||||
private static GTimerMonitor DO_NOTHING_MONITOR = new DoNothingMonitor();
|
||||
|
||||
/**
|
||||
* Schedules a runnable for execution after the specified delay.
|
||||
* @param delay the time (in milliseconds) to wait before executing the runnable.
|
||||
* Schedules a runnable for execution after the specified delay. A delay value less than 0
|
||||
* will cause this timer to schedule nothing. This allows clients to use this timer class
|
||||
* with no added logic for managing timer enablement.
|
||||
*
|
||||
* @param delay the time (in milliseconds) to wait before executing the runnable. A negative
|
||||
* value signals not to run the timer--the callback will not be executed
|
||||
* @param callback the runnable to be executed.
|
||||
* @return a GTimerMonitor which allows the caller to cancel the timer and check its status.
|
||||
*/
|
||||
public static GTimerMonitor scheduleRunnable(long delay, Runnable callback) {
|
||||
if (delay <= 0) {
|
||||
if (delay < 0) {
|
||||
return DO_NOTHING_MONITOR;
|
||||
}
|
||||
GTimerTask gTimerTask = new GTimerTask(callback);
|
||||
|
@ -41,14 +49,22 @@ public class GTimer {
|
|||
}
|
||||
|
||||
/**
|
||||
* Schedules a runnable for <b>repeated</b> execution after the specified delay.
|
||||
*
|
||||
* @param delay the time (in milliseconds) to wait before executing the runnable.
|
||||
* @param period time in milliseconds between successive runnable executions.
|
||||
* @param callback the runnable to be executed.
|
||||
* @return a GTimerMonitor which allows the caller to cancel the timer and check its status.
|
||||
* Schedules a runnable for <b>repeated</b> execution after the specified delay. A delay value
|
||||
* less than 0 will cause this timer to schedule nothing. This allows clients to use this
|
||||
* timer class with no added logic for managing timer enablement.
|
||||
*
|
||||
* @param delay the time (in milliseconds) to wait before executing the runnable. A negative
|
||||
* value signals not to run the timer--the callback will not be executed
|
||||
* @param period time in milliseconds between successive runnable executions
|
||||
* @param callback the runnable to be executed
|
||||
* @return a GTimerMonitor which allows the caller to cancel the timer and check its status
|
||||
* @throws IllegalArgumentException if {@code period <= 0}
|
||||
*/
|
||||
public static GTimerMonitor scheduleRepeatingRunnable(long delay, long period, Runnable callback) {
|
||||
public static GTimerMonitor scheduleRepeatingRunnable(long delay, long period,
|
||||
Runnable callback) {
|
||||
if (delay < 0) {
|
||||
return DO_NOTHING_MONITOR;
|
||||
}
|
||||
GTimerTask gTimerTask = new GTimerTask(callback);
|
||||
getTimer().schedule(gTimerTask, delay, period);
|
||||
return gTimerTask;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue