/************************************************************************** * File name : CyclicExecutive.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 javax.realtime.AbsoluteTime; import javax.realtime.Clock; import javax.realtime.RelativeTime; import javax.safetycritical.annotate.Level; import javax.safetycritical.annotate.Phase; import javax.safetycritical.annotate.SCJAllowed; /** * A <code>CyclicExecutive</code> represents a Level 0 mission. Every mission * in a Level 0 application must be a subclass of <code>CyclicExecutive</code>. * * @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 public abstract class CyclicExecutive extends Mission { Clock rtClock; AbsoluteTime next; RelativeTime deltaTime; @SCJAllowed public CyclicExecutive() { this.rtClock = Clock.getRealtimeClock(); this.next = rtClock.getTime(); this.deltaTime = new RelativeTime(rtClock); } /** * Every <code>CyclicExecutive</code> shall provide its own cyclic schedule, which is represented * by an instance of the <code>CyclicSchedule</code> class. Application programmers are expected to override * the <code>getSchedule</code> method to provide a schedule that is appropriate for the mission.<br> * Level 0 infrastructure code invokes the <code>getSchedule</code> method on the mission returned from * <code>MissionSequencer.getNextMission</code> after invoking the mission's <code>initialize</code> method * in order to obtain the desired cyclic schedule. <br> * Upon entry into the <code>getSchedule</code> method, this mission's <code>MissionMemory</code> area shall be the * active allocation context. The value returned from <code>getSchedule</code> must reside in the current * mission's <code>MissionMemory</code> area or in some enclosing scope. <br> * Infrastructure code shall check that all of the <code>PeriodicEventHandler</code> objects referenced * from within the returned <code>CyclicSchedule</code> object have been registered for execution with this mission. * * @param handlers The handlers that have been registered with <code>this Mission</code>. * The handler objects must reside in an enclosing scope of <code>this</code>. * @return A cyclic schedule for the handlers. */ @SCJAllowed(Level.INFRASTRUCTURE) public abstract CyclicSchedule getSchedule(PeriodicEventHandler[] handlers); void runInitialize() { // overrides the method in class Mission and is called in mission memory phaseOfMission = Phase.INITIALIZE; msSetForMission = new ManagedSchedulableSet(); initialize(); } /** * Implementation of a cyclic executive. * Is invoked in a mission memory scope. */ void runExecute() // overrides the method in class Mission and is called in mission memory { // The following four lines of code: to meet the precondition in getSchedule. ManagedSchedulable[] msObjects = Mission.getMission().msSetForMission.managedSchObjects; PeriodicEventHandler[] pevs = new PeriodicEventHandler[Mission.getMission().msSetForMission.noOfRegistered]; for (int i = 0; i < pevs.length; i++) pevs[i] = (PeriodicEventHandler)msObjects[i]; CyclicSchedule schedule = getSchedule(pevs) ; /** * local reference to frames */ final Frame[] frames = schedule.getFrames(); /** * step is the minor cycle counter */ int step = 0; while (!missionTerminate) { PeriodicEventHandler[] handlers = frames[step].handlers; int n = handlers.length; for (int handlerIdx = 0; handlerIdx < n; handlerIdx++) { handlers[handlerIdx].privateMemory.enter(handlers[handlerIdx]); } // wait for frame.duration to expire waitForNextFrame(frames[step].duration); // index to next frame step = (step + 1) % frames.length; } } void runCleanup(MissionMemory missMem) //overrides the method in class Mission and is called in mission memory { vm.ClockInterruptHandler.instance.disable(); Mission.getMission().msSetForMission.terminateMSObjects(); cleanUp(); missMem.resetArea(); vm.ClockInterruptHandler.instance.enable(); } private void waitForNextFrame(RelativeTime duration) { next.add(duration, next); vm.RealtimeClock.delayNativeUntil(next); } // Used in feasible below /*static private int find(PeriodicEventHandler[] handlerList, PeriodicEventHandler h) { for (int i = handlerList.length - 1; i >= 0; i--) if (handlerList[i] == h) return i; return -1; }*/ // Used in JML annotations // boolean feasible(PeriodicEventHandler[] handlerList, CyclicSchedule schedule) { // // checks a cyclic schedule. It is assumed, conservatively, that every handler runs to its deadline. // // RelativeTime[] nextDeadline = new RelativeTime[handlerList.length]; // for (int h = 0; h < handlerList.length; h++) // nextDeadline[h] = new RelativeTime( // handlerList[h].release.getDeadline()); // // Frame[] frames = schedule.getFrames(); // // RelativeTime next = new RelativeTime(); // // for (int step = 0; step < frames.length; step++) { // PeriodicEventHandler[] handlers = frames[step].handlers; // PeriodicEventHandler hx; // int n = handlers.length; // RelativeTime startFrame = new RelativeTime(next); // // for (int handlerIdx = 0; handlerIdx < n; handlerIdx++) { // hx = handlers[handlerIdx]; // // check handler declared // int h = find(handlerList, hx); // if (h < 0) // return false; // // run handler hx // next.add(hx.release.getDeadline()); // // check against absolute deadline // if (next.compareTo(nextDeadline[h]) > 0) // return false; // nextDeadline[h].add(((PeriodicParameters) hx.release) // .getPeriod()); // } // // advance to next frame // if (next.compareTo(startFrame.add(frames[step].duration)) > 0) // return false; // next.add(frames[step].duration); // } // // the schedule was OK for handlers in the frames // // check no handler left behind. // for (int h = 0; h < handlerList.length; h++) // if (nextDeadline[h].compareTo(next) <= 0) // return false; // // return true; // } }