GP-994: Improve error reporting when GADP-based models fail to start

This commit is contained in:
Dan 2022-11-08 16:37:40 -05:00
parent 7a92882ba3
commit b4d2cb75ba
14 changed files with 80 additions and 16 deletions

View file

@ -277,10 +277,12 @@ public class AsyncLock {
/**
* Queue a sequence of actions on this lock
*
* <p>
* The lock will be acquired before executing the first action of the sequence, and the hold
* will be automatically released upon completion, whether normal or exceptional. The first
* action receives a reference to the hold, which may be used to re-enter the lock.
*
* <p>
* If the sequence stalls, i.e., an action never completes, it will cause deadlock.
*
* @param type the type "returned" by the sequence
@ -297,6 +299,7 @@ public class AsyncLock {
/**
* Queue a sequence of actions on this lock
*
* <p>
* Identical to {@link #with(TypeSpec, Hold)} except that the acquired hold is stored into an
* atomic reference rather than passed to the first action.
*

View file

@ -18,7 +18,8 @@ package ghidra.async;
import java.lang.ref.Cleaner.Cleanable;
import java.lang.ref.WeakReference;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.RejectedExecutionException;
import java.util.function.Function;
import java.util.function.Predicate;
@ -375,7 +376,7 @@ public class AsyncReference<T, C> {
}
}
ExecutionException ex = new ExecutionException("Disposed", reason);
DisposedException ex = new DisposedException(reason);
for (CompletableFuture<?> future : toExcept) {
future.completeExceptionally(ex);
}

View file

@ -0,0 +1,22 @@
/* ###
* 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 ghidra.async;
public class DisposedException extends RuntimeException {
public DisposedException(Throwable reason) {
super(reason);
}
}

View file

@ -38,6 +38,7 @@ public class AsyncSequenceWithoutTemp<R> {
/**
* Construct a new sequence without a temporary value
*
* <p>
* Do not call this directly. Please use {@link AsyncUtils#sequence(TypeSpec)}.
*
* @param seqResult the result of the whole sequence, passed to each appended sequence
@ -180,6 +181,7 @@ public class AsyncSequenceWithoutTemp<R> {
/**
* Finish defining this sequence of actions and obtain its future result
*
* <p>
* When an action in the sequence calls {@link AsyncHandlerCanExit#exit(Object, Throwable)}, the
* returned {@link CompletableFuture} is completed. If any action completes exceptionally, the
* returned {@link CompletableFuture} is completed exceptionally. If the final action executes,
@ -197,13 +199,17 @@ public class AsyncSequenceWithoutTemp<R> {
/**
* Register an action to execute on sequence completion
*
* <p>
* All registered actions are submitted for execution simultaneously when an action in the
* sequence calls {@link AsyncHandlerCanExit#exit(Object, Throwable)}. This is useful for
* methods that begin executing sequences "with a context". It is roughly equivalent to a
* {@code finally} block. On-exit actions can be registered before other actions are appended to
* the chain.
*
* An uncaught exception in an on-exit action will simply be logged and ignored.
* <p>
* If the sequence completes exceptionally, that exception is passed to the action. This method
* cannot be used to handle the exception, since this method returns this same sequence, not the
* resulting one. An uncaught exception in an on-exit action will simply be logged and ignored.
*
* @param action the action to execute
*/

View file

@ -87,6 +87,18 @@ public class AsyncLockTest {
}).finish();
}
@Test
public void testWithError() throws Throwable {
AsyncLock l = new AsyncLock();
int result = l.with(TypeSpec.INT, null).then((own, seq) -> {
throw new AssertionError("Blargh");
}).finish().exceptionally(exc -> {
return 0xdead;
}).get(1000, TimeUnit.MILLISECONDS);
assertEquals(0xdead, result);
}
@Test
public void testReentry() {
// This is very contrived. A real use would pass ownership to some method which cannot