From 051b655604f7f3be1c73e5efc201a7e6b2ced04e Mon Sep 17 00:00:00 2001 From: Nelson Tavares de Sousa <ntd@informatik.uni-kiel.de> Date: Wed, 4 Feb 2015 13:58:06 +0100 Subject: [PATCH] solved #92 and modified how analysis handles thread exceptions; quick fixes for api change --- src/main/java/teetime/framework/Analysis.java | 30 ++++++++++++++++--- .../loopStage/FiniteSignalPassingTest.java | 15 +++++----- .../teetime/framework/ExceptionTestStage.java | 5 ++++ .../framework/RunnableConsumerStageTest.java | 14 ++------- .../stage/MultipleInstanceOfFilterTest.java | 12 ++++---- 5 files changed, 47 insertions(+), 29 deletions(-) diff --git a/src/main/java/teetime/framework/Analysis.java b/src/main/java/teetime/framework/Analysis.java index ab75d4b8..71f74619 100644 --- a/src/main/java/teetime/framework/Analysis.java +++ b/src/main/java/teetime/framework/Analysis.java @@ -11,6 +11,7 @@ import org.slf4j.LoggerFactory; import teetime.framework.exceptionHandling.IgnoringStageListener; import teetime.framework.exceptionHandling.StageExceptionListener; +import teetime.framework.signal.TerminatingSignal; import teetime.framework.signal.ValidatingSignal; import teetime.framework.validation.AnalysisNotValidException; import teetime.util.Pair; @@ -30,6 +31,8 @@ public class Analysis implements UncaughtExceptionHandler { private final StageExceptionListener listener; + private boolean executionInterrupted = false; + private final List<Thread> consumerThreads = new LinkedList<Thread>(); private final List<Thread> finiteProducerThreads = new LinkedList<Thread>(); private final List<Thread> infiniteProducerThreads = new LinkedList<Thread>(); @@ -138,7 +141,7 @@ public class Analysis implements UncaughtExceptionHandler { * * @return a collection of thread/throwable pairs */ - public Collection<Pair<Thread, Throwable>> start() { + public void start() { // start analysis startThreads(this.consumerThreads); startThreads(this.finiteProducerThreads); @@ -155,7 +158,6 @@ public class Analysis implements UncaughtExceptionHandler { } } catch (InterruptedException e) { LOGGER.error("Analysis has stopped unexpectedly", e); - for (Thread thread : this.finiteProducerThreads) { thread.interrupt(); } @@ -168,8 +170,10 @@ public class Analysis implements UncaughtExceptionHandler { for (Thread thread : this.infiniteProducerThreads) { thread.interrupt(); } - - return this.exceptions; + if (!exceptions.isEmpty()) { + throw new RuntimeException("Errors while running analysis"); // TODO: add exceptions + } + // return this.exceptions; } private void startThreads(final Iterable<Thread> threads) { @@ -190,6 +194,24 @@ public class Analysis implements UncaughtExceptionHandler { @Override public void uncaughtException(final Thread thread, final Throwable throwable) { + if (!executionInterrupted) { + executionInterrupted = true; + LOGGER.warn("Thread " + thread + " was interrupted. Terminating analysis now."); + for (Stage stage : configuration.getThreadableStageJobs()) { + if (stage.getOwningThread() != thread) { + switch (stage.getTerminationStrategy()) { + case BY_SELF_DECISION: { + stage.terminate(); // onSignal would also work, but this will execute in its own Thread + } + case BY_SIGNAL: { + final TerminatingSignal terminatingSignal = new TerminatingSignal(); + stage.onSignal(terminatingSignal, null); + } + default: + } + } + } + } this.exceptions.add(Pair.of(thread, throwable)); } } diff --git a/src/performancetest/java/teetime/examples/loopStage/FiniteSignalPassingTest.java b/src/performancetest/java/teetime/examples/loopStage/FiniteSignalPassingTest.java index ffcef1df..f1637c8e 100644 --- a/src/performancetest/java/teetime/examples/loopStage/FiniteSignalPassingTest.java +++ b/src/performancetest/java/teetime/examples/loopStage/FiniteSignalPassingTest.java @@ -1,24 +1,25 @@ package teetime.examples.loopStage; -import static org.junit.Assert.assertEquals; - -import java.util.Collection; +import static org.junit.Assert.assertFalse; import org.junit.Test; import teetime.framework.Analysis; -import teetime.util.Pair; public class FiniteSignalPassingTest { @Test(timeout = 5000) // may not run infinitely, so we set an arbitrary timeout that is high enough public void testStartSignalDoesNotEndUpInInfiniteLoop() throws Exception { + boolean exceptionsOccured = false; LoopStageAnalysisConfiguration configuration = new LoopStageAnalysisConfiguration(); Analysis analysis = new Analysis(configuration); analysis.init(); - Collection<Pair<Thread, Throwable>> exceptions = analysis.start(); - - assertEquals(0, exceptions.size()); + try { + analysis.start(); + } catch (RuntimeException e) { + exceptionsOccured = true; + } + assertFalse(exceptionsOccured); } } diff --git a/src/test/java/teetime/framework/ExceptionTestStage.java b/src/test/java/teetime/framework/ExceptionTestStage.java index c6aa4e64..ea37feaa 100644 --- a/src/test/java/teetime/framework/ExceptionTestStage.java +++ b/src/test/java/teetime/framework/ExceptionTestStage.java @@ -11,4 +11,9 @@ public class ExceptionTestStage extends AbstractProducerStage { } loops++; } + + @Override + public TerminationStrategy getTerminationStrategy() { + return TerminationStrategy.BY_SELF_DECISION; + } } diff --git a/src/test/java/teetime/framework/RunnableConsumerStageTest.java b/src/test/java/teetime/framework/RunnableConsumerStageTest.java index 02335317..5e2de121 100644 --- a/src/test/java/teetime/framework/RunnableConsumerStageTest.java +++ b/src/test/java/teetime/framework/RunnableConsumerStageTest.java @@ -3,14 +3,9 @@ package teetime.framework; import static org.junit.Assert.assertEquals; import java.lang.Thread.State; -import java.util.Collection; import org.junit.Test; -import teetime.util.Pair; - -import com.google.common.base.Joiner; - public class RunnableConsumerStageTest { @Test @@ -68,12 +63,7 @@ public class RunnableConsumerStageTest { } private void start(final Analysis analysis) { - Collection<Pair<Thread, Throwable>> exceptions = analysis.start(); - for (Pair<Thread, Throwable> pair : exceptions) { - System.err.println(pair.getSecond()); - System.err.println(Joiner.on("\n").join(pair.getSecond().getStackTrace())); - throw new RuntimeException(pair.getSecond()); - } - assertEquals(0, exceptions.size()); + analysis.start(); + assertEquals(0, 0); } } diff --git a/src/test/java/teetime/stage/MultipleInstanceOfFilterTest.java b/src/test/java/teetime/stage/MultipleInstanceOfFilterTest.java index 4740dea2..d1f7fea4 100644 --- a/src/test/java/teetime/stage/MultipleInstanceOfFilterTest.java +++ b/src/test/java/teetime/stage/MultipleInstanceOfFilterTest.java @@ -1,13 +1,12 @@ package teetime.stage; import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.List; import org.junit.Test; @@ -18,7 +17,6 @@ import teetime.framework.OutputPort; import teetime.framework.pipe.IPipeFactory; import teetime.framework.pipe.PipeFactoryRegistry.PipeOrdering; import teetime.framework.pipe.PipeFactoryRegistry.ThreadCommunication; -import teetime.util.Pair; public class MultipleInstanceOfFilterTest { @@ -51,9 +49,11 @@ public class MultipleInstanceOfFilterTest { final Analysis analysis = new Analysis(new TestConfiguration(initialInput, integerList, floatList)); analysis.init(); - final Collection<Pair<Thread, Throwable>> errors = analysis.start(); - - assertThat(errors, is(empty())); + try { + analysis.start(); + } catch (Exception e) { + assertTrue(false); + } assertThat(integerList, contains(1, 2, 3)); assertThat(floatList, contains(1.5f, 2.5f, 3.5f)); -- GitLab