//
// Administrator of the National Aeronautics and Space Administration
// Copyright (C) 2006 United States Government as represented by the
// (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.mc.threads;
import org.junit.Test;
import gov.nasa.jpf.util.test.TestJPF;
/**
* various deadlock detection test
*/
public class DeadlockTest extends TestJPF {
//--- tests
abstract class SyncRunnable implements Runnable {
SyncRunnable other;
public void setOther(SyncRunnable other) {
this.other = other;
}
public abstract void doSomething();
public abstract void doSomethingElse();
public abstract void run();
}
/**
* Required by the testMissedSignalDeadlock().
*/
class Event {
int count = 0;
public synchronized void signal_event() {
count = (count + 1) % 3;
notifyAll();
}
public synchronized void wait_for_event() {
try {
wait();
} catch (InterruptedException e) {
}
}
}
/**
* Required by the testMissedSignalDeadlock().
*/
class FirstTask extends java.lang.Thread {
Event event1;
Event event2;
int count = 0;
public FirstTask(Event e1, Event e2) {
event1 = e1;
event2 = e2;
}
public void run() {
count = event1.count;
while (true) {
if (count == event1.count) {
event1.wait_for_event();
}
count = event1.count;
event2.signal_event();
}
}
}
/**
* Required by the testMissedSignalDeadlock().
*/
class SecondTask extends java.lang.Thread {
Event event1;
Event event2;
int count = 0;
public SecondTask(Event e1, Event e2) {
event1 = e1;
event2 = e2;
}
public void run() {
count = event2.count;
while (true) {
event1.signal_event();
if (count == event2.count) {
event2.wait_for_event();
}
count = event2.count;
}
}
}
class SyncBlockRunnable extends SyncRunnable {
public void doSomething() {
synchronized (this) {
other.doSomethingElse();
}
}
public void doSomethingElse() {
synchronized (this) {
}
}
public void run() {
//while (true) {
synchronized (this) {
other.doSomething();
}
//}
}
}
class SyncMthRunnable extends SyncRunnable {
public synchronized void doSomething() {
other.doSomethingElse();
}
public synchronized void doSomethingElse() {
}
public synchronized void run() {
//while (true) {
other.doSomething();
//}
}
}
static Object lock1 = new Object();
static Object lock2 = new Object();
static int counter;
/**
* classical asymmetric lock order deadlock
*/
@Test
public void testLockOrderDeadlock() {
if (verifyDeadlock()) {
Thread t1 = new Thread(new Runnable() {
public void run() {
synchronized (lock1) {
synchronized (lock2) {
counter++;
}
}
System.out.println("t1 finished");
}
});
Thread t2 = new Thread(new Runnable() {
public void run() {
synchronized (lock2) {
synchronized (lock1) {
counter--;
}
}
System.out.println("t2 finished");
}
});
t1.start();
t2.start();
}
}
/**
* a nested monitor lockout
*/
static Object lock = new Object();
static Object sig = new Object();
@Test
public void testNestedMonitorLockoutDeadlock() {
if (verifyDeadlock()) {
Thread t1 = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 3; i++) {
synchronized (lock) {
synchronized (sig) {
try {
sig.wait();
} catch (InterruptedException ix) {
}
}
}
}
System.out.println("t1 finished");
}
});
Thread t2 = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 2; i++) {
synchronized (sig) {
synchronized (lock) {
}
sig.notify();
}
}
System.out.println("t2 finished");
}
});
t1.start();
t2.start();
}
}
@Test
public void testSimpleMissedSignal() {
if (verifyDeadlock()) {
Thread t1 = new Thread(new Runnable() {
public void run() {
synchronized (sig) {
try {
sig.wait();
} catch (InterruptedException ix) {
}
}
System.out.println("t1 finished");
}
});
Thread t2 = new Thread(new Runnable() {
public void run() {
synchronized (sig) {
sig.notify();
}
System.out.println("t2 finished");
}
});
t1.start();
t2.start();
}
}
/**
* Testing for deadlocks resulting from missed signal. This is the original
* oldclassic example which has been turned into a test case.
* as the name implies - a missed signal deadlock
*/
@Test
public void testMissedSignalDeadlock() {
if (verifyDeadlock()) {
Event new_event1 = new Event();
Event new_event2 = new Event();
FirstTask task1 = new FirstTask(new_event1, new_event2);
SecondTask task2 = new SecondTask(new_event1, new_event2);
task1.start();
task2.start();
}
}
/**
* the test which mixes synchronized method attr with MONITORENTER/EXIT
* simple lock order deadlock
*/
@Test
public void testMixedDeadlock() {
if (verifyDeadlock()) {
SyncRunnable r1 = new SyncMthRunnable();
SyncRunnable r2 = new SyncBlockRunnable();
r1.setOther(r2);
r2.setOther(r1);
//Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
Thread t1 = new Thread(r1);
t1.start();
t2.start();
}
}
/**
* the test which checks MONITORENTER / MONITOREXIT
* simple lock order deadlock
*/
@Test
public void testSyncBlockDeadlock() {
if (verifyDeadlock()) {
SyncRunnable r1 = new SyncBlockRunnable();
SyncRunnable r2 = new SyncBlockRunnable();
r1.setOther(r2);
r2.setOther(r1);
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
}
}
/**
* the test which checks the synchronized method attribute
* simple lock order deadlock
*/
@Test
public void testSyncMthDeadlock() {
if (verifyDeadlock()) {
SyncRunnable r1 = new SyncMthRunnable();
SyncRunnable r2 = new SyncMthRunnable();
r1.setOther(r2);
r2.setOther(r1);
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
}
}
@Test
public void testTerminationDeadlock() {
if (verifyDeadlock()){
Thread t = new Thread(){
public void run(){
System.out.println("# t running");
synchronized(this){
System.out.println("# t waiting (forever)..");
try {
wait();
} catch (InterruptedException ix){
fail("t got unexpectedly interrupted");
}
}
}
};
t.start();
System.out.println("# main thread terminating");
}
}
}