// ************************************************************************ // $Id: PrivateScopedMemory.java 561 2005-07-11 20:09:17Z mdeters $ // ************************************************************************ // // jRate // // Copyright (C) 2001-2005 by Angelo Corsaro. // // All Rights Reserved. // // Permission to use, copy, modify, and distribute this software and // its documentation for any purpose is hereby granted without fee, // provided that the above copyright notice appear in all copies and // that both that copyright notice and this permission notice appear // in supporting documentation. I don't make any representations // about the suitability of this software for any purpose. It is // provided "as is" without express or implied warranty. // // // ************************************************************************* // // ************************************************************************* package javax.realtime; /** * The class PrivateScopedMemory refines the * ScopedMemory by restricting the number of active * thread within a memory to one. * * @author Angelo Corsaro * @version 1.0 */ public abstract class PrivateScopedMemory extends ScopedMemory { protected RealtimeThread owner; /** * Creates a new PrivateScopedMemory instance. * * @param size The size of MemoryArea to allocate, in * bytes. If size is less than or equal to zero an * {@link IllegalArgumentException} is thrown. */ public PrivateScopedMemory(long size) { this(size, null); } /** * Creates a new PrivateScopedMemory instance. * * @param size The size of MemoryArea to allocate, in * bytes. If size is less than or equal to zero an * {@link IllegalArgumentException} is thrown. * @param logic -The java.lang.Runnable whose run() method is * invoked when any of the variations of enter() which do not take * a java.lang.Runnable is called. */ public PrivateScopedMemory(long size, Runnable logic) { super(size, logic); } /** * Creates a new PrivateScopedMemory instance. * * @param size A {@link SizeEstimator} object which indicates the * amount of memory required by this MemoryArea. */ public PrivateScopedMemory(SizeEstimator size) { this(size.getEstimate(), null); } /** * Creates a new PrivateScopedMemory instance. * * @param size The size of MemoryArea to * allocate, in bytes. * @param logic The run() method of this object will be called * whenever enter() called. */ public PrivateScopedMemory(SizeEstimator size, Runnable logic) { this(size.getEstimate(), logic); } /** * Wait until the reference count of this * PrivateScopedMemory goes down to zero. * * @exception InterruptedException If another thread interrupts * this thread while it is waiting. */ public void join() throws InterruptedException { if (this.getReferenceCount() == 0) return; synchronized (this.joinSynchronizer) { this.joinSynchronizer.wait(); } } /** * Wait at most until the time designated by the time * parameter for the reference count of this * PrivateScopedMemory to go down to zero. * * @param time If this time is an absolute time, the wait is * bounded by that point in time. If the time is a relative time * (or a member of the RationalTime subclass of * RelativeTime the wait is bounded by a the * specified interval from some time between the time * join is called and the time it starts waiting for * the reference count to reach zero. * @exception InterruptedException if another thread interrupts * this thread while it is waiting. */ public void join(HighResolutionTime time) throws InterruptedException { if (this.getReferenceCount() == 0) return; synchronized (this.joinSynchronizer) { this.joinSynchronizer.wait(time.getMilliseconds(), time.getNanoseconds()); } } /** * Combine join();enter(); such that no * enter from another thread can intervene between * the two method invocations. The resulting method will wait for * the reference count on this PrivateScopedMemory to reach * zero, then enter the PrivateScopedMemory and execute the * run method from logic passed in the * constructor. If no Runnable was passed, the method returns * immediately. * * @exception InterruptedException If another thread interrupts * this thread while it is waiting. * @exception ScopedCycleException If entering this * PrivateScopedMemory would violate the single parent rule. */ public void joinAndEnter() throws InterruptedException, ScopedCycleException { if (this.logic == null) throw new IllegalArgumentException("No Runnable associated with this Memory Area"); RealtimeThread currentThread = RealtimeThread.currentRealtimeThread(); synchronized (this.joinSynchronizer) { if (this.getReferenceCount() != 0) { this.joinSynchronizer.wait(); this.setOwner(); if (currentThread.pushMemoryArea(this) == false) throw new ScopedCycleException("Entering this memory area would create a cycle!"); } else if (currentThread.pushMemoryArea(this) == false) throw new ScopedCycleException("Entering this memory area would create a cycle!"); } try { // Run the logic guardedRun(this.logic); } finally { // Pop this memory area on the current real-time thread stack synchronized (this.joinSynchronizer) { currentThread.popMemoryArea(); currentThread = null; this.resetOwner(); if (this.getReferenceCount() == 0) this.joinSynchronizer.notify(); } } } /** * Combine join(time);enter(); such that no * enter from another thread can intervene between * the two method invocations. The resulting method will wait for * the reference count on this PrivateScopedMemory to reach * zero, or for the current time to reach the designated time, * then enter the PrivateScopedMemory and execute the * run method from Runnable object * passed at constructin time. If no Runnable was * passed then this method returns immediately. * * @param time The time that bounds the wait. * @exception InterruptedException if another thread interrupts * this thread while it is waiting. * @exception ScopedCycleException If entering this * PrivateScopedMemory would violate the single parent rule. */ public void joinAndEnter(HighResolutionTime time) throws InterruptedException, ScopedCycleException { if (this.logic == null) throw new IllegalArgumentException("No Runnable associated with this Memory Area"); RealtimeThread currentThread = RealtimeThread.currentRealtimeThread(); synchronized (this.joinSynchronizer) { if (this.getReferenceCount() != 0) { this.joinSynchronizer.wait(time.getMilliseconds(), time.getNanoseconds()); this.setOwner(); if (currentThread.pushMemoryArea(this) == false) throw new ScopedCycleException("Entering this memory area would create a cycle!"); } else if (currentThread.pushMemoryArea(this) == false) throw new ScopedCycleException("Entering this memory area would create a cycle!"); } try { // Run the logic guardedRun(this.logic); } finally { // Pop this memory area on the current real-time thread stack synchronized (this.joinSynchronizer) { currentThread.popMemoryArea(); currentThread = null; this.resetOwner(); if (this.getReferenceCount() == 0) this.joinSynchronizer.notify(); } } } /** * Combine join();enter(logic); such that no * enter from another thread can intervene between * the two method invocations. The resulting method will wait for * the reference count on this PrivateScopedMemory to reach * zero, then enter the PrivateScopedMemory and execute the * run method from logic * * @param logic The {@link Runnable} object which contains the * code to execute. * @exception InterruptedException If another thread interrupts * this thread while it is waiting. * @exception ScopedCycleException If entering this * PrivateScopedMemory would violate the single parent rule. */ public void joinAndEnter(Runnable logic) throws InterruptedException, ScopedCycleException { if (logic == null) throw new IllegalArgumentException("No Runnable associated with this Memory Area"); RealtimeThread currentThread = RealtimeThread.currentRealtimeThread(); synchronized (this.joinSynchronizer) { if (this.getReferenceCount() != 0) { this.joinSynchronizer.wait(); this.setOwner(); if (currentThread.pushMemoryArea(this) == false) throw new ScopedCycleException("Entering this memory area would create a cycle!"); } else if (currentThread.pushMemoryArea(this) == false) throw new ScopedCycleException("Entering this memory area would create a cycle!"); } try { // Run the logic guardedRun(logic); } finally { // Pop this memory area on the current real-time thread stack synchronized (this.joinSynchronizer) { currentThread.popMemoryArea(); currentThread = null; this.resetOwner(); if (this.getReferenceCount() == 0) this.joinSynchronizer.notify(); } } } /** * Combine join(time);enter(logic); such that no * enter from another thread can intervene between * the two method invocations. The resulting method will wait for * the reference count on this PrivateScopedMemory to reach * zero, or for the current time to reach the designated time, * then enter the PrivateScopedMemory and execute the * run method from logic. * * @param logic The {@link Runnable} object which contains the * code to execute. * @param time The time that bounds the wait. * @exception InterruptedException if another thread interrupts * this thread while it is waiting. * @exception ScopedCycleException If entering this * PrivateScopedMemory would violate the single parent rule. */ public void joinAndEnter(Runnable logic, HighResolutionTime time) throws InterruptedException, ScopedCycleException { if (logic == null) throw new IllegalArgumentException("No Runnable associated with this Memory Area"); RealtimeThread currentThread = RealtimeThread.currentRealtimeThread(); synchronized (this.joinSynchronizer) { if (this.getReferenceCount() != 0) { this.joinSynchronizer.wait(time.getMilliseconds(), time.getNanoseconds()); this.setOwner(); if (currentThread.pushMemoryArea(this) == false) throw new ScopedCycleException("Entering this memory area would create a cycle!"); } else if (currentThread.pushMemoryArea(this) == false) throw new ScopedCycleException("Entering this memory area would create a cycle!"); } try { // Run the logic guardedRun(logic); } finally { // Pop this memory area on the current real-time thread stack synchronized (this.joinSynchronizer) { currentThread.popMemoryArea(); currentThread = null; this.resetOwner(); if (this.getReferenceCount() == 0) this.joinSynchronizer.notify(); } } } /** * Returns a user-friendly representation of this * PrivateScopedMemory. * @return The string representation */ public String toString() { return super.toString(); } /** * Associate this memory area to the current real-time thread for * the duration of the execution of the run() method * of the given {@link java.lang.Runnable}. During this bound * period of execution, all objects are allocated from the memory * area until another one takes effect, or the * enter() method is exited. A runtime exception is * thrown if this method is called from thread other than a * RealtimeThread or * NoHeapRealtimeThread. * * @param logic The Runnable object whose run() method should be * invoked. * @exception ScopedCycleException If entering this PrivateScopedMemory * would violate the single parent rule. */ public void enter(Runnable logic) throws ScopedCycleException { RealtimeThread currentThread = RealtimeThread.currentRealtimeThread(); if (logic == null) throw new IllegalArgumentException("No Runnable associated with this Memory Area"); synchronized (this.joinSynchronizer) { // Push this memory area on the current real-time thread stack this.setOwner(); if (currentThread.pushMemoryArea(this) == false) throw new ScopedCycleException("Entering this memory area would create a cycle!"); } try { // Run the logic guardedRun(logic); } finally { // Pop this memory area on the current real-time thread stack synchronized (joinSynchronizer) { currentThread.popMemoryArea(); currentThread = null; this.resetOwner(); if (this.getReferenceCount() == 0) joinSynchronizer.notify(); } } } protected synchronized void setOwner() { RealtimeThread currentThread = RealtimeThread.currentRealtimeThread(); if (this.owner == null) this.owner = currentThread; else if (this.owner != currentThread) throw new AccessViolationError("Trying to enter a non-owned PrivateScopedMemory"); } protected synchronized void resetOwner() { this.owner = null; } }