package hj.verify;
import gov.nasa.jpf.Config;
import gov.nasa.jpf.vm.DefaultSchedulerFactory;
import gov.nasa.jpf.vm.VM;
import gov.nasa.jpf.vm.SystemState;
import gov.nasa.jpf.vm.ChoiceGenerator;
import gov.nasa.jpf.vm.ThreadInfo;
import gov.nasa.jpf.vm.ElementInfo;
import gov.nasa.jpf.vm.ThreadList;
/**
*
* @author bchase
*
* This returns a special choice generator returns choices that
* decide whether to run only one choice, or multiple choices
*/
public class HJScheduler extends DefaultSchedulerFactory {
public HJScheduler (Config config, VM vm, SystemState ss) {
super(config,vm,ss);
}
@Override
protected ChoiceGenerator<ThreadInfo> getRunnableCG (String id, ThreadInfo ti) {
ThreadInfo[] choices = getRunnablesIfChoices(ti);
if (choices != null) {
return new HJThreadChoice( id, choices, true);
} else {
return null;
}
}
@Override
public ChoiceGenerator<ThreadInfo> createMonitorEnterCG(ElementInfo ei,
ThreadInfo ti) {
if (ti.isBlocked()) { // we have to return something
if (ss.isAtomic()) {
ss.setBlockedInAtomicSection();
}
return new HJThreadChoice("monitorEnter", getRunnables(ti), true);
} else {
if (ss.isAtomic()) {
return null;
}
return getSyncCG( "monitorEnter", ei, ti);
}
}
@Override
public ChoiceGenerator<ThreadInfo> createWaitCG (ElementInfo ei, ThreadInfo ti, long timeOut) {
if (ss.isAtomic()) {
ss.setBlockedInAtomicSection();
}
return new HJThreadChoice( "wait", getRunnables(ti), true);
}
@Override
public ChoiceGenerator<ThreadInfo> createNotifyCG (ElementInfo ei, ThreadInfo ti) {
if (ss.isAtomic()) {
return null;
}
ThreadInfo[] waiters = ei.getWaitingThreads();
if (waiters.length < 2) {
// if there are less than 2 threads waiting, there is no nondeterminism
return null;
} else {
return new HJThreadChoice( "notify", waiters, false);
}
}
@Override
public ChoiceGenerator<ThreadInfo> createParkCG (ElementInfo ei, ThreadInfo tiPark, boolean isAbsoluteTime, long timeOut){
// we treat this like a wait, but don't differentiate between absolute and relative timeout. Note it has to be a right mover
// note that tiPark is already blocked at this point
if (ss.isAtomic()) {
ss.setBlockedInAtomicSection();
}
return new HJThreadChoice( "park", getRunnables(tiPark), true);
}
@Override
public ChoiceGenerator<ThreadInfo> createThreadTerminateCG (ThreadInfo terminateThread) {
// terminateThread is already TERMINATED at this point
ThreadList tl = vm.getThreadList();
// NOTE returning null does not directly define an end state - that's up to
// a subsequent call to vm.isEndState()
// <2do> FIXME this is redundant and error prone
if (tl.hasAnyAliveThread()) {
return new HJThreadChoice( "terminate", getRunnablesWithout(terminateThread), true);
} else {
return null;
}
}
@Override
public ChoiceGenerator<ThreadInfo> createBeginAtomicCG (ThreadInfo atomicThread) {
if (ss.isAtomic()) {
return null;
}
return getRunnableCG("begin atomic", atomicThread);
}
public ChoiceGenerator<ThreadInfo> createEndIsolationCG (ThreadInfo runningThread) {
return new HJThreadChoice("STOP_ISOLATION", getRunnables(runningThread), true);
}
}