// // Copyright (C) 2008 United States Government as represented by the // Administrator of the National Aeronautics and Space Administration // (NASA). All Rights Reserved. // // This software is distributed under the NASA Open Source Agreement // (NOSA), version 1.3. The NOSA has been approved by the Open Source // Initiative. See the file NOSA-1.3-JPF at the top of the distribution // directory tree for the complete NOSA document. // // THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY // KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT // LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO // SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR // A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT // THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT // DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. // package gov.nasa.jpf.test.vm.threads; import org.junit.Test; import gov.nasa.jpf.util.test.TestJPF; /** * regression test for suspend/resume */ public class SuspendResumeTest extends TestJPF { static boolean isRunning; static boolean pass = false; static class T1 extends Thread { public void run(){ System.out.println("t1 running"); isRunning = true; while (!pass){ Thread.yield(); } System.out.println("t1 terminating"); } } @Test public void testBasicSuspendDeadlock(){ if (verifyDeadlock("+cg.threads.break_yield")) { Thread t1 = new T1(); t1.start(); while (!isRunning) { Thread.yield(); } t1.suspend(); assertTrue(t1.getState() == Thread.State.RUNNABLE); pass = true; // without resuming, T1 should not be scheduled again, despite being in a RUNNABLE state //t1.resume(); } } @Test public void testBasicSuspendResume(){ if (verifyNoPropertyViolation("+cg.threads.break_yield")) { Thread t1 = new T1(); t1.start(); while (!isRunning) { Thread.yield(); } System.out.println("main suspending t1"); t1.suspend(); assertTrue(t1.getState() == Thread.State.RUNNABLE); pass = true; System.out.println("main resuming t1"); t1.resume(); try { System.out.println("main joining t1"); t1.join(); } catch (InterruptedException ix){ fail("t1.join got interrupted"); } System.out.println("main terminating after t1.join"); } } //--------------- // this is the main reason to model suspend/resume, since suspension does // *not* give up any held locks, and hence is very prone to creating deadlocks static class T2 extends Thread { public synchronized void run(){ System.out.println("t2 running with lock"); isRunning = true; while (!pass){ Thread.yield(); } System.out.println("t2 terminating"); } } @Test public void testLockholderSuspendDeadlock(){ if (verifyDeadlock("+cg.threads.break_yield")) { Thread t2 = new T2(); t2.start(); while (!isRunning) { Thread.yield(); } System.out.println("main suspending t2"); t2.suspend(); // now t2 should hold and never give up its lock synchronized (t2){ fail("main should never get here"); } } } //------------ static class T3 extends Thread { public synchronized void run(){ System.out.println("t3 running"); isRunning = true; try { wait(); } catch (InterruptedException ix){ fail("t3 got interrupted"); } System.out.println("t3 terminating"); } } @Test public void testWaitingSuspendNotifyDeadlock(){ if (verifyDeadlock("+cg.threads.break_yield")) { Thread t3 = new T3(); t3.start(); while (!isRunning) { Thread.yield(); } synchronized (t3){ assertTrue( t3.getState() == Thread.State.WAITING); System.out.println("main suspending t3"); t3.suspend(); System.out.println("main notifying t3"); t3.notify(); // t3 should be still suspended, despite being notified } } } @Test public void testWaitingSuspendNotifyResume(){ if (verifyNoPropertyViolation("+cg.threads.break_yield")) { Thread t3 = new T3(); t3.start(); while (!isRunning) { Thread.yield(); } synchronized (t3){ assertTrue( t3.getState() == Thread.State.WAITING); System.out.println("main suspending t3"); t3.suspend(); System.out.println("main notifying t3"); t3.notify(); // t3 should be still suspended, despite being notified System.out.println("main resuming t3"); t3.resume(); try { System.out.println("main joining t3"); t3.join(); } catch (InterruptedException ix) { fail("t3.join got interrupted"); } System.out.println("main terminating after t3.join"); } } } //---------------- static class T4 extends Thread { public void run(){ System.out.println("t4 running "); isRunning = true; while (!pass){ Thread.yield(); } System.out.println("t4 trying to obtain lock"); synchronized (this){ System.out.println("t4 obtained lock"); } System.out.println("t4 terminating"); } } @Test public void testBlockSuspendUnblockDeadlock(){ if (verifyDeadlock("+cg.threads.break_yield")) { Thread t4 = new T4(); t4.start(); while (!isRunning) { Thread.yield(); } synchronized (t4){ pass = true; while (t4.getState() != Thread.State.BLOCKED){ Thread.yield(); } System.out.println("main suspending t4"); t4.suspend(); } System.out.println("main released t4 lock"); } } @Test public void testBlockSuspendUnblockResume(){ if (verifyNoPropertyViolation("+cg.threads.break_yield")) { Thread t4 = new T4(); t4.start(); while (!isRunning) { Thread.yield(); } synchronized (t4){ pass = true; while (t4.getState() != Thread.State.BLOCKED){ Thread.yield(); } System.out.println("main suspending t4"); t4.suspend(); } System.out.println("main released t4 lock"); System.out.println("main resuming t4"); t4.resume(); try { System.out.println("main joining t4"); t4.join(); } catch (InterruptedException ix) { fail("t4.join got interrupted"); } System.out.println("main terminating after t4.join"); } } }