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      */
theBlocker()42     static Object theBlocker() {
43         return LockSupportTest.class;
44     }
45 
46     enum ParkMethod {
park()47         park() {
48             void park() {
49                 LockSupport.park();
50             }
51             void park(long millis) {
52                 throw new UnsupportedOperationException();
53             }
54         },
parkUntil()55         parkUntil() {
56             void park(long millis) {
57                 LockSupport.parkUntil(deadline(millis));
58             }
59         },
parkNanos()60         parkNanos() {
61             void park(long millis) {
62                 LockSupport.parkNanos(MILLISECONDS.toNanos(millis));
63             }
64         },
parkBlocker()65         parkBlocker() {
66             void park() {
67                 LockSupport.park(theBlocker());
68             }
69             void park(long millis) {
70                 throw new UnsupportedOperationException();
71             }
72         },
parkUntilBlocker()73         parkUntilBlocker() {
74             void park(long millis) {
75                 LockSupport.parkUntil(theBlocker(), deadline(millis));
76             }
77         },
parkNanosBlocker()78         parkNanosBlocker() {
79             void park(long millis) {
80                 LockSupport.parkNanos(theBlocker(),
81                                       MILLISECONDS.toNanos(millis));
82             }
83         };
84 
park()85         void park() { park(2 * LONG_DELAY_MS); }
park(long millis)86         abstract void park(long millis);
87 
88         /** Returns a deadline to use with parkUntil. */
deadline(long millis)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      */
testParkBeforeUnpark_park()98     public void testParkBeforeUnpark_park() {
99         testParkBeforeUnpark(ParkMethod.park);
100     }
testParkBeforeUnpark_parkNanos()101     public void testParkBeforeUnpark_parkNanos() {
102         testParkBeforeUnpark(ParkMethod.parkNanos);
103     }
testParkBeforeUnpark_parkUntil()104     public void testParkBeforeUnpark_parkUntil() {
105         testParkBeforeUnpark(ParkMethod.parkUntil);
106     }
testParkBeforeUnpark_parkBlocker()107     public void testParkBeforeUnpark_parkBlocker() {
108         testParkBeforeUnpark(ParkMethod.parkBlocker);
109     }
testParkBeforeUnpark_parkNanosBlocker()110     public void testParkBeforeUnpark_parkNanosBlocker() {
111         testParkBeforeUnpark(ParkMethod.parkNanosBlocker);
112     }
testParkBeforeUnpark_parkUntilBlocker()113     public void testParkBeforeUnpark_parkUntilBlocker() {
114         testParkBeforeUnpark(ParkMethod.parkUntilBlocker);
115     }
testParkBeforeUnpark(final ParkMethod parkMethod)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      */
testParkAfterUnpark_park()132     public void testParkAfterUnpark_park() {
133         testParkAfterUnpark(ParkMethod.park);
134     }
testParkAfterUnpark_parkNanos()135     public void testParkAfterUnpark_parkNanos() {
136         testParkAfterUnpark(ParkMethod.parkNanos);
137     }
testParkAfterUnpark_parkUntil()138     public void testParkAfterUnpark_parkUntil() {
139         testParkAfterUnpark(ParkMethod.parkUntil);
140     }
testParkAfterUnpark_parkBlocker()141     public void testParkAfterUnpark_parkBlocker() {
142         testParkAfterUnpark(ParkMethod.parkBlocker);
143     }
testParkAfterUnpark_parkNanosBlocker()144     public void testParkAfterUnpark_parkNanosBlocker() {
145         testParkAfterUnpark(ParkMethod.parkNanosBlocker);
146     }
testParkAfterUnpark_parkUntilBlocker()147     public void testParkAfterUnpark_parkUntilBlocker() {
148         testParkAfterUnpark(ParkMethod.parkUntilBlocker);
149     }
testParkAfterUnpark(final ParkMethod parkMethod)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      */
testParkBeforeInterrupt_park()170     public void testParkBeforeInterrupt_park() {
171         testParkBeforeInterrupt(ParkMethod.park);
172     }
testParkBeforeInterrupt_parkNanos()173     public void testParkBeforeInterrupt_parkNanos() {
174         testParkBeforeInterrupt(ParkMethod.parkNanos);
175     }
testParkBeforeInterrupt_parkUntil()176     public void testParkBeforeInterrupt_parkUntil() {
177         testParkBeforeInterrupt(ParkMethod.parkUntil);
178     }
testParkBeforeInterrupt_parkBlocker()179     public void testParkBeforeInterrupt_parkBlocker() {
180         testParkBeforeInterrupt(ParkMethod.parkBlocker);
181     }
testParkBeforeInterrupt_parkNanosBlocker()182     public void testParkBeforeInterrupt_parkNanosBlocker() {
183         testParkBeforeInterrupt(ParkMethod.parkNanosBlocker);
184     }
testParkBeforeInterrupt_parkUntilBlocker()185     public void testParkBeforeInterrupt_parkUntilBlocker() {
186         testParkBeforeInterrupt(ParkMethod.parkUntilBlocker);
187     }
testParkBeforeInterrupt(final ParkMethod parkMethod)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      */
testParkAfterInterrupt_park()208     public void testParkAfterInterrupt_park() {
209         testParkAfterInterrupt(ParkMethod.park);
210     }
testParkAfterInterrupt_parkNanos()211     public void testParkAfterInterrupt_parkNanos() {
212         testParkAfterInterrupt(ParkMethod.parkNanos);
213     }
testParkAfterInterrupt_parkUntil()214     public void testParkAfterInterrupt_parkUntil() {
215         testParkAfterInterrupt(ParkMethod.parkUntil);
216     }
testParkAfterInterrupt_parkBlocker()217     public void testParkAfterInterrupt_parkBlocker() {
218         testParkAfterInterrupt(ParkMethod.parkBlocker);
219     }
testParkAfterInterrupt_parkNanosBlocker()220     public void testParkAfterInterrupt_parkNanosBlocker() {
221         testParkAfterInterrupt(ParkMethod.parkNanosBlocker);
222     }
testParkAfterInterrupt_parkUntilBlocker()223     public void testParkAfterInterrupt_parkUntilBlocker() {
224         testParkAfterInterrupt(ParkMethod.parkUntilBlocker);
225     }
testParkAfterInterrupt(final ParkMethod parkMethod)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      */
testParkTimesOut_parkNanos()248     public void testParkTimesOut_parkNanos() {
249         testParkTimesOut(ParkMethod.parkNanos);
250     }
testParkTimesOut_parkUntil()251     public void testParkTimesOut_parkUntil() {
252         testParkTimesOut(ParkMethod.parkUntil);
253     }
testParkTimesOut_parkNanosBlocker()254     public void testParkTimesOut_parkNanosBlocker() {
255         testParkTimesOut(ParkMethod.parkNanosBlocker);
256     }
testParkTimesOut_parkUntilBlocker()257     public void testParkTimesOut_parkUntilBlocker() {
258         testParkTimesOut(ParkMethod.parkUntilBlocker);
259     }
testParkTimesOut(final ParkMethod parkMethod)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      */
testGetBlockerNull()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      */
testGetBlocker_parkBlocker()288     public void testGetBlocker_parkBlocker() {
289         testGetBlocker(ParkMethod.parkBlocker);
290     }
testGetBlocker_parkNanosBlocker()291     public void testGetBlocker_parkNanosBlocker() {
292         testGetBlocker(ParkMethod.parkNanosBlocker);
293     }
testGetBlocker_parkUntilBlocker()294     public void testGetBlocker_parkUntilBlocker() {
295         testGetBlocker(ParkMethod.parkUntilBlocker);
296     }
testGetBlocker(final ParkMethod parkMethod)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      */
testPark0_parkNanos()336     public void testPark0_parkNanos() {
337         testPark0(ParkMethod.parkNanos);
338     }
testPark0_parkUntil()339     public void testPark0_parkUntil() {
340         testPark0(ParkMethod.parkUntil);
341     }
testPark0_parkNanosBlocker()342     public void testPark0_parkNanosBlocker() {
343         testPark0(ParkMethod.parkNanosBlocker);
344     }
testPark0_parkUntilBlocker()345     public void testPark0_parkUntilBlocker() {
346         testPark0(ParkMethod.parkUntilBlocker);
347     }
testPark0(final ParkMethod parkMethod)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      */
testParkNeg_parkNanos()360     public void testParkNeg_parkNanos() {
361         testParkNeg(ParkMethod.parkNanos);
362     }
testParkNeg_parkUntil()363     public void testParkNeg_parkUntil() {
364         testParkNeg(ParkMethod.parkUntil);
365     }
testParkNeg_parkNanosBlocker()366     public void testParkNeg_parkNanosBlocker() {
367         testParkNeg(ParkMethod.parkNanosBlocker);
368     }
testParkNeg_parkUntilBlocker()369     public void testParkNeg_parkUntilBlocker() {
370         testParkNeg(ParkMethod.parkUntilBlocker);
371     }
testParkNeg(final ParkMethod parkMethod)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