37 import static java.util.concurrent.TimeUnit.NANOSECONDS; |
37 import static java.util.concurrent.TimeUnit.NANOSECONDS; |
38 |
38 |
39 import java.util.Arrays; |
39 import java.util.Arrays; |
40 import java.util.Collection; |
40 import java.util.Collection; |
41 import java.util.HashSet; |
41 import java.util.HashSet; |
42 import java.util.concurrent.ThreadLocalRandom; |
42 import java.util.concurrent.atomic.AtomicBoolean; |
43 import java.util.concurrent.locks.AbstractQueuedLongSynchronizer; |
43 import java.util.concurrent.locks.AbstractQueuedLongSynchronizer; |
44 import java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject; |
44 import java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject; |
45 |
45 |
46 import junit.framework.Test; |
46 import junit.framework.Test; |
47 import junit.framework.TestSuite; |
47 import junit.framework.TestSuite; |
1284 } |
1284 } |
1285 |
1285 |
1286 /** |
1286 /** |
1287 * Tests scenario for |
1287 * Tests scenario for |
1288 * JDK-8191937: Lost interrupt in AbstractQueuedSynchronizer when tryAcquire methods throw |
1288 * JDK-8191937: Lost interrupt in AbstractQueuedSynchronizer when tryAcquire methods throw |
1289 */ |
1289 * ant -Djsr166.tckTestClass=AbstractQueuedLongSynchronizerTest -Djsr166.methodFilter=testInterruptedFailingAcquire -Djsr166.runsPerTest=10000 tck |
1290 public void testInterruptedFailingAcquire() throws InterruptedException { |
1290 */ |
1291 final RuntimeException ex = new RuntimeException(); |
1291 public void testInterruptedFailingAcquire() throws Throwable { |
|
1292 class PleaseThrow extends RuntimeException {} |
|
1293 final PleaseThrow ex = new PleaseThrow(); |
|
1294 final AtomicBoolean thrown = new AtomicBoolean(); |
1292 |
1295 |
1293 // A synchronizer only offering a choice of failure modes |
1296 // A synchronizer only offering a choice of failure modes |
1294 class Sync extends AbstractQueuedLongSynchronizer { |
1297 class Sync extends AbstractQueuedLongSynchronizer { |
1295 boolean pleaseThrow; |
1298 volatile boolean pleaseThrow; |
|
1299 void maybeThrow() { |
|
1300 if (pleaseThrow) { |
|
1301 // assert: tryAcquire methods can throw at most once |
|
1302 if (! thrown.compareAndSet(false, true)) |
|
1303 throw new AssertionError(); |
|
1304 throw ex; |
|
1305 } |
|
1306 } |
|
1307 |
1296 @Override protected boolean tryAcquire(long ignored) { |
1308 @Override protected boolean tryAcquire(long ignored) { |
1297 if (pleaseThrow) throw ex; |
1309 maybeThrow(); |
1298 return false; |
1310 return false; |
1299 } |
1311 } |
1300 @Override protected long tryAcquireShared(long ignored) { |
1312 @Override protected long tryAcquireShared(long ignored) { |
1301 if (pleaseThrow) throw ex; |
1313 maybeThrow(); |
1302 return -1; |
1314 return -1; |
1303 } |
1315 } |
1304 @Override protected boolean tryRelease(long ignored) { |
1316 @Override protected boolean tryRelease(long ignored) { |
1305 return true; |
1317 return true; |
1306 } |
1318 } |
1308 return true; |
1320 return true; |
1309 } |
1321 } |
1310 } |
1322 } |
1311 |
1323 |
1312 final Sync s = new Sync(); |
1324 final Sync s = new Sync(); |
1313 |
1325 final boolean acquireInterruptibly = randomBoolean(); |
|
1326 final Action[] uninterruptibleAcquireActions = { |
|
1327 () -> s.acquire(1), |
|
1328 () -> s.acquireShared(1), |
|
1329 }; |
|
1330 final long nanosTimeout = MILLISECONDS.toNanos(2 * LONG_DELAY_MS); |
|
1331 final Action[] interruptibleAcquireActions = { |
|
1332 () -> s.acquireInterruptibly(1), |
|
1333 () -> s.acquireSharedInterruptibly(1), |
|
1334 () -> s.tryAcquireNanos(1, nanosTimeout), |
|
1335 () -> s.tryAcquireSharedNanos(1, nanosTimeout), |
|
1336 }; |
|
1337 final Action[] releaseActions = { |
|
1338 () -> s.release(1), |
|
1339 () -> s.releaseShared(1), |
|
1340 }; |
|
1341 final Action acquireAction = acquireInterruptibly |
|
1342 ? chooseRandomly(interruptibleAcquireActions) |
|
1343 : chooseRandomly(uninterruptibleAcquireActions); |
|
1344 final Action releaseAction |
|
1345 = chooseRandomly(releaseActions); |
|
1346 |
|
1347 // From os_posix.cpp: |
|
1348 // |
|
1349 // NOTE that since there is no "lock" around the interrupt and |
|
1350 // is_interrupted operations, there is the possibility that the |
|
1351 // interrupted flag (in osThread) will be "false" but that the |
|
1352 // low-level events will be in the signaled state. This is |
|
1353 // intentional. The effect of this is that Object.wait() and |
|
1354 // LockSupport.park() will appear to have a spurious wakeup, which |
|
1355 // is allowed and not harmful, and the possibility is so rare that |
|
1356 // it is not worth the added complexity to add yet another lock. |
1314 final Thread thread = newStartedThread(new CheckedRunnable() { |
1357 final Thread thread = newStartedThread(new CheckedRunnable() { |
1315 public void realRun() { |
1358 public void realRun() throws Throwable { |
1316 try { |
1359 try { |
1317 if (ThreadLocalRandom.current().nextBoolean()) |
1360 acquireAction.run(); |
1318 s.acquire(1); |
|
1319 else |
|
1320 s.acquireShared(1); |
|
1321 shouldThrow(); |
1361 shouldThrow(); |
1322 } catch (Throwable t) { |
1362 } catch (InterruptedException possible) { |
1323 assertSame(ex, t); |
1363 assertTrue(acquireInterruptibly); |
1324 assertTrue(Thread.interrupted()); |
1364 assertFalse(Thread.interrupted()); |
|
1365 } catch (PleaseThrow possible) { |
|
1366 awaitInterrupted(); |
1325 } |
1367 } |
1326 }}); |
1368 }}); |
1327 waitForThreadToEnterWaitState(thread); |
1369 for (long startTime = 0L;; ) { |
1328 assertSame(thread, s.getFirstQueuedThread()); |
1370 waitForThreadToEnterWaitState(thread); |
1329 assertTrue(s.hasQueuedPredecessors()); |
1371 if (s.getFirstQueuedThread() == thread |
1330 assertTrue(s.hasQueuedThreads()); |
1372 && s.hasQueuedPredecessors() |
1331 assertEquals(1, s.getQueueLength()); |
1373 && s.hasQueuedThreads() |
|
1374 && s.getQueueLength() == 1 |
|
1375 && s.hasContended()) |
|
1376 break; |
|
1377 if (startTime == 0L) |
|
1378 startTime = System.nanoTime(); |
|
1379 else if (millisElapsedSince(startTime) > LONG_DELAY_MS) |
|
1380 fail("timed out waiting for AQS state: " |
|
1381 + "thread state=" + thread.getState() |
|
1382 + ", queued threads=" + s.getQueuedThreads()); |
|
1383 Thread.yield(); |
|
1384 } |
1332 |
1385 |
1333 s.pleaseThrow = true; |
1386 s.pleaseThrow = true; |
1334 thread.interrupt(); |
1387 // release and interrupt, in random order |
1335 s.release(1); |
1388 if (randomBoolean()) { |
|
1389 thread.interrupt(); |
|
1390 releaseAction.run(); |
|
1391 } else { |
|
1392 releaseAction.run(); |
|
1393 thread.interrupt(); |
|
1394 } |
1336 awaitTermination(thread); |
1395 awaitTermination(thread); |
|
1396 |
|
1397 if (! acquireInterruptibly) |
|
1398 assertTrue(thrown.get()); |
|
1399 |
|
1400 assertNull(s.getFirstQueuedThread()); |
|
1401 assertFalse(s.hasQueuedPredecessors()); |
|
1402 assertFalse(s.hasQueuedThreads()); |
|
1403 assertEquals(0, s.getQueueLength()); |
|
1404 assertTrue(s.getQueuedThreads().isEmpty()); |
|
1405 assertTrue(s.hasContended()); |
1337 } |
1406 } |
1338 |
1407 |
1339 } |
1408 } |