38 |
38 |
39 import java.util.ArrayList; |
39 import java.util.ArrayList; |
40 import java.util.Arrays; |
40 import java.util.Arrays; |
41 import java.util.Collection; |
41 import java.util.Collection; |
42 import java.util.HashSet; |
42 import java.util.HashSet; |
43 import java.util.concurrent.ThreadLocalRandom; |
43 import java.util.concurrent.atomic.AtomicBoolean; |
44 import java.util.concurrent.locks.AbstractQueuedSynchronizer; |
44 import java.util.concurrent.locks.AbstractQueuedSynchronizer; |
45 import java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject; |
45 import java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject; |
46 |
46 |
47 import junit.framework.Test; |
47 import junit.framework.Test; |
48 import junit.framework.TestSuite; |
48 import junit.framework.TestSuite; |
1335 } |
1335 } |
1336 |
1336 |
1337 /** |
1337 /** |
1338 * Tests scenario for |
1338 * Tests scenario for |
1339 * JDK-8191937: Lost interrupt in AbstractQueuedSynchronizer when tryAcquire methods throw |
1339 * JDK-8191937: Lost interrupt in AbstractQueuedSynchronizer when tryAcquire methods throw |
1340 */ |
1340 * ant -Djsr166.tckTestClass=AbstractQueuedSynchronizerTest -Djsr166.methodFilter=testInterruptedFailingAcquire -Djsr166.runsPerTest=10000 tck |
1341 public void testInterruptedFailingAcquire() throws InterruptedException { |
1341 */ |
1342 final RuntimeException ex = new RuntimeException(); |
1342 public void testInterruptedFailingAcquire() throws Throwable { |
|
1343 class PleaseThrow extends RuntimeException {} |
|
1344 final PleaseThrow ex = new PleaseThrow(); |
|
1345 final AtomicBoolean thrown = new AtomicBoolean(); |
1343 |
1346 |
1344 // A synchronizer only offering a choice of failure modes |
1347 // A synchronizer only offering a choice of failure modes |
1345 class Sync extends AbstractQueuedSynchronizer { |
1348 class Sync extends AbstractQueuedSynchronizer { |
1346 boolean pleaseThrow; |
1349 volatile boolean pleaseThrow; |
|
1350 void maybeThrow() { |
|
1351 if (pleaseThrow) { |
|
1352 // assert: tryAcquire methods can throw at most once |
|
1353 if (! thrown.compareAndSet(false, true)) |
|
1354 throw new AssertionError(); |
|
1355 throw ex; |
|
1356 } |
|
1357 } |
|
1358 |
1347 @Override protected boolean tryAcquire(int ignored) { |
1359 @Override protected boolean tryAcquire(int ignored) { |
1348 if (pleaseThrow) throw ex; |
1360 maybeThrow(); |
1349 return false; |
1361 return false; |
1350 } |
1362 } |
1351 @Override protected int tryAcquireShared(int ignored) { |
1363 @Override protected int tryAcquireShared(int ignored) { |
1352 if (pleaseThrow) throw ex; |
1364 maybeThrow(); |
1353 return -1; |
1365 return -1; |
1354 } |
1366 } |
1355 @Override protected boolean tryRelease(int ignored) { |
1367 @Override protected boolean tryRelease(int ignored) { |
1356 return true; |
1368 return true; |
1357 } |
1369 } |
1359 return true; |
1371 return true; |
1360 } |
1372 } |
1361 } |
1373 } |
1362 |
1374 |
1363 final Sync s = new Sync(); |
1375 final Sync s = new Sync(); |
1364 |
1376 final boolean acquireInterruptibly = randomBoolean(); |
|
1377 final Action[] uninterruptibleAcquireActions = { |
|
1378 () -> s.acquire(1), |
|
1379 () -> s.acquireShared(1), |
|
1380 }; |
|
1381 final long nanosTimeout = MILLISECONDS.toNanos(2 * LONG_DELAY_MS); |
|
1382 final Action[] interruptibleAcquireActions = { |
|
1383 () -> s.acquireInterruptibly(1), |
|
1384 () -> s.acquireSharedInterruptibly(1), |
|
1385 () -> s.tryAcquireNanos(1, nanosTimeout), |
|
1386 () -> s.tryAcquireSharedNanos(1, nanosTimeout), |
|
1387 }; |
|
1388 final Action[] releaseActions = { |
|
1389 () -> s.release(1), |
|
1390 () -> s.releaseShared(1), |
|
1391 }; |
|
1392 final Action acquireAction = acquireInterruptibly |
|
1393 ? chooseRandomly(interruptibleAcquireActions) |
|
1394 : chooseRandomly(uninterruptibleAcquireActions); |
|
1395 final Action releaseAction |
|
1396 = chooseRandomly(releaseActions); |
|
1397 |
|
1398 // From os_posix.cpp: |
|
1399 // |
|
1400 // NOTE that since there is no "lock" around the interrupt and |
|
1401 // is_interrupted operations, there is the possibility that the |
|
1402 // interrupted flag (in osThread) will be "false" but that the |
|
1403 // low-level events will be in the signaled state. This is |
|
1404 // intentional. The effect of this is that Object.wait() and |
|
1405 // LockSupport.park() will appear to have a spurious wakeup, which |
|
1406 // is allowed and not harmful, and the possibility is so rare that |
|
1407 // it is not worth the added complexity to add yet another lock. |
1365 final Thread thread = newStartedThread(new CheckedRunnable() { |
1408 final Thread thread = newStartedThread(new CheckedRunnable() { |
1366 public void realRun() { |
1409 public void realRun() throws Throwable { |
1367 try { |
1410 try { |
1368 if (ThreadLocalRandom.current().nextBoolean()) |
1411 acquireAction.run(); |
1369 s.acquire(1); |
|
1370 else |
|
1371 s.acquireShared(1); |
|
1372 shouldThrow(); |
1412 shouldThrow(); |
1373 } catch (Throwable t) { |
1413 } catch (InterruptedException possible) { |
1374 assertSame(ex, t); |
1414 assertTrue(acquireInterruptibly); |
1375 assertTrue(Thread.interrupted()); |
1415 assertFalse(Thread.interrupted()); |
|
1416 } catch (PleaseThrow possible) { |
|
1417 awaitInterrupted(); |
1376 } |
1418 } |
1377 }}); |
1419 }}); |
1378 waitForThreadToEnterWaitState(thread); |
1420 for (long startTime = 0L;; ) { |
1379 assertSame(thread, s.getFirstQueuedThread()); |
1421 waitForThreadToEnterWaitState(thread); |
1380 assertTrue(s.hasQueuedPredecessors()); |
1422 if (s.getFirstQueuedThread() == thread |
1381 assertTrue(s.hasQueuedThreads()); |
1423 && s.hasQueuedPredecessors() |
1382 assertEquals(1, s.getQueueLength()); |
1424 && s.hasQueuedThreads() |
|
1425 && s.getQueueLength() == 1 |
|
1426 && s.hasContended()) |
|
1427 break; |
|
1428 if (startTime == 0L) |
|
1429 startTime = System.nanoTime(); |
|
1430 else if (millisElapsedSince(startTime) > LONG_DELAY_MS) |
|
1431 fail("timed out waiting for AQS state: " |
|
1432 + "thread state=" + thread.getState() |
|
1433 + ", queued threads=" + s.getQueuedThreads()); |
|
1434 Thread.yield(); |
|
1435 } |
1383 |
1436 |
1384 s.pleaseThrow = true; |
1437 s.pleaseThrow = true; |
1385 thread.interrupt(); |
1438 // release and interrupt, in random order |
1386 s.release(1); |
1439 if (randomBoolean()) { |
|
1440 thread.interrupt(); |
|
1441 releaseAction.run(); |
|
1442 } else { |
|
1443 releaseAction.run(); |
|
1444 thread.interrupt(); |
|
1445 } |
1387 awaitTermination(thread); |
1446 awaitTermination(thread); |
|
1447 |
|
1448 if (! acquireInterruptibly) |
|
1449 assertTrue(thrown.get()); |
|
1450 |
|
1451 assertNull(s.getFirstQueuedThread()); |
|
1452 assertFalse(s.hasQueuedPredecessors()); |
|
1453 assertFalse(s.hasQueuedThreads()); |
|
1454 assertEquals(0, s.getQueueLength()); |
|
1455 assertTrue(s.getQueuedThreads().isEmpty()); |
|
1456 assertTrue(s.hasContended()); |
1388 } |
1457 } |
1389 |
1458 |
1390 } |
1459 } |