//
// Copyright (C) 2006 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.annotation.FilterField;
import gov.nasa.jpf.util.test.TestJPF;
import gov.nasa.jpf.vm.Verify;
/**
* threading test
*/
public class ThreadTest extends TestJPF {
static String didRunThread = null;
@Test public void testDaemon () {
if (verifyNoPropertyViolation()) {
Runnable r = new Runnable() {
public void run() {
Thread t = Thread.currentThread();
if (!t.isDaemon()) {
throw new RuntimeException("isDaemon failed");
}
didRunThread = t.getName();
}
};
didRunThread = null;
Thread t = new Thread(r);
t.setDaemon(true);
t.start();
try {
t.join();
} catch (InterruptedException ix) {
throw new RuntimeException("thread was interrupted");
}
String tname = Thread.currentThread().getName();
if ((didRunThread == null) || (didRunThread.equals(tname))) {
throw new RuntimeException("thread did not execute: " + didRunThread);
}
}
}
@Test public void testDaemonTermination () {
if (verifyNoPropertyViolation("+cg.threads.break_start=true",
"+cg.threads.break_yield=true")) {
final Thread mainThread = Thread.currentThread();
Runnable r = new Runnable() {
@FilterField // without this, we have a perfectly open state space and never finish in JPF
int n = 0;
public void run() {
while (true) { // loop forever or until main finishes
n++;
// NOTE: this does not necessarily hold outside of JPF, since the daemon might still run for a few cycles
assert (n < 100) || mainThread.isAlive() : "main terminated but daemon still running";
System.out.println(" daemon running in round: " + n);
Thread.yield();
}
}
};
Thread t = new Thread(r);
t.setDaemon(true);
t.start();
Thread.yield();
// finishing this thread should also (eventually) terminate the daemon
System.out.println("main terminating");
}
}
@Test public void testMain () {
if (verifyNoPropertyViolation()) {
Thread t = Thread.currentThread();
String refName = "main";
String name = t.getName();
if (!name.equals(refName)) {
throw new RuntimeException("wrong main thread name, is: " + name +
", expected: " + refName);
}
refName = "my-main-thread";
t.setName(refName);
name = t.getName();
if (!name.equals(refName)) {
throw new RuntimeException("Thread.setName() failed, is: " + name +
", expected: " + refName);
}
int refPrio = Thread.NORM_PRIORITY;
int prio = t.getPriority();
if (prio != refPrio) {
throw new RuntimeException("main thread has no NORM_PRIORITY: " + prio);
}
refPrio++;
t.setPriority(refPrio);
prio = t.getPriority();
if (prio != refPrio) {
throw new RuntimeException("main thread setPriority failed: " + prio);
}
if (t.isDaemon()) {
throw new RuntimeException("main thread is daemon");
}
}
}
@Test public void testName () {
if (verifyNoPropertyViolation()) {
Runnable r = new Runnable() {
public void run() {
Thread t = Thread.currentThread();
String name = t.getName();
if (!name.equals("my-thread")) {
throw new RuntimeException("wrong Thread name: " + name);
}
didRunThread = name;
}
};
didRunThread = null;
Thread t = new Thread(r, "my-thread");
//Thread t = new Thread(r);
t.start();
try {
t.join();
} catch (InterruptedException ix) {
throw new RuntimeException("thread was interrupted");
}
String tname = Thread.currentThread().getName();
if ((didRunThread == null) || (didRunThread.equals(tname))) {
throw new RuntimeException("thread did not execute: " + didRunThread);
}
}
}
public void testSingleYield () {
Thread.yield();
}
@Test public void testYield () {
if (verifyNoPropertyViolation("+cg.threads.break_start=true",
"+cg.threads.break_yield=true")) {
Runnable r = new Runnable() {
public void run() {
Thread t = Thread.currentThread();
while (!didRunThread.equals("blah")) {
Thread.yield();
}
didRunThread = t.getName();
}
};
didRunThread = "blah";
Thread t = new Thread(r);
t.start();
while (didRunThread.equals("blah")) {
Thread.yield();
}
String tname = Thread.currentThread().getName();
if ((didRunThread == null) || (didRunThread.equals(tname))) {
throw new RuntimeException("thread did not execute: " + didRunThread);
}
}
}
@Test public void testPriority () {
if (verifyNoPropertyViolation()) {
Runnable r = new Runnable() {
public void run() {
Thread t = Thread.currentThread();
int prio = t.getPriority();
if (prio != (Thread.MIN_PRIORITY + 2)) {
throw new RuntimeException("wrong Thread priority: " + prio);
}
didRunThread = t.getName();
}
};
didRunThread = null;
Thread t = new Thread(r);
t.setPriority(Thread.MIN_PRIORITY + 2);
t.start();
try {
t.join();
} catch (InterruptedException ix) {
throw new RuntimeException("thread was interrupted");
}
String tname = Thread.currentThread().getName();
if ((didRunThread == null) || (didRunThread.equals(tname))) {
throw new RuntimeException("thread did not execute: " + didRunThread);
}
}
}
@Test public void testJoin () {
if (verifyNoPropertyViolation()) {
Runnable r = new Runnable() {
public synchronized void run() {
didRunThread = Thread.currentThread().getName();
}
};
Thread t = new Thread(r);
synchronized (r) {
t.start();
Thread.yield();
if (didRunThread != null) {
throw new RuntimeException("sync thread did execute before lock release");
}
}
try {
t.join();
} catch (InterruptedException ix) {
throw new RuntimeException("main thread was interrupted");
}
if (didRunThread == null) {
throw new RuntimeException("sync thread did not run after lock release");
}
}
}
@Test public void testTimeoutJoin () {
if (!isJPFRun()){
Verify.resetCounter(0);
Verify.resetCounter(1);
}
if (verifyNoPropertyViolation()) {
Runnable r = new Runnable() {
public void run() {
synchronized(this){
System.out.println("[t] started");
}
didRunThread = Thread.currentThread().getName(); // this causes a CG
System.out.println("[t] finished");
}
};
Thread t = new Thread(r);
synchronized (r) {
t.start();
Thread.yield();
if (didRunThread != null) {
throw new RuntimeException("sync thread did execute before lock release");
}
}
try {
System.out.println("[main] joining..");
t.join(42);
System.out.println("[main] joined, t state: " + t.getState());
// we should get here for both terminated and non-terminated t
switch (t.getState()) {
case TERMINATED:
if (didRunThread != null){
Verify.incrementCounter(0);
}
break;
case RUNNABLE:
Verify.incrementCounter(1);
break;
default:
throw new RuntimeException("infeasible thread state: " + t.getState());
}
} catch (InterruptedException ix) {
throw new RuntimeException("main thread was interrupted");
}
}
if (!isJPFRun()){
assert Verify.getCounter(0) > 0;
assert Verify.getCounter(1) > 0;
}
}
@Test public void testInterrupt() {
if (verifyNoPropertyViolation()) {
Runnable r = new Runnable() {
public synchronized void run() {
try {
didRunThread = Thread.currentThread().getName();
System.out.println("-- t waiting");
wait();
} catch (InterruptedException x) {
System.out.println("-- t interrupted");
didRunThread = null;
}
System.out.println("-- t terminated");
}
};
Thread t = new Thread(r);
t.start();
while (didRunThread == null) {
Thread.yield();
}
synchronized (r) {
System.out.println("-- main thread interrupting...");
t.interrupt();
}
try {
t.join();
} catch (InterruptedException ix) {
throw new RuntimeException("main thread was interrupted");
}
if (didRunThread != null) {
throw new RuntimeException("t did not get interrupted");
}
System.out.println("-- main thread terminated");
}
}
@Test public void testSimpleThreadGroup () {
if (verifyNoPropertyViolation()) {
System.out.println("-- main thread started");
Thread mainThread = Thread.currentThread();
final ThreadGroup sysGroup = mainThread.getThreadGroup();
assert sysGroup != null && sysGroup.getName().equals("main");
int active = sysGroup.activeCount();
assert active == 1;
Thread[] list = new Thread[active];
int n = sysGroup.enumerate(list);
assert (n == active);
assert list[0] == mainThread;
Runnable r = new Runnable() {
public void run() {
System.out.println("-- t started");
didRunThread = Thread.currentThread().getName();
Thread t = Thread.currentThread();
ThreadGroup group = t.getThreadGroup();
assert group != null && group == sysGroup;
int active = group.activeCount();
assert active == 2;
Thread[] list = new Thread[active];
int n = group.enumerate(list);
assert (n == active);
assert list[1] == t;
System.out.println("-- t terminated");
}
};
Thread t = new Thread(r);
t.start();
try {
t.join();
} catch (InterruptedException ix) {
throw new RuntimeException("main thread was interrupted");
}
if (didRunThread == null) {
throw new RuntimeException("t did not run");
}
System.out.println("-- main thread terminated");
}
}
}