/**************************************************************************
* File name : PriorityScheduler.java
*
* This file is part a SCJ Level 0 and Level 1 implementation,
* based on SCJ Draft, Version 0.94 25 June 2013.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This SCJ Level 0 and Level 1 implementation is distributed in the hope
* that it will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this SCJ Level 0 and Level 1 implementation.
* If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2012
* @authors Anders P. Ravn, Aalborg University, DK
* Stephan E. Korsholm and Hans Søndergaard,
* VIA University College, DK
*************************************************************************/
package javax.safetycritical;
import icecaptools.IcecapCompileMe;
import javax.realtime.AbsoluteTime;
import javax.realtime.Clock;
import javax.realtime.RelativeTime;
import javax.safetycritical.annotate.Level;
import javax.safetycritical.annotate.SCJAllowed;
import javax.scj.util.Const;
import javax.scj.util.Priorities;
/**
* This class represents the priority-based scheduler for Level 1 and 2. <br>
* The only access to the priority scheduler is for obtaining the software
* priorities.
*
* @version 1.2; - December 2013
*
* @author Anders P. Ravn, Aalborg University, <A
* HREF="mailto:apr@cs.aau.dk">apr@cs.aau.dk</A>, <br>
* Hans Søndergaard, VIA University College, Denmark, <A
* HREF="mailto:hso@viauc.dk">hso@via.dk</A>
*/
@SCJAllowed(Level.LEVEL_1)
public class PriorityScheduler extends javax.realtime.PriorityScheduler {
PriorityFrame pFrame;
ScjProcess current;
PrioritySchedulerImpl prioritySchedulerImpl;
Clock rtClock;
RelativeTime timeGrain;
AbsoluteTime now;
private static PriorityScheduler scheduler = new PriorityScheduler();
ScjProcess outerMostSeqProcess = null;
/**
*
* @return The priority scheduler.
*/
/*@
behaviour
requires true;
assignable \nothing;
ensures \result != null ;
@*/
@SCJAllowed(Level.LEVEL_1)
public static PriorityScheduler instance() {
// if (scheduler == null) {
// scheduler = new PriorityScheduler();
// }
return scheduler;
}
private PriorityScheduler() {
int[] schedulerStack = new int[Const.PRIORITY_SCHEDULER_STACK_SIZE];
this.pFrame = new PriorityFrame(Const.DEFAULT_PRIORITY_QUEUE_SIZE);
this.prioritySchedulerImpl = new PrioritySchedulerImpl();
vm.ClockInterruptHandler.initialize(this.prioritySchedulerImpl,
schedulerStack);
this.rtClock = Clock.getRealtimeClock();
this.now = new AbsoluteTime(this.rtClock);
rtClock.getTime(this.now);
this.timeGrain = new RelativeTime(0, 0, this.rtClock);
rtClock.getResolution(this.timeGrain);
scheduler = this;
}
void addOuterMostSeq(MissionSequencer<?> seq ) {
ScjProcess process = ManagedSchedMethods.createScjProcess(seq);
process.index = -2;
MissionSequencer.missSeqProcess = process;
outerMostSeqProcess = seq.process;
pFrame.addProcess(process);
}
private vm.Process mainProcess;
private void processStart() {
vm.ClockInterruptHandler clockHandler = vm.ClockInterruptHandler.instance;
mainProcess = new vm.Process(null, null);
clockHandler.register();
clockHandler.enable();
clockHandler.startClockHandler(mainProcess);
clockHandler.yield();
}
@IcecapCompileMe
void stop(vm.Process current) {
current.transferTo(mainProcess);
}
void start() {
current = pFrame.readyQueue.extractMax();
processStart();
}
void release(AperiodicEventHandler handler) {
// see AperiodicEventHandler, where release is called
vm.ClockInterruptHandler.instance.disable();
if (handler.process.state == ScjProcess.State.EXECUTING) {
; // do nothing, - is already running
}
else if (handler.process.state == ScjProcess.State.BLOCKED) {
handler.process.state = ScjProcess.State.READY;
handler.process.start();
pFrame.readyQueue.insert(handler.process);
} else {
; // it is already ready
}
vm.ClockInterruptHandler.instance.enable();
}
@IcecapCompileMe
ScjProcess move() {
if (current == ScjProcess.idleProcess) {
pFrame.readyQueue.insert(current);
}
else {
current.gotoNextState(pFrame);
}
// Move processes from sleepingQueue to readyQueue
ScjProcess process = pFrame.sleepingQueue.minimum();
rtClock.getTime(now);
while (process != null && process.next.compareTo(now) <= 0) {
process.state = ScjProcess.State.READY;
ScjProcess t = pFrame.sleepingQueue.extractMin();
//devices.Console.println("PrSch.move:sleep --> ready: " + t.index);
pFrame.readyQueue.insert(t);
// look at "next" process in sleeping queue with smallest
// activationTime
process = pFrame.sleepingQueue.minimum();
}
// get next process from readyQueue
ScjProcess nextProcess = pFrame.readyQueue.extractMax();
nextProcess.state = ScjProcess.State.EXECUTING;
current = nextProcess;
if ( current == ScjProcess.idleProcess &&
pFrame.sleepingQueue.heapSize == 0
&& pFrame.waitQueue.queueSize == 0 && pFrame.lockQueue.queueSize == 0)
{
current.getTarget().cleanUp();
//devices.Console.println("PrioritySch.move: null; missions: " + MissionSequencer.howManyMissions);
return null;
} else {
return nextProcess;
}
}
ScjProcess getCurrentProcess() {
return current;
}
/**
*
* @return The maximum hardware real-time priority supported by this
* scheduler.
*/
@SCJAllowed(Level.LEVEL_1)
public int getMaxHardwarePriority() {
return Priorities.MAX_HARDWARE_PRIORITY;
}
/**
*
* @return The minimum hardware real-time priority supported by this
* scheduler.
*/
@SCJAllowed(Level.LEVEL_1)
public int getMinHardwarePriority() {
return Priorities.MIN_HARDWARE_PRIORITY;
}
void insertReadyQueue(ScjProcess process) {
pFrame.readyQueue.insert(process);
}
void addProcessToLockQueue(Object target, ScjProcess process) {
pFrame.lockQueue.addProcess(target, process);
}
ScjProcess getProcessFromLockQueue(Object monitor) {
return pFrame.lockQueue.getNextProcess(monitor);
}
void wait(Object target) {
prioritySchedulerImpl.wait(target);
}
void notify(Object target) {
prioritySchedulerImpl.notify(target);
}
void notifyAll(Object target) {
prioritySchedulerImpl.notifyAll(target);
}
void moveToNext() {
ScjProcess nextProcess = pFrame.readyQueue.extractMax();
nextProcess.state = ScjProcess.State.EXECUTING;
current = nextProcess;
//devices.Console.println("<<< From readyQueue to current: " + nextProcess.index);
}
// public static boolean waitForObject(Object target, HighResolutionTime time) {
// return PrioritySchedulerImpl.waitForObject(target, time);
// }
/**
* Print out the contents of the queues.
* For testing only.
*/
public void printQueues() {
vm.ClockInterruptHandler.instance.disable();
devices.Console.println("");
// devices.Console.println("PriorityScheduler: current process: "
// + current.getTarget() + "; index: " + current.index);
//devices.Console.println("----------- ready queue ----------");
pFrame.readyQueue.print();
//devices.Console.println("----------- sleeping queue ----------");
pFrame.sleepingQueue.print();
//devices.Console.println("----------- lock queue ----------");
pFrame.lockQueue.print();
//devices.Console.println("----------- wait queue ----------");
pFrame.waitQueue.print();
devices.Console.println("");
vm.ClockInterruptHandler.instance.enable();
}
}