--- jsr166/src/test/tck/SubmissionPublisherTest.java 2016/12/11 22:11:45 1.16 +++ jsr166/src/test/tck/SubmissionPublisherTest.java 2018/10/24 21:15:49 1.29 @@ -6,6 +6,7 @@ */ import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.Flow; @@ -146,7 +147,7 @@ public class SubmissionPublisherTest ext * defaultExecutor */ public void testConstructor1() { - SubmissionPublisher p = new SubmissionPublisher(); + SubmissionPublisher p = new SubmissionPublisher<>(); checkInitialState(p); assertEquals(p.getMaxBufferCapacity(), Flow.defaultBufferSize()); Executor e = p.getExecutor(), c = ForkJoinPool.commonPool(); @@ -162,14 +163,15 @@ public class SubmissionPublisherTest ext */ public void testConstructor2() { Executor e = Executors.newFixedThreadPool(1); - SubmissionPublisher p = new SubmissionPublisher(e, 8); + SubmissionPublisher p = new SubmissionPublisher<>(e, 8); checkInitialState(p); assertSame(p.getExecutor(), e); assertEquals(8, p.getMaxBufferCapacity()); } /** - * A null Executor argument to SubmissionPublisher constructor throws NPE + * A null Executor argument to SubmissionPublisher constructor + * throws NullPointerException */ public void testConstructor3() { try { @@ -180,7 +182,7 @@ public class SubmissionPublisherTest ext /** * A negative capacity argument to SubmissionPublisher constructor - * throws IAE + * throws IllegalArgumentException */ public void testConstructor4() { Executor e = Executors.newFixedThreadPool(1); @@ -192,8 +194,9 @@ public class SubmissionPublisherTest ext /** * A closed publisher reports isClosed with no closedException and - * throws ISE upon attempted submission; a subsequent close or - * closeExceptionally has no additional effect. + * throws IllegalStateException upon attempted submission; a + * subsequent close or closeExceptionally has no additional + * effect. */ public void testClose() { SubmissionPublisher p = basicPublisher(); @@ -213,9 +216,9 @@ public class SubmissionPublisherTest ext /** * A publisher closedExceptionally reports isClosed with the - * closedException and throws ISE upon attempted submission; a - * subsequent close or closeExceptionally has no additional - * effect. + * closedException and throws IllegalStateException upon attempted + * submission; a subsequent close or closeExceptionally has no + * additional effect. */ public void testCloseExceptionally() { SubmissionPublisher p = basicPublisher(); @@ -331,9 +334,7 @@ public class SubmissionPublisherTest ext TestSubscriber s = new TestSubscriber(); SubmissionPublisher p = basicPublisher(); s.throwOnCall = true; - try { - p.subscribe(s); - } catch (Exception ok) {} + p.subscribe(s); s.awaitError(); assertEquals(0, s.nexts); assertEquals(1, s.errors); @@ -390,7 +391,7 @@ public class SubmissionPublisherTest ext s1.awaitError(); assertTrue(s1.nexts <= 1); assertEquals(1, s1.errors); - s1.awaitSubscribe(); + s2.awaitSubscribe(); s2.awaitError(); assertTrue(s2.nexts <= 1); assertEquals(1, s2.errors); @@ -400,7 +401,8 @@ public class SubmissionPublisherTest ext * Cancelling a subscription eventually causes no more onNexts to be issued */ public void testCancel() { - SubmissionPublisher p = basicPublisher(); + SubmissionPublisher p = + new SubmissionPublisher<>(basicExecutor, 4); // must be < 20 TestSubscriber s1 = new TestSubscriber(); TestSubscriber s2 = new TestSubscriber(); p.subscribe(s1); @@ -444,9 +446,8 @@ public class SubmissionPublisherTest ext */ public void testThrowOnNextHandler() { AtomicInteger calls = new AtomicInteger(); - SubmissionPublisher p = new SubmissionPublisher - (basicExecutor, 8, - (s, e) -> calls.getAndIncrement()); + SubmissionPublisher p = new SubmissionPublisher<>( + basicExecutor, 8, (s, e) -> calls.getAndIncrement()); TestSubscriber s1 = new TestSubscriber(); TestSubscriber s2 = new TestSubscriber(); p.subscribe(s1); @@ -493,7 +494,7 @@ public class SubmissionPublisherTest ext s1.request = false; p.subscribe(s1); s1.awaitSubscribe(); - assertTrue(p.estimateMinimumDemand() == 0); + assertEquals(0, p.estimateMinimumDemand()); TestSubscriber s2 = new TestSubscriber(); p.subscribe(s2); p.submit(1); @@ -534,17 +535,21 @@ public class SubmissionPublisherTest ext } /** - * Negative request causes error + * Non-positive request causes error */ public void testRequest3() { SubmissionPublisher p = basicPublisher(); TestSubscriber s1 = new TestSubscriber(); TestSubscriber s2 = new TestSubscriber(); + TestSubscriber s3 = new TestSubscriber(); p.subscribe(s1); p.subscribe(s2); + p.subscribe(s3); + s3.awaitSubscribe(); s2.awaitSubscribe(); s1.awaitSubscribe(); s1.sn.request(-1L); + s3.sn.request(0L); p.submit(1); p.submit(2); p.close(); @@ -554,11 +559,14 @@ public class SubmissionPublisherTest ext s1.awaitError(); assertEquals(1, s1.errors); assertTrue(s1.lastError instanceof IllegalArgumentException); + s3.awaitError(); + assertEquals(1, s3.errors); + assertTrue(s3.lastError instanceof IllegalArgumentException); } /** * estimateMinimumDemand reports 0 until request, nonzero after - * request, and zero again after delivery + * request */ public void testEstimateMinimumDemand() { TestSubscriber s = new TestSubscriber(); @@ -569,9 +577,6 @@ public class SubmissionPublisherTest ext assertEquals(0, p.estimateMinimumDemand()); s.sn.request(1); assertEquals(1, p.estimateMinimumDemand()); - p.submit(1); - s.awaitNext(1); - assertEquals(0, p.estimateMinimumDemand()); } /** @@ -627,14 +632,13 @@ public class SubmissionPublisherTest ext * submit eventually issues requested items when buffer capacity is 1 */ public void testCap1Submit() { - SubmissionPublisher p = new SubmissionPublisher( - basicExecutor, 1); + SubmissionPublisher p + = new SubmissionPublisher<>(basicExecutor, 1); TestSubscriber s1 = new TestSubscriber(); TestSubscriber s2 = new TestSubscriber(); p.subscribe(s1); p.subscribe(s2); for (int i = 1; i <= 20; ++i) { - assertTrue(p.estimateMinimumDemand() <= 1); assertTrue(p.submit(i) >= 0); } p.close(); @@ -706,8 +710,8 @@ public class SubmissionPublisherTest ext * offer reports drops if saturated */ public void testDroppedOffer() { - SubmissionPublisher p = new SubmissionPublisher( - basicExecutor, 4); + SubmissionPublisher p + = new SubmissionPublisher<>(basicExecutor, 4); TestSubscriber s1 = new TestSubscriber(); s1.request = false; TestSubscriber s2 = new TestSubscriber(); @@ -735,8 +739,8 @@ public class SubmissionPublisherTest ext */ public void testHandledDroppedOffer() { AtomicInteger calls = new AtomicInteger(); - SubmissionPublisher p = new SubmissionPublisher( - basicExecutor, 4); + SubmissionPublisher p + = new SubmissionPublisher<>(basicExecutor, 4); TestSubscriber s1 = new TestSubscriber(); s1.request = false; TestSubscriber s2 = new TestSubscriber(); @@ -763,8 +767,8 @@ public class SubmissionPublisherTest ext */ public void testRecoveredHandledDroppedOffer() { AtomicInteger calls = new AtomicInteger(); - SubmissionPublisher p = new SubmissionPublisher( - basicExecutor, 4); + SubmissionPublisher p + = new SubmissionPublisher<>(basicExecutor, 4); TestSubscriber s1 = new TestSubscriber(); s1.request = false; TestSubscriber s2 = new TestSubscriber(); @@ -844,8 +848,8 @@ public class SubmissionPublisherTest ext * Timed offer reports drops if saturated */ public void testDroppedTimedOffer() { - SubmissionPublisher p = new SubmissionPublisher( - basicExecutor, 4); + SubmissionPublisher p + = new SubmissionPublisher<>(basicExecutor, 4); TestSubscriber s1 = new TestSubscriber(); s1.request = false; TestSubscriber s2 = new TestSubscriber(); @@ -876,8 +880,8 @@ public class SubmissionPublisherTest ext */ public void testHandledDroppedTimedOffer() { AtomicInteger calls = new AtomicInteger(); - SubmissionPublisher p = new SubmissionPublisher( - basicExecutor, 4); + SubmissionPublisher p + = new SubmissionPublisher<>(basicExecutor, 4); TestSubscriber s1 = new TestSubscriber(); s1.request = false; TestSubscriber s2 = new TestSubscriber(); @@ -906,8 +910,8 @@ public class SubmissionPublisherTest ext */ public void testRecoveredHandledDroppedTimedOffer() { AtomicInteger calls = new AtomicInteger(); - SubmissionPublisher p = new SubmissionPublisher( - basicExecutor, 4); + SubmissionPublisher p + = new SubmissionPublisher<>(basicExecutor, 4); TestSubscriber s1 = new TestSubscriber(); s1.request = false; TestSubscriber s2 = new TestSubscriber(); @@ -973,4 +977,38 @@ public class SubmissionPublisherTest ext assertTrue(count.get() < n); } + /** + * Tests scenario for + * JDK-8187947: A race condition in SubmissionPublisher + * cvs update -D '2017-11-25' src/main/java/util/concurrent/SubmissionPublisher.java && ant -Djsr166.expensiveTests=true -Djsr166.tckTestClass=SubmissionPublisherTest -Djsr166.methodFilter=testMissedSignal tck; cvs update -A src/main/java/util/concurrent/SubmissionPublisher.java + */ + public void testMissedSignal_8187947() throws Exception { + if (!atLeastJava9()) return; // backport to jdk8 too hard + final int N = + ((ForkJoinPool.getCommonPoolParallelism() < 2) // JDK-8212899 + ? (1 << 5) + : (1 << 10)) + * (expensiveTests ? (1 << 10) : 1); + final CountDownLatch finished = new CountDownLatch(1); + final SubmissionPublisher pub = new SubmissionPublisher<>(); + class Sub implements Subscriber { + int received; + public void onSubscribe(Subscription s) { + s.request(N); + } + public void onNext(Boolean item) { + if (++received == N) + finished.countDown(); + else + CompletableFuture.runAsync(() -> pub.submit(Boolean.TRUE)); + } + public void onError(Throwable t) { throw new AssertionError(t); } + public void onComplete() {} + } + pub.subscribe(new Sub()); + checkTimedGet( + CompletableFuture.runAsync(() -> pub.submit(Boolean.TRUE)), + null); + await(finished); + } }