Mercurial > hg > Members > kono > jpf-core
comparison src/tests/gov/nasa/jpf/test/vm/threads/JoinTest.java @ 0:61d41facf527
initial v8 import (history reset)
author | Peter Mehlitz <Peter.C.Mehlitz@nasa.gov> |
---|---|
date | Fri, 23 Jan 2015 10:14:01 -0800 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:61d41facf527 |
---|---|
1 /* | |
2 * Copyright (C) 2014, United States Government, as represented by the | |
3 * Administrator of the National Aeronautics and Space Administration. | |
4 * All rights reserved. | |
5 * | |
6 * The Java Pathfinder core (jpf-core) platform is licensed under the | |
7 * Apache License, Version 2.0 (the "License"); you may not use this file except | |
8 * in compliance with the License. You may obtain a copy of the License at | |
9 * | |
10 * http://www.apache.org/licenses/LICENSE-2.0. | |
11 * | |
12 * Unless required by applicable law or agreed to in writing, software | |
13 * distributed under the License is distributed on an "AS IS" BASIS, | |
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
15 * See the License for the specific language governing permissions and | |
16 * limitations under the License. | |
17 */ | |
18 | |
19 package gov.nasa.jpf.test.vm.threads; | |
20 | |
21 import gov.nasa.jpf.util.test.TestJPF; | |
22 import gov.nasa.jpf.vm.Verify; | |
23 | |
24 import org.junit.Test; | |
25 | |
26 | |
27 /** | |
28 * regression test for various Thread.join scenarios | |
29 */ | |
30 public class JoinTest extends TestJPF { | |
31 | |
32 static final String[] JPF_ARGS = { "+cg.threads.break_start=true", | |
33 "+cg.threads.break_yield=true", | |
34 "+vm.tree_output=false", | |
35 "+vm.path_output=true"}; | |
36 | |
37 @Test public void testSimpleJoin(){ | |
38 if (verifyNoPropertyViolation(JPF_ARGS)) { | |
39 Runnable r = new Runnable() { | |
40 @Override | |
41 public void run() { | |
42 System.out.println("thread-0 run"); | |
43 } | |
44 }; | |
45 | |
46 Thread t = new Thread(r); | |
47 t.start(); | |
48 | |
49 try { | |
50 t.join(); | |
51 assert !t.isAlive(); | |
52 System.out.println("main returned from join"); | |
53 } catch (InterruptedException x) { | |
54 fail("join() did throw InterruptedException"); | |
55 } | |
56 } | |
57 } | |
58 | |
59 @Test public void testNoRunnableSimpleJoin() { | |
60 if (verifyNoPropertyViolation(JPF_ARGS)) { | |
61 Thread t = new Thread() { | |
62 @Override | |
63 public synchronized void run() { | |
64 System.out.println("thread-0 run"); | |
65 } | |
66 }; | |
67 | |
68 t.start(); | |
69 | |
70 try { | |
71 t.join(); | |
72 assert !t.isAlive(); | |
73 System.out.println("main returned from join"); | |
74 } catch (InterruptedException x) { | |
75 fail("join() did throw InterruptedException"); | |
76 } | |
77 } | |
78 } | |
79 | |
80 static class SomeThread extends Thread { | |
81 Object o; | |
82 | |
83 @Override | |
84 public void run() { | |
85 synchronized (this){ | |
86 // this causes a transition break - write on a shared object while | |
87 // we still hold the lock | |
88 o = new Object(); | |
89 } | |
90 System.out.println("thread-0 done"); | |
91 } | |
92 } | |
93 | |
94 @Test public void testBlockedJoin() { | |
95 if (verifyNoPropertyViolation("+cg.threads.break_start=true", | |
96 "+vm.storage.class=null")) { | |
97 Thread t = new SomeThread(); | |
98 | |
99 t.start(); | |
100 System.out.println("main started thread-0"); | |
101 | |
102 try { | |
103 t.join(); | |
104 assert !t.isAlive(); | |
105 System.out.println("main returned from join"); | |
106 } catch (InterruptedException x) { | |
107 fail("join() did throw InterruptedException"); | |
108 } | |
109 } | |
110 } | |
111 | |
112 @Test public void testJoinHoldingLock(){ | |
113 if (verifyNoPropertyViolation(JPF_ARGS)) { | |
114 Runnable r = new Runnable() { | |
115 @Override | |
116 public void run() { | |
117 System.out.println("thread-0 run"); | |
118 } | |
119 }; | |
120 | |
121 Thread t = new Thread(r); | |
122 t.start(); | |
123 | |
124 try { | |
125 synchronized(t){ | |
126 t.join(); | |
127 } | |
128 System.out.println("main returned from join"); | |
129 } catch (InterruptedException x) { | |
130 fail("join() did throw InterruptedException"); | |
131 } | |
132 } | |
133 } | |
134 | |
135 | |
136 @Test public void testNotAliveJoin(){ | |
137 if (verifyNoPropertyViolation(JPF_ARGS)) { | |
138 Runnable r = new Runnable() { | |
139 @Override | |
140 public void run() { | |
141 System.out.println("thread-0 run"); | |
142 } | |
143 }; | |
144 | |
145 Thread t = new Thread(r); | |
146 t.start(); | |
147 | |
148 // poor man's join | |
149 while (t.isAlive()){ | |
150 Thread.yield(); | |
151 } | |
152 | |
153 try { | |
154 t.join(); | |
155 System.out.println("main returned from join"); | |
156 } catch (InterruptedException x) { | |
157 fail("join() did throw InterruptedException"); | |
158 } | |
159 } | |
160 } | |
161 | |
162 @Test public void testPreJoinInterrupt() { | |
163 if (verifyNoPropertyViolation(JPF_ARGS)) { | |
164 Runnable r = new Runnable() { | |
165 @Override | |
166 public void run() { | |
167 System.out.println("thread-0 run"); | |
168 } | |
169 }; | |
170 | |
171 Thread.currentThread().interrupt(); | |
172 | |
173 Thread t = new Thread(r); | |
174 t.start(); | |
175 | |
176 try { | |
177 t.join(); | |
178 fail("join() didn't throw InterruptedException"); | |
179 } catch (InterruptedException x) { | |
180 System.out.println("caught InterruptedException"); | |
181 } | |
182 } | |
183 } | |
184 | |
185 @Test public void testInterruptedJoin() { | |
186 if (verifyNoPropertyViolation(JPF_ARGS)) { | |
187 final Thread mainThread = Thread.currentThread(); | |
188 | |
189 Runnable r = new Runnable() { | |
190 @Override | |
191 public void run() { | |
192 System.out.println("thread-0 interrupting main"); | |
193 mainThread.interrupt(); | |
194 } | |
195 }; | |
196 | |
197 Thread t = new Thread(r); | |
198 t.start(); | |
199 | |
200 try { | |
201 t.join(); | |
202 fail("join() didn't throw InterruptedException"); | |
203 } catch (InterruptedException x) { | |
204 System.out.println("caught InterruptedException"); | |
205 } | |
206 } | |
207 } | |
208 | |
209 @Test public void testJoinLoop() { | |
210 if (verifyDeadlock(JPF_ARGS)) { | |
211 try { | |
212 Thread.currentThread().join(); | |
213 fail("main can't get here if waiting for itself"); | |
214 } catch (InterruptedException ex) { | |
215 fail("thread cannot be interrupted"); | |
216 } | |
217 } | |
218 } | |
219 | |
220 @Test public void testMultipleJoins() { | |
221 if (verifyNoPropertyViolation(JPF_ARGS)) { | |
222 try { | |
223 final Thread t1 = new Thread() { | |
224 @Override | |
225 public void run() { | |
226 Thread.yield(); | |
227 } | |
228 }; | |
229 Thread t2 = new Thread() { | |
230 @Override | |
231 public void run() { | |
232 try { | |
233 t1.join(); | |
234 } catch (InterruptedException e) { | |
235 fail("unexpected interrupt"); | |
236 } | |
237 } | |
238 }; | |
239 | |
240 t1.start(); | |
241 t2.start(); | |
242 t1.join(); | |
243 t2.join(); | |
244 | |
245 assert (!t1.isAlive() && !t2.isAlive()); | |
246 } catch (Exception ex) { | |
247 fail("unexpected exception: " + ex); | |
248 } | |
249 } | |
250 } | |
251 | |
252 @Test public void testJoinBeforeStart() { | |
253 if (verifyNoPropertyViolation(JPF_ARGS)) { | |
254 try { | |
255 Thread t = new Thread(); | |
256 t.join(); | |
257 System.out.println("join on not-yet-started thread has no effect"); | |
258 } catch (Exception ex) { | |
259 fail(ex.getMessage()); | |
260 } | |
261 } | |
262 } | |
263 | |
264 | |
265 @Test public void testJoinAfterNotify() { | |
266 if (verifyNoPropertyViolation(JPF_ARGS)) { | |
267 try { | |
268 final Thread t = new Thread() { | |
269 @Override | |
270 public void run() { | |
271 synchronized(this){ | |
272 System.out.println("thread-0 notifying"); | |
273 notifyAll(); // this should not get us out of the join() | |
274 } | |
275 System.out.println("thread-0 terminating"); | |
276 } | |
277 }; | |
278 | |
279 t.start(); | |
280 System.out.println("main joining.."); | |
281 t.join(); | |
282 System.out.println("main joined"); | |
283 | |
284 Verify.printPathOutput("main termination"); | |
285 assert !t.isAlive(); | |
286 | |
287 } catch (Exception ex) { | |
288 fail("unexpected exception: " + ex); | |
289 } | |
290 } | |
291 } | |
292 | |
293 @Test public void testJoinNotifyDeadlock() { | |
294 if (verifyDeadlock(JPF_ARGS)) { | |
295 try { | |
296 final Thread t = new Thread() { | |
297 @Override | |
298 public void run() { | |
299 synchronized(this){ | |
300 System.out.println("thread-0 notifying"); | |
301 notifyAll(); | |
302 | |
303 try { | |
304 System.out.println("thread-0 waiting"); | |
305 wait(); | |
306 } catch (InterruptedException ix){ | |
307 System.out.println("unexpected interrupt"); | |
308 } | |
309 } | |
310 System.out.println("thread-0 terminating"); | |
311 } | |
312 }; | |
313 | |
314 t.start(); | |
315 System.out.println("main joining.."); | |
316 t.join(); | |
317 System.out.println("main joined"); | |
318 | |
319 synchronized (t){ | |
320 System.out.println("main notifying"); | |
321 t.notify(); | |
322 } | |
323 | |
324 Verify.printPathOutput("main termination"); | |
325 assert !t.isAlive(); | |
326 | |
327 } catch (Exception ex) { | |
328 fail("unexpected exception: " + ex); | |
329 } | |
330 } | |
331 } | |
332 | |
333 | |
334 @Test public void testRedundantJoin() { | |
335 if (verifyNoPropertyViolation(JPF_ARGS)) { | |
336 try { | |
337 Thread t = new Thread(); | |
338 | |
339 t.start(); | |
340 t.join(); | |
341 System.out.println("main returned from first join()"); | |
342 t.join(); | |
343 System.out.println("main returned from second join()"); | |
344 | |
345 assert (!t.isAlive()); | |
346 } catch (Exception ex) { | |
347 fail(ex.getMessage()); | |
348 } | |
349 } | |
350 } | |
351 | |
352 @Test public void testJoinThreadSet(){ | |
353 if (verifyNoPropertyViolation(JPF_ARGS)) { | |
354 final Thread[] worker = new Thread[3]; | |
355 worker[0] = new Thread(new Runnable() { | |
356 @Override | |
357 public void run() { | |
358 System.out.println("worker[0] finished"); | |
359 } | |
360 }); | |
361 worker[1] = new Thread(new Runnable() { | |
362 @Override | |
363 public void run() { | |
364 System.out.println("worker[1] finished"); | |
365 } | |
366 }); | |
367 worker[2] = new Thread(new Runnable() { | |
368 @Override | |
369 public void run() { | |
370 System.out.println("worker[2] finished"); | |
371 } | |
372 }); | |
373 | |
374 int nJoin = 0; | |
375 for (int i = 0; i < worker.length; i++) { | |
376 worker[i].start(); | |
377 nJoin++; | |
378 } | |
379 | |
380 while (nJoin > 0) { | |
381 for (int i = 0; i < worker.length; i++) { | |
382 if (worker[i] != null) { | |
383 try { | |
384 worker[i].join(); | |
385 } catch (InterruptedException x) { | |
386 fail("unexpected interrupt"); | |
387 } | |
388 nJoin--; | |
389 worker[i] = null; | |
390 System.out.println("main joined worker[" + i + "]"); | |
391 } | |
392 } | |
393 } | |
394 } | |
395 } | |
396 | |
397 | |
398 @Test public void testRecursiveJoinThreadGroup() { | |
399 if (!isJPFRun()){ | |
400 Verify.resetCounter(0); | |
401 Verify.resetCounter(1); | |
402 Verify.resetCounter(2); | |
403 Verify.resetCounter(3); | |
404 } | |
405 | |
406 if (verifyNoPropertyViolation(JPF_ARGS)) { | |
407 | |
408 ThreadGroup workers = new ThreadGroup("workers"); | |
409 | |
410 Thread t = new Thread( workers, new Runnable(){ | |
411 @Override | |
412 public void run() { | |
413 Thread t1 = new Thread( new Runnable(){ | |
414 @Override | |
415 public void run() { | |
416 Thread t11 = new Thread(new Runnable() { | |
417 @Override | |
418 public void run() { | |
419 System.out.println("t11 run"); | |
420 Verify.incrementCounter(0); | |
421 } | |
422 }, "t11"); | |
423 t11.start(); | |
424 System.out.println("t1 run"); | |
425 Verify.incrementCounter(1); | |
426 } | |
427 }, "t1"); | |
428 t1.start(); | |
429 | |
430 Thread t2 = new Thread( new Runnable(){ | |
431 @Override | |
432 public void run() { | |
433 System.out.println("t2 run"); | |
434 Verify.incrementCounter(2); | |
435 } | |
436 }, "t2"); | |
437 t2.start(); | |
438 System.out.println("t run"); | |
439 Verify.incrementCounter(3); | |
440 } | |
441 }, "t"); | |
442 t.start(); | |
443 | |
444 try { | |
445 Thread[] actives = new Thread[10]; // the length is just a guess here | |
446 int nActives = workers.enumerate(actives, true); | |
447 System.out.println("main joining " + nActives + " active threads"); | |
448 | |
449 while (nActives > 0){ | |
450 assert nActives < actives.length; // it has to be strictly less to know we've got all | |
451 for (int i=0; i<nActives; i++){ | |
452 System.out.println("main joining: " + actives[i].getName()); | |
453 actives[i].join(); | |
454 System.out.println("main joined: " + actives[i].getName()); | |
455 } | |
456 nActives = workers.enumerate(actives, true); | |
457 System.out.println("..main now joining " + nActives + " active threads"); | |
458 } | |
459 } catch (Throwable x){ | |
460 fail("unexpected exception: " + x); | |
461 } | |
462 | |
463 System.out.println("main done"); | |
464 Verify.printPathOutput("end"); | |
465 } | |
466 | |
467 if (!isJPFRun()){ | |
468 // not an ideal test since we don't know if the threads are still alive | |
469 assert Verify.getCounter(0) > 0; | |
470 assert Verify.getCounter(1) > 0; | |
471 assert Verify.getCounter(2) > 0; | |
472 assert Verify.getCounter(3) > 0; | |
473 } | |
474 } | |
475 | |
476 | |
477 @Test | |
478 public void testInterruptThreadWaitingToJoin() { | |
479 if (!isJPFRun()){ | |
480 Verify.resetCounter(0); | |
481 } | |
482 | |
483 if (verifyNoPropertyViolation(JPF_ARGS)) { | |
484 try { | |
485 class ChildThread extends Thread { | |
486 Thread toInterrupt; | |
487 public void setToInterrupt(Thread toInterrupt) { | |
488 this.toInterrupt = toInterrupt; | |
489 } | |
490 @Override | |
491 public void run() { | |
492 toInterrupt.interrupt(); | |
493 } | |
494 } | |
495 final ChildThread child = new ChildThread(); | |
496 | |
497 class WaitingToJoinThread extends Thread { | |
498 @Override | |
499 public void run() { | |
500 try { | |
501 child.setToInterrupt(this); | |
502 child.start(); | |
503 child.join(); | |
504 } catch (InterruptedException ix) { | |
505 System.out.println("-- parent interrupted while child continues to run"); | |
506 Verify.incrementCounter(0); | |
507 } | |
508 } | |
509 } | |
510 | |
511 WaitingToJoinThread threadWaitingToJoin = new WaitingToJoinThread(); | |
512 | |
513 threadWaitingToJoin.start(); | |
514 try { | |
515 threadWaitingToJoin.join(); | |
516 } catch (InterruptedException ix) { | |
517 throw new RuntimeException("main thread was interrupted"); | |
518 } | |
519 try { | |
520 child.join(); | |
521 } catch (InterruptedException ix) { | |
522 throw new RuntimeException("main thread was interrupted"); | |
523 } | |
524 } catch (Exception ex) { | |
525 throw new RuntimeException(ex.getMessage()); | |
526 } | |
527 } | |
528 | |
529 if (!isJPFRun()){ | |
530 // at least one execution interrupts parent while child continues to run | |
531 assert Verify.getCounter(0) > 0; | |
532 } | |
533 } | |
534 | |
535 @Test public void testTimeoutJoin () { | |
536 if (!isJPFRun()){ | |
537 Verify.resetCounter(0); | |
538 Verify.resetCounter(1); | |
539 } | |
540 | |
541 if (verifyNoPropertyViolation(JPF_ARGS)) { | |
542 Runnable r = new Runnable() { | |
543 @Override | |
544 public void run() { | |
545 System.out.println("thread-0 run"); | |
546 Thread.yield(); | |
547 } | |
548 }; | |
549 | |
550 Thread t = new Thread(r); | |
551 t.start(); | |
552 //Thread.yield(); | |
553 | |
554 try { | |
555 System.out.println("main joining.."); | |
556 t.join(42); | |
557 System.out.println("main joined, t state: " + t.getState()); | |
558 | |
559 // we should get here for both terminated and non-terminated thread | |
560 switch (t.getState()) { | |
561 case TERMINATED: | |
562 System.out.println("got terminated case"); | |
563 Verify.incrementCounter(0); | |
564 break; | |
565 case RUNNABLE: | |
566 System.out.println("got timedout case"); | |
567 Verify.incrementCounter(1); | |
568 break; | |
569 default: | |
570 fail("infeasible thread state: " + t.getState()); | |
571 } | |
572 | |
573 } catch (InterruptedException ix) { | |
574 fail("main thread was interrupted"); | |
575 } | |
576 } | |
577 | |
578 if (!isJPFRun()) { | |
579 assert Verify.getCounter(0) > 0; | |
580 assert Verify.getCounter(1) > 0; | |
581 } | |
582 } | |
583 | |
584 @Test public void testZeroTimeoutJoin () { | |
585 if (!isJPFRun()){ | |
586 Verify.resetCounter(0); | |
587 Verify.resetCounter(1); | |
588 } | |
589 | |
590 if (verifyNoPropertyViolation(JPF_ARGS)) { | |
591 Runnable r = new Runnable() { | |
592 @Override | |
593 public void run() { | |
594 System.out.println("thread-0 run"); | |
595 Thread.yield(); | |
596 } | |
597 }; | |
598 | |
599 Thread t = new Thread(r); | |
600 t.start(); | |
601 //Thread.yield(); | |
602 | |
603 try { | |
604 System.out.println("main joining.."); | |
605 t.join(0); | |
606 System.out.println("main joined, t state: " + t.getState()); | |
607 | |
608 // we should get here for both terminated and non-terminated thread | |
609 switch (t.getState()) { | |
610 case TERMINATED: | |
611 Verify.incrementCounter(0); | |
612 break; | |
613 case RUNNABLE: | |
614 Verify.incrementCounter(1); | |
615 break; | |
616 default: | |
617 fail("infeasible thread state: " + t.getState()); | |
618 } | |
619 | |
620 } catch (InterruptedException ix) { | |
621 fail("main thread was interrupted"); | |
622 } | |
623 } | |
624 | |
625 if (!isJPFRun()) { | |
626 assert Verify.getCounter(0) > 0; | |
627 assert Verify.getCounter(1) == 0; | |
628 } | |
629 } | |
630 | |
631 @Test public void testNegativeTimeoutJoin() { | |
632 if (verifyNoPropertyViolation(JPF_ARGS)) { | |
633 try { | |
634 Thread t = new Thread(); | |
635 t.join(-1); | |
636 fail("should never get here"); | |
637 } catch (InterruptedException ix) { | |
638 fail("unexpected InterruptedException"); | |
639 } catch (IllegalArgumentException ax){ | |
640 System.out.println("caught " + ax); | |
641 } | |
642 } | |
643 } | |
644 | |
645 @Test public void testNestedLocksJoin() { | |
646 if (verifyNoPropertyViolation(JPF_ARGS)){ | |
647 Thread t1 = new Thread() { | |
648 @Override | |
649 public synchronized void run() { | |
650 System.out.println("t1 notifying"); | |
651 notifyAll(); | |
652 | |
653 try{ | |
654 System.out.println("t1 waiting"); | |
655 wait(); | |
656 } catch (InterruptedException ix){ | |
657 System.out.println("t1 unexpectedly interrupted"); | |
658 } | |
659 | |
660 System.out.println("t1 terminating"); | |
661 } | |
662 }; | |
663 | |
664 Thread t2 = new Thread() { | |
665 @Override | |
666 public synchronized void run() { | |
667 System.out.println("t2 notifying"); | |
668 notifyAll(); | |
669 | |
670 try{ | |
671 System.out.println("t2 waiting"); | |
672 wait(); | |
673 } catch (InterruptedException ix){ | |
674 System.out.println("t2 unexpectedly interrupted"); | |
675 } | |
676 | |
677 System.out.println("t2 terminating"); | |
678 } | |
679 }; | |
680 | |
681 synchronized (t2){ | |
682 try { | |
683 t2.start(); | |
684 | |
685 System.out.println("main waiting on t2"); | |
686 t2.wait(); | |
687 | |
688 synchronized(t1){ | |
689 t1.start(); | |
690 | |
691 System.out.println("main waiting on t1"); | |
692 t1.wait(); | |
693 | |
694 System.out.println("main notifying t1"); | |
695 t1.notify(); | |
696 } | |
697 | |
698 System.out.println("main joining t1"); | |
699 t1.join(); | |
700 | |
701 System.out.println("main notifying t2"); | |
702 t2.notify(); | |
703 | |
704 System.out.println("main joining t2"); | |
705 t2.join(); | |
706 | |
707 } catch (InterruptedException ix){ | |
708 System.out.println("main unexpectedly interrupted"); | |
709 } | |
710 } | |
711 | |
712 System.out.println("main terminating"); | |
713 Verify.printPathOutput("main termination"); | |
714 } | |
715 } | |
716 } |