--- jsr166/src/test/tck/RecursiveActionTest.java 2010/11/22 20:19:47 1.24 +++ jsr166/src/test/tck/RecursiveActionTest.java 2011/02/22 01:18:59 1.29 @@ -6,8 +6,10 @@ import junit.framework.*; import java.util.concurrent.CancellationException; +import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ExecutionException; import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; import java.util.concurrent.ForkJoinWorkerThread; import java.util.concurrent.RecursiveAction; import java.util.concurrent.TimeUnit; @@ -59,7 +61,7 @@ public class RecursiveActionTest extends assertNull(a.getException()); assertNull(a.getRawResult()); - if (! (Thread.currentThread() instanceof ForkJoinWorkerThread)) { + if (! ForkJoinTask.inForkJoinPool()) { Thread.currentThread().interrupt(); try { a.get(); @@ -132,7 +134,7 @@ public class RecursiveActionTest extends assertFalse(a.isCancelled()); assertFalse(a.isCompletedNormally()); assertTrue(a.isCompletedAbnormally()); - assertSame(t, a.getException()); + assertSame(t.getClass(), a.getException().getClass()); assertNull(a.getRawResult()); assertFalse(a.cancel(false)); assertFalse(a.cancel(true)); @@ -141,26 +143,27 @@ public class RecursiveActionTest extends a.join(); shouldThrow(); } catch (Throwable expected) { - assertSame(t, expected); + assertSame(expected.getClass(), t.getClass()); } try { a.get(); shouldThrow(); } catch (ExecutionException success) { - assertSame(t, success.getCause()); + assertSame(t.getClass(), success.getCause().getClass()); } catch (Throwable fail) { threadUnexpectedException(fail); } try { a.get(5L, SECONDS); shouldThrow(); } catch (ExecutionException success) { - assertSame(t, success.getCause()); + assertSame(t.getClass(), success.getCause().getClass()); } catch (Throwable fail) { threadUnexpectedException(fail); } } - static final class FJException extends RuntimeException { - FJException() { super(); } + public static final class FJException extends RuntimeException { + public FJException() { super(); } + public FJException(Throwable cause) { super(cause); } } // A simple recursive action for testing @@ -247,73 +250,183 @@ public class RecursiveActionTest extends } /** - * join/quietlyJoin of a forked task ignores interrupts + * join/quietlyJoin of a forked task succeeds in the presence of interrupts */ public void testJoinIgnoresInterrupts() { RecursiveAction a = new CheckedRecursiveAction() { public void realCompute() { FibAction f = new FibAction(8); + final Thread myself = Thread.currentThread(); // test join() assertSame(f, f.fork()); - Thread.currentThread().interrupt(); + myself.interrupt(); + assertTrue(myself.isInterrupted()); assertNull(f.join()); - assertTrue(Thread.interrupted()); + Thread.interrupted(); assertEquals(21, f.result); checkCompletedNormally(f); f.reinitialize(); f.cancel(true); assertSame(f, f.fork()); - Thread.currentThread().interrupt(); + myself.interrupt(); + assertTrue(myself.isInterrupted()); try { f.join(); shouldThrow(); } catch (CancellationException success) { - assertTrue(Thread.interrupted()); + Thread.interrupted(); checkCancelled(f); } f.reinitialize(); f.completeExceptionally(new FJException()); assertSame(f, f.fork()); - Thread.currentThread().interrupt(); + myself.interrupt(); + assertTrue(myself.isInterrupted()); try { f.join(); shouldThrow(); } catch (FJException success) { - assertTrue(Thread.interrupted()); + Thread.interrupted(); checkCompletedAbnormally(f, success); } // test quietlyJoin() f.reinitialize(); assertSame(f, f.fork()); - Thread.currentThread().interrupt(); + myself.interrupt(); + assertTrue(myself.isInterrupted()); f.quietlyJoin(); - assertTrue(Thread.interrupted()); + Thread.interrupted(); assertEquals(21, f.result); checkCompletedNormally(f); f.reinitialize(); f.cancel(true); assertSame(f, f.fork()); - Thread.currentThread().interrupt(); + myself.interrupt(); + assertTrue(myself.isInterrupted()); f.quietlyJoin(); - assertTrue(Thread.interrupted()); + Thread.interrupted(); checkCancelled(f); f.reinitialize(); f.completeExceptionally(new FJException()); assertSame(f, f.fork()); - Thread.currentThread().interrupt(); + myself.interrupt(); + assertTrue(myself.isInterrupted()); + f.quietlyJoin(); + Thread.interrupted(); + checkCompletedAbnormally(f, f.getException()); + }}; + testInvokeOnPool(mainPool(), a); + a.reinitialize(); + testInvokeOnPool(singletonPool(), a); + } + + /** + * join/quietlyJoin of a forked task when not in ForkJoinPool + * succeeds in the presence of interrupts + */ + public void testJoinIgnoresInterruptsOutsideForkJoinPool() { + final SynchronousQueue sq = + new SynchronousQueue(); + RecursiveAction a = new CheckedRecursiveAction() { + public void realCompute() throws InterruptedException { + FibAction[] fibActions = new FibAction[6]; + for (int i = 0; i < fibActions.length; i++) + fibActions[i] = new FibAction(8); + + fibActions[1].cancel(false); + fibActions[2].completeExceptionally(new FJException()); + fibActions[4].cancel(true); + fibActions[5].completeExceptionally(new FJException()); + + for (int i = 0; i < fibActions.length; i++) + fibActions[i].fork(); + + sq.put(fibActions); + + helpQuiesce(); + }}; + + Runnable r = new CheckedRunnable() { + public void realRun() throws InterruptedException { + FibAction[] fibActions = sq.take(); + FibAction f; + final Thread myself = Thread.currentThread(); + + // test join() ------------ + + f = fibActions[0]; + assertFalse(ForkJoinTask.inForkJoinPool()); + myself.interrupt(); + assertTrue(myself.isInterrupted()); + assertNull(f.join()); + assertTrue(Thread.interrupted()); + assertEquals(21, f.result); + checkCompletedNormally(f); + + f = fibActions[1]; + myself.interrupt(); + assertTrue(myself.isInterrupted()); + try { + f.join(); + shouldThrow(); + } catch (CancellationException success) { + assertTrue(Thread.interrupted()); + checkCancelled(f); + } + + f = fibActions[2]; + myself.interrupt(); + assertTrue(myself.isInterrupted()); + try { + f.join(); + shouldThrow(); + } catch (FJException success) { + assertTrue(Thread.interrupted()); + checkCompletedAbnormally(f, success); + } + + // test quietlyJoin() --------- + + f = fibActions[3]; + myself.interrupt(); + assertTrue(myself.isInterrupted()); + f.quietlyJoin(); + assertTrue(Thread.interrupted()); + assertEquals(21, f.result); + checkCompletedNormally(f); + + f = fibActions[4]; + myself.interrupt(); + assertTrue(myself.isInterrupted()); f.quietlyJoin(); assertTrue(Thread.interrupted()); + checkCancelled(f); + + f = fibActions[5]; + myself.interrupt(); + assertTrue(myself.isInterrupted()); + f.quietlyJoin(); + assertTrue(Thread.interrupted()); + assertTrue(f.getException() instanceof FJException); checkCompletedAbnormally(f, f.getException()); }}; + + Thread t; + + t = newStartedThread(r); testInvokeOnPool(mainPool(), a); + awaitTermination(t, LONG_DELAY_MS); + a.reinitialize(); + t = newStartedThread(r); testInvokeOnPool(singletonPool(), a); + awaitTermination(t, LONG_DELAY_MS); } /** @@ -657,9 +770,10 @@ public class RecursiveActionTest extends RecursiveAction a = new CheckedRecursiveAction() { public void realCompute() { ForkJoinWorkerThread w = - (ForkJoinWorkerThread)(Thread.currentThread()); + (ForkJoinWorkerThread) Thread.currentThread(); assertTrue(w.getPoolIndex() >= 0); - assertTrue(w.getPoolIndex() < mainPool.getPoolSize()); + // pool size can shrink after assigning index, so cannot check + // assertTrue(w.getPoolIndex() < mainPool.getPoolSize()); }}; testInvokeOnPool(mainPool, a); }