/************************************************************************** * File name : ManagedMemory.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.MemoryArea; import javax.safetycritical.annotate.Level; import javax.safetycritical.annotate.SCJAllowed; import vm.Memory; /** * Managed memory is a scoped memory area that is managed by a mission. * * @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 ManagedMemory extends MemoryArea { static boolean flag = true; /** * statically allocated Exception prevents memory area reference mismatches. */ private static final IllegalArgumentException exception = new IllegalArgumentException(); private static class BackingStore extends MemoryArea { public BackingStore(Memory delegate) { super(delegate); } } /** * This method is called once in javax.safetycritical.Launcher * * @param size * The size of the backing store used by the SCJ application */ static void allocateBackingStore(int size) { MemoryArea.overAllBackingStore = new BackingStore(Memory.allocateInHeap(size)); } public static class ImmortalMemory extends ManagedMemory // HSO: not public { ImmortalMemory(int sizeOfArea) { super(sizeOfArea, sizeOfArea, MemoryArea.overAllBackingStore, "Imm"); } public static ImmortalMemory instance() { MemoryArea result = MemoryArea.getNamedMemoryArea("Imm"); if (result != null) { return (ImmortalMemory)result; } return null; } } /** * @param size is the number of free bytes in the memory area */ @IcecapCompileMe ManagedMemory(int size, int BackingStoreOfThisMemory, MemoryArea backingStoreProvider, String label) { super(size, BackingStoreOfThisMemory, backingStoreProvider, label); } /** * Makes this memory area the allocation context for the execution of the * <code>run()</code> method of the instance of <code>Runnable</code> given * in the constructor. <br> * During this period of execution, this memory area becomes the default * allocation context until another allocation context is selected or the * <code>Runnable</code>'s <code>run</code> method exits. * <p> * This method is like the <code>executeInArea</code> method, but extended * with cleanup and pointer reset. * * @throws IllegalArgumentException * if the caller is a schedulable object and <code>logic</code> * is null. * * @param logic * is the <code>Runnable</code> object whose <code>run()</code> * method shall be executed. */ @SCJAllowed(Level.INFRASTRUCTURE) @IcecapCompileMe void enter(Runnable logic) throws IllegalArgumentException { if (logic == null || !( logic instanceof ManagedSchedulable)) throw new IllegalArgumentException(); ManagedSchedulable ms = (ManagedSchedulable) logic; if (ms instanceof ManagedEventHandler) { ManagedEventHandler mevh = (ManagedEventHandler) ms; Memory mem = Memory.switchToArea(mevh.privateMemory.delegate); logic.run(); Memory.switchToArea(mem); mevh.privateMemory.delegate.reset(0); } else if (ms instanceof ManagedThread) { devices.Console.println("ManagedMemory.enter: managedThred should work"); ManagedThread mth = (ManagedThread) ms; Memory mem = Memory.switchToArea(mth.privateMemory.delegate); logic.run(); Memory.switchToArea(mem); mth.privateMemory.delegate.reset(0); } else { // (ms is instanceof ManagedLongEventHandler) devices.Console.println("ManagedMemory.enter: UPS ManagedLongEventHandler not implemented"); //ManagedLongEventHandler mevh = (ManagedLongEventHandler) ms; // finish this ... } } /** * Executes <code>logic</code> in this memory area, with no cleanup and no * pointer reset at the end. * * @param logic * The Runnable object whose <code>run()</code> method shall be executed. * * @throws IllegalArgumentException * If <code>logic</code> is null. */ @SCJAllowed void executeInArea(Runnable logic) throws IllegalArgumentException { if (logic == null) throw new IllegalArgumentException("executeInArea: logic is null"); if (flag) { flag = false; Memory currentMem = vm.Memory.getHeapArea(); Memory.switchToArea(this.delegate); logic.run(); Memory.switchToArea(currentMem); } else { ScjProcess currProcess = getCurrentProcess(); if (currProcess == null) throw new IllegalArgumentException("executeInArea: process is null"); Memory mem = Memory.switchToArea(this.delegate); logic.run(); Memory.switchToArea(mem); } } static final ManagedMemory getOuterMemory(MemoryArea mem) { if (mem instanceof InnerPrivateMemory) return ((InnerPrivateMemory) mem).prev; else if (mem instanceof PrivateMemory) return Mission.getMission().getSequencer().getMissionMemory(); else if (mem instanceof MissionMemory) { // return nearest outermost memory MissionSequencer<?> missSeq = Mission.getMission().getSequencer(); if (missSeq.outerSeq == null) return ImmortalMemory.instance(); else return missSeq.getOuterSeq().getMissionMemory(); } else return null; } /** * Invoke the run method of logic with a fresh private memory area that is * immediately nested within the current <code>ManagedMemory</code> area, * sized to provide <code>size</code> bytes of free memory as the current * allocation area. * * @param size * is the number of free bytes within the inner-nested private * memory. * * @param logic * provides the run method that is to be executed within the * inner-nested private memory area. */ // /*@ // public static normal_behavior // requires logic != null; // ensures true; // not finished // also // public static exceptional_behaviour // requires logic == null; // signals (IllegalStateException) true; // // @*/ @SCJAllowed public static void enterPrivateMemory(int size, Runnable logic) throws IllegalStateException { /** * prevMemory is the memory area at entry; prevFree is the free pointer * before allocation of the private memory. If the current free has * changed after running the logic, there has been allocation in the * outer area, and the private memory cannot be released. */ if (logic == null) throw exception; vm.ClockInterruptHandler.instance.disable(); // atomic operation ?? ManagedSchedulable ms = getCurrentProcess().getTarget(); //devices.Console.println("enterPrivateMemory by " + getCurrentProcess().index); runEnterPrivateMemory(ms, size, logic); vm.ClockInterruptHandler.instance.enable(); } private static void runEnterPrivateMemory(ManagedSchedulable ms, int size, Runnable logic) { ManagedMemory prev = getMemory (ms); long prevFree = prev.memoryConsumed(); InnerPrivateMemory inner = new InnerPrivateMemory( size, prev.getRemainingBackingstoreSize(), prev, "InnerPrvMem"); inner.prev = prev; Memory mem = Memory.switchToArea(inner.delegate); logic.run(); Memory.switchToArea(mem); if (prev.memoryConsumed() != prevFree) prev.resetArea(prevFree); inner.removeArea(); } private static ManagedMemory getMemory (ManagedSchedulable ms) { if (ms instanceof ManagedEventHandler) { ManagedEventHandler mevh = (ManagedEventHandler) ms; return mevh.privateMemory; } else if(ms instanceof ManagedThread) { ManagedThread mth = (ManagedThread) ms; return mth.privateMemory; } else { // (ms is instanceof ManagedLongEventHandler) ManagedLongEventHandler mlevh = (ManagedLongEventHandler) ms; return mlevh.privateMemory; } } @SCJAllowed public static void executeInAreaOf(Object obj, Runnable logic) { if (obj == null || logic == null) throw exception; vm.ClockInterruptHandler.instance.disable(); // atomic operation ?? ManagedMemory memAreaOfObject = (ManagedMemory)MemoryArea.getMemoryArea(obj); //devices.Console.println("executeInAreaOf: memAreaOfObject: " + memAreaOfObject); Memory mem = Memory.switchToArea(memAreaOfObject.getDelegate()); logic.run(); Memory.switchToArea(mem); vm.ClockInterruptHandler.instance.enable(); // atomic operation ?? } @SCJAllowed public static void executeInOuterArea(Runnable logic) { if (logic == null) throw exception; vm.ClockInterruptHandler.instance.disable(); // atomic operation ?? MemoryArea currentMem = MemoryArea.getCurrentMemoryArea(); //devices.Console.println("executeInOuterArea: currentMem: " + currentMem); if (currentMem instanceof ManagedMemory.ImmortalMemory) { devices.Console.println("executeInOuterArea: already in ImmortalMemory"); vm.ClockInterruptHandler.instance.enable(); // atomic operation ?? throw new IllegalStateException("executeInOuterArea: already in ImmortalMemory"); } ManagedMemory outerMemory = getOuterMemory(currentMem); Memory mem = Memory.switchToArea(outerMemory.getDelegate()); logic.run(); Memory.switchToArea(mem); vm.ClockInterruptHandler.instance.enable(); // atomic operation ?? } /** * * @return the size of the remaining memory available to the current * ManagedMemory area. * @scjComment the same as memoryRemaining() in MemoryArea? */ @SCJAllowed public long getRemainingBackingStore() { return memoryRemaining(); } /** * Resetting the number of available bytes. The parameter * <code>newFree</code> is typically acquired by a previous call of * <code>memoryConsumed()</code>. * * @param newFree * the number. */ private void resetArea(long newFree) { this.delegate.reset((int) newFree); } void resetArea() { this.delegate.reset(0); } void removeArea() { this.removeMemArea(); } void resizeArea(long newSize) { this.resizeMemArea(newSize); } static ScjProcess getCurrentProcess() { if (Launcher.level != 0) return PriorityScheduler.instance().getCurrentProcess(); else return CyclicScheduler.instance().getCurrentProcess(); } protected Memory getDelegate() { return delegate; } // For JML annotations /*@ spec_public @*/ static MemoryArea getCurretAllocationArea() { return null; } // For JML annotations /*@ spec_public @*/ MemoryArea getTopMostArea() { return null; } }