Home | History | Annotate | Download | only in jsr166
      1 /*
      2  * Written by Doug Lea and Martin Buchholz with assistance from
      3  * members of JCP JSR-166 Expert Group and released to the public
      4  * domain, as explained at
      5  * http://creativecommons.org/publicdomain/zero/1.0/
      6  * Other contributors include Andrew Wright, Jeffrey Hayes,
      7  * Pat Fisher, Mike Judd.
      8  */
      9 
     10 package jsr166;
     11 
     12 import static java.util.concurrent.TimeUnit.MILLISECONDS;
     13 
     14 import java.util.concurrent.CountDownLatch;
     15 import java.util.concurrent.atomic.AtomicBoolean;
     16 import java.util.concurrent.locks.LockSupport;
     17 
     18 import junit.framework.Test;
     19 import junit.framework.TestSuite;
     20 
     21 public class LockSupportTest extends JSR166TestCase {
     22     // android-note: Removed because the CTS runner does a bad job of
     23     // retrying tests that have suite() declarations.
     24     //
     25     // public static void main(String[] args) {
     26     //     main(suite(), args);
     27     // }
     28     // public static Test suite() {
     29     //     return new TestSuite(LockSupportTest.class);
     30     // }
     31 
     32     static {
     33         // Reduce the risk of rare disastrous classloading in first call to
     34         // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
     35         Class<?> ensureLoaded = LockSupport.class;
     36     }
     37 
     38     /**
     39      * Returns the blocker object used by tests in this file.
     40      * Any old object will do; we'll return a convenient one.
     41      */
     42     static Object theBlocker() {
     43         return LockSupportTest.class;
     44     }
     45 
     46     enum ParkMethod {
     47         park() {
     48             void park() {
     49                 LockSupport.park();
     50             }
     51             void park(long millis) {
     52                 throw new UnsupportedOperationException();
     53             }
     54         },
     55         parkUntil() {
     56             void park(long millis) {
     57                 LockSupport.parkUntil(deadline(millis));
     58             }
     59         },
     60         parkNanos() {
     61             void park(long millis) {
     62                 LockSupport.parkNanos(MILLISECONDS.toNanos(millis));
     63             }
     64         },
     65         parkBlocker() {
     66             void park() {
     67                 LockSupport.park(theBlocker());
     68             }
     69             void park(long millis) {
     70                 throw new UnsupportedOperationException();
     71             }
     72         },
     73         parkUntilBlocker() {
     74             void park(long millis) {
     75                 LockSupport.parkUntil(theBlocker(), deadline(millis));
     76             }
     77         },
     78         parkNanosBlocker() {
     79             void park(long millis) {
     80                 LockSupport.parkNanos(theBlocker(),
     81                                       MILLISECONDS.toNanos(millis));
     82             }
     83         };
     84 
     85         void park() { park(2 * LONG_DELAY_MS); }
     86         abstract void park(long millis);
     87 
     88         /** Returns a deadline to use with parkUntil. */
     89         long deadline(long millis) {
     90             // beware of rounding
     91             return System.currentTimeMillis() + millis + 1;
     92         }
     93     }
     94 
     95     /**
     96      * park is released by subsequent unpark
     97      */
     98     public void testParkBeforeUnpark_park() {
     99         testParkBeforeUnpark(ParkMethod.park);
    100     }
    101     public void testParkBeforeUnpark_parkNanos() {
    102         testParkBeforeUnpark(ParkMethod.parkNanos);
    103     }
    104     public void testParkBeforeUnpark_parkUntil() {
    105         testParkBeforeUnpark(ParkMethod.parkUntil);
    106     }
    107     public void testParkBeforeUnpark_parkBlocker() {
    108         testParkBeforeUnpark(ParkMethod.parkBlocker);
    109     }
    110     public void testParkBeforeUnpark_parkNanosBlocker() {
    111         testParkBeforeUnpark(ParkMethod.parkNanosBlocker);
    112     }
    113     public void testParkBeforeUnpark_parkUntilBlocker() {
    114         testParkBeforeUnpark(ParkMethod.parkUntilBlocker);
    115     }
    116     public void testParkBeforeUnpark(final ParkMethod parkMethod) {
    117         final CountDownLatch pleaseUnpark = new CountDownLatch(1);
    118         Thread t = newStartedThread(new CheckedRunnable() {
    119             public void realRun() {
    120                 pleaseUnpark.countDown();
    121                 parkMethod.park();
    122             }});
    123 
    124         await(pleaseUnpark);
    125         LockSupport.unpark(t);
    126         awaitTermination(t);
    127     }
    128 
    129     /**
    130      * park is released by preceding unpark
    131      */
    132     public void testParkAfterUnpark_park() {
    133         testParkAfterUnpark(ParkMethod.park);
    134     }
    135     public void testParkAfterUnpark_parkNanos() {
    136         testParkAfterUnpark(ParkMethod.parkNanos);
    137     }
    138     public void testParkAfterUnpark_parkUntil() {
    139         testParkAfterUnpark(ParkMethod.parkUntil);
    140     }
    141     public void testParkAfterUnpark_parkBlocker() {
    142         testParkAfterUnpark(ParkMethod.parkBlocker);
    143     }
    144     public void testParkAfterUnpark_parkNanosBlocker() {
    145         testParkAfterUnpark(ParkMethod.parkNanosBlocker);
    146     }
    147     public void testParkAfterUnpark_parkUntilBlocker() {
    148         testParkAfterUnpark(ParkMethod.parkUntilBlocker);
    149     }
    150     public void testParkAfterUnpark(final ParkMethod parkMethod) {
    151         final CountDownLatch pleaseUnpark = new CountDownLatch(1);
    152         final AtomicBoolean pleasePark = new AtomicBoolean(false);
    153         Thread t = newStartedThread(new CheckedRunnable() {
    154             public void realRun() {
    155                 pleaseUnpark.countDown();
    156                 while (!pleasePark.get())
    157                     Thread.yield();
    158                 parkMethod.park();
    159             }});
    160 
    161         await(pleaseUnpark);
    162         LockSupport.unpark(t);
    163         pleasePark.set(true);
    164         awaitTermination(t);
    165     }
    166 
    167     /**
    168      * park is released by subsequent interrupt
    169      */
    170     public void testParkBeforeInterrupt_park() {
    171         testParkBeforeInterrupt(ParkMethod.park);
    172     }
    173     public void testParkBeforeInterrupt_parkNanos() {
    174         testParkBeforeInterrupt(ParkMethod.parkNanos);
    175     }
    176     public void testParkBeforeInterrupt_parkUntil() {
    177         testParkBeforeInterrupt(ParkMethod.parkUntil);
    178     }
    179     public void testParkBeforeInterrupt_parkBlocker() {
    180         testParkBeforeInterrupt(ParkMethod.parkBlocker);
    181     }
    182     public void testParkBeforeInterrupt_parkNanosBlocker() {
    183         testParkBeforeInterrupt(ParkMethod.parkNanosBlocker);
    184     }
    185     public void testParkBeforeInterrupt_parkUntilBlocker() {
    186         testParkBeforeInterrupt(ParkMethod.parkUntilBlocker);
    187     }
    188     public void testParkBeforeInterrupt(final ParkMethod parkMethod) {
    189         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
    190         Thread t = newStartedThread(new CheckedRunnable() {
    191             public void realRun() {
    192                 pleaseInterrupt.countDown();
    193                 do {
    194                     parkMethod.park();
    195                     // park may return spuriously
    196                 } while (! Thread.currentThread().isInterrupted());
    197             }});
    198 
    199         await(pleaseInterrupt);
    200         assertThreadStaysAlive(t);
    201         t.interrupt();
    202         awaitTermination(t);
    203     }
    204 
    205     /**
    206      * park is released by preceding interrupt
    207      */
    208     public void testParkAfterInterrupt_park() {
    209         testParkAfterInterrupt(ParkMethod.park);
    210     }
    211     public void testParkAfterInterrupt_parkNanos() {
    212         testParkAfterInterrupt(ParkMethod.parkNanos);
    213     }
    214     public void testParkAfterInterrupt_parkUntil() {
    215         testParkAfterInterrupt(ParkMethod.parkUntil);
    216     }
    217     public void testParkAfterInterrupt_parkBlocker() {
    218         testParkAfterInterrupt(ParkMethod.parkBlocker);
    219     }
    220     public void testParkAfterInterrupt_parkNanosBlocker() {
    221         testParkAfterInterrupt(ParkMethod.parkNanosBlocker);
    222     }
    223     public void testParkAfterInterrupt_parkUntilBlocker() {
    224         testParkAfterInterrupt(ParkMethod.parkUntilBlocker);
    225     }
    226     public void testParkAfterInterrupt(final ParkMethod parkMethod) {
    227         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
    228         final AtomicBoolean pleasePark = new AtomicBoolean(false);
    229         Thread t = newStartedThread(new CheckedRunnable() {
    230             public void realRun() throws Exception {
    231                 pleaseInterrupt.countDown();
    232                 while (!pleasePark.get())
    233                     Thread.yield();
    234                 assertTrue(Thread.currentThread().isInterrupted());
    235                 parkMethod.park();
    236                 assertTrue(Thread.currentThread().isInterrupted());
    237             }});
    238 
    239         await(pleaseInterrupt);
    240         t.interrupt();
    241         pleasePark.set(true);
    242         awaitTermination(t);
    243     }
    244 
    245     /**
    246      * timed park times out if not unparked
    247      */
    248     public void testParkTimesOut_parkNanos() {
    249         testParkTimesOut(ParkMethod.parkNanos);
    250     }
    251     public void testParkTimesOut_parkUntil() {
    252         testParkTimesOut(ParkMethod.parkUntil);
    253     }
    254     public void testParkTimesOut_parkNanosBlocker() {
    255         testParkTimesOut(ParkMethod.parkNanosBlocker);
    256     }
    257     public void testParkTimesOut_parkUntilBlocker() {
    258         testParkTimesOut(ParkMethod.parkUntilBlocker);
    259     }
    260     public void testParkTimesOut(final ParkMethod parkMethod) {
    261         Thread t = newStartedThread(new CheckedRunnable() {
    262             public void realRun() {
    263                 for (;;) {
    264                     long startTime = System.nanoTime();
    265                     parkMethod.park(timeoutMillis());
    266                     // park may return spuriously
    267                     if (millisElapsedSince(startTime) >= timeoutMillis())
    268                         return;
    269                 }
    270             }});
    271 
    272         awaitTermination(t);
    273     }
    274 
    275     /**
    276      * getBlocker(null) throws NullPointerException
    277      */
    278     public void testGetBlockerNull() {
    279         try {
    280             LockSupport.getBlocker(null);
    281             shouldThrow();
    282         } catch (NullPointerException success) {}
    283     }
    284 
    285     /**
    286      * getBlocker returns the blocker object passed to park
    287      */
    288     public void testGetBlocker_parkBlocker() {
    289         testGetBlocker(ParkMethod.parkBlocker);
    290     }
    291     public void testGetBlocker_parkNanosBlocker() {
    292         testGetBlocker(ParkMethod.parkNanosBlocker);
    293     }
    294     public void testGetBlocker_parkUntilBlocker() {
    295         testGetBlocker(ParkMethod.parkUntilBlocker);
    296     }
    297     public void testGetBlocker(final ParkMethod parkMethod) {
    298         final CountDownLatch started = new CountDownLatch(1);
    299         Thread t = newStartedThread(new CheckedRunnable() {
    300             public void realRun() {
    301                 Thread t = Thread.currentThread();
    302                 started.countDown();
    303                 do {
    304                     assertNull(LockSupport.getBlocker(t));
    305                     parkMethod.park();
    306                     assertNull(LockSupport.getBlocker(t));
    307                     // park may return spuriously
    308                 } while (! Thread.currentThread().isInterrupted());
    309             }});
    310 
    311         long startTime = System.nanoTime();
    312         await(started);
    313         for (;;) {
    314             Object x = LockSupport.getBlocker(t);
    315             if (x == theBlocker()) { // success
    316                 t.interrupt();
    317                 awaitTermination(t);
    318                 assertNull(LockSupport.getBlocker(t));
    319                 return;
    320             } else {
    321                 assertNull(x);  // ok
    322                 if (millisElapsedSince(startTime) > LONG_DELAY_MS)
    323                     fail("timed out");
    324                 Thread.yield();
    325             }
    326         }
    327     }
    328 
    329     /**
    330      * timed park(0) returns immediately.
    331      *
    332      * Requires hotspot fix for:
    333      * 6763959 java.util.concurrent.locks.LockSupport.parkUntil(0) blocks forever
    334      * which is in jdk7-b118 and 6u25.
    335      */
    336     public void testPark0_parkNanos() {
    337         testPark0(ParkMethod.parkNanos);
    338     }
    339     public void testPark0_parkUntil() {
    340         testPark0(ParkMethod.parkUntil);
    341     }
    342     public void testPark0_parkNanosBlocker() {
    343         testPark0(ParkMethod.parkNanosBlocker);
    344     }
    345     public void testPark0_parkUntilBlocker() {
    346         testPark0(ParkMethod.parkUntilBlocker);
    347     }
    348     public void testPark0(final ParkMethod parkMethod) {
    349         Thread t = newStartedThread(new CheckedRunnable() {
    350             public void realRun() {
    351                 parkMethod.park(0L);
    352             }});
    353 
    354         awaitTermination(t);
    355     }
    356 
    357     /**
    358      * timed park(Long.MIN_VALUE) returns immediately.
    359      */
    360     public void testParkNeg_parkNanos() {
    361         testParkNeg(ParkMethod.parkNanos);
    362     }
    363     public void testParkNeg_parkUntil() {
    364         testParkNeg(ParkMethod.parkUntil);
    365     }
    366     public void testParkNeg_parkNanosBlocker() {
    367         testParkNeg(ParkMethod.parkNanosBlocker);
    368     }
    369     public void testParkNeg_parkUntilBlocker() {
    370         testParkNeg(ParkMethod.parkUntilBlocker);
    371     }
    372     public void testParkNeg(final ParkMethod parkMethod) {
    373         Thread t = newStartedThread(new CheckedRunnable() {
    374             public void realRun() {
    375                 parkMethod.park(Long.MIN_VALUE);
    376             }});
    377 
    378         awaitTermination(t);
    379     }
    380 }
    381