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