001 // ScopedMemory.java, created by wbeebee 002 // Copyright (C) 2001 Wes Beebee <wbeebee@mit.edu> 003 // Licensed under the terms of the GNU GPL; see COPYING for details. 004 package javax.realtime; 005 006 /** 007 * @author Wes Beebee <<a href="mailto:wbeebee@mit.edu">wbeebee@mit.edu</a>> 008 */ 009 010 /** <code>ScopedMemory</code> is the abstract base class of all classes dealing 011 * with representations of memoryspaces with a limited lifetime. The 012 * <code>ScopedMemory</code> area is valid as long as there are real-time 013 * threads with access to it. A reference is created for each accessor when 014 * either a real-time thread is created with the <code>ScopedMemory</code> 015 * object as its memory area, or a real-time thread runs the <code>enter()</code> 016 * method for the memory area. When the last reference to the object is removed, 017 * by exiting the thread or exiting the <code>enter()</code> method, finalizers 018 * are run for all objects in the memory area, and the area is emptied. 019 * <p> 020 * A <code>ScopedMemory</code> area is a connection to a particular region of 021 * memory and reflects the current status of it. 022 * <p> 023 * When a <code>ScopedMemory</code> area is instantiated, the object itself is allocated 024 * from the current memory allocation scheme in use, but the memory space that object 025 * represents is not. Memory is allocated, as always, using an <code>RTJ_malloc</code> call. 026 * <p> 027 * The <code>enter()</code> method of <code>ScopedMemory</code> is the mechanism used 028 * to activate a new memory scope. Entry into the scope is done by calling the method 029 * <code>enter(Runnable r)</code>, where <code>r</code> is a <code>Runnable</code> 030 * object whose <code>run()</code> method represents the entry point to the code that 031 * will run in the new scope. Exit from the scope occurs when the <code>r.run()</code> 032 * completes. Allocations of objects within <code>r.run()</code> are done with the 033 * <code>ScopedMemory</code> area. When <code>r.run()</code> is complete, the scoped 034 * memory area is no longer active. Its reference count will be decremented and if it 035 * is zero all of objects in the memory are finalized and collected. 036 * <p> 037 * Objects allocated from a <code>ScopedMemory</code> area have a unique lifetime. They 038 * cease to exist on exiting <code>enter()</code> method or upon exiting the last 039 * real-time thread referencing the area, regardless of any references that may exist 040 * to the object. Thus, to maintain the safety of Java and avoid dangling references, 041 * a very restrictive set of rules apply to <code>ScopedMemory</code> area objects: 042 * <ul> 043 * <li>1. A reference to an object in <code>ScopedMemory</code> can never be stored in 044 * an Object allocated in the Java heap. 045 * <li>2. A reference to an object in <code>ScopedMemory</code> can never be stored in 046 * an Object allocated in <code>ImmortalMemory</code>. 047 * <li>3. A reference to an object in <code>ScopedMemory</code> can only be stored in 048 * Objects allocated in the same <code>ScopedMemory</code> area, or into a 049 * -- more inner -- <code>ScopedMemory</code> area nested by the use of its 050 * <code>enter()</code> method. 051 * <li>4. References to immortal of heap objects <i>may</i> be stored into an object 052 * allocated in a <code>ScopedMemory</code> area. 053 * </ul> 054 */ 055 public abstract class ScopedMemory extends MemoryArea { 056 protected Object portal; 057 private int count = 0; 058 059 /** <code>logic.run()</code> is executed when <code>enter()</code> is called. */ 060 protected Runnable logic; 061 062 /** Create a new <code>ScopedMemory</code> with the given parameters. 063 * 064 * @param size The size of the new <code>ScopedMemory</code> area in bytes. 065 * If size is less than or equal to zero nothing happens. 066 */ 067 public ScopedMemory(long size) { 068 super(size); 069 portal = null; 070 scoped = true; 071 } 072 073 /** Create a new <code>ScopedMemory</code> with the given parameters. 074 * 075 * @param size The size of the new <code>ScopedMemory</code> area in bytes. 076 * If size is less than or equal to zero nothing happens. 077 * @param r The logic which will use the memory represented by <code>this</code> 078 * as its initial memory area. 079 */ 080 public ScopedMemory(long size, Runnable r) { 081 this(size); 082 logic = r; 083 } 084 085 /** Create a new <code>ScopedMemory</code> with the given parameters. 086 * 087 * @param size The size of the new <code>ScopedMemory</code> area estimated 088 * by an instance of <code>SizeEstimator</code>. 089 */ 090 public ScopedMemory(SizeEstimator size) { 091 this(size.getEstimate()); 092 } 093 094 /** Create a new <code>ScopedMemory</code> with the given parameters. 095 * 096 * @param size The size of the new <code>ScopedMemory</code> area estimated 097 * by an instance of <code>SizeEstimator</code>. 098 * @param r The logic which will use the memory represented by <code>this</code> 099 * as its initial memory area. 100 */ 101 public ScopedMemory(SizeEstimator size, Runnable r) { 102 this(size); 103 logic = r; 104 } 105 106 public ScopedMemory(long minimum, long maximum) { 107 super(minimum, maximum); 108 portal = null; 109 scoped = true; 110 } 111 112 /** Associate this <code>ScopedMemory</code> area to the current realtime 113 * thread for the duration of the execution of the <code>run()</code> method 114 * of the current instance of <code>Schedulable</code> or the <code>run()</code> 115 * method of the instance of <code>Schedulable</code> fiven in the constructor. 116 * During this bound period of execution, all objects are allocated from the 117 * <code>ScopedMemory</code> area until another one takes effect, or the 118 * <code>enter()</code> method is exited. A runtime exception is thrown if this 119 * method is called from a thread other than a <code>RealtimeThread</code> or 120 * <code>NoHeapRealtimeThread</code>. 121 */ 122 public void enter() { 123 // Will NEVER implement single parent rule. 124 super.enter(); 125 } 126 127 /** Associate this <code>ScopedMemory</code> area to the current realtime 128 * thread for the duration of the execution of the <code>run()</code> method 129 * of the current instance of <code>Schedulable</code> or the <code>run()</code> 130 * method of the instance of <code>Schedulable</code> fiven in the constructor. 131 * During this bound period of execution, all objects are allocated from the 132 * <code>ScopedMemory</code> area until another one takes effect, or the 133 * <code>enter()</code> method is exited. A runtime exception is thrown if this 134 * method is called from a thread other than a <code>RealtimeThread</code> or 135 * <code>NoHeapRealtimeThread</code>. 136 * 137 * @param logic The runnable object which contains the code to execute. 138 */ 139 public void enter(Runnable logic) { 140 // Will NEVER implement single parent rule. 141 super.enter(logic); 142 } 143 144 /** Get the maximum size this memory area can attain. If this is a fixed size 145 * memory area, the returned value will be equal to the initial size. 146 * 147 * @return The maximum size attainable. 148 */ 149 public long getMaximumSize() { 150 return size; 151 } 152 153 /** Return a reference to the portal object in this instance of <code>ScopedMemory</code>. 154 * 155 * @return A reference to the portal object or null if there is no portal object. 156 */ 157 public Object getPortal() { 158 return portal; 159 } 160 161 /** Returns the reference count of this <code>ScopedMemory</code>. The reference 162 * count is an indication of the number of threads that may have access to this scope. 163 * 164 * @return The reference count of this <code>ScopedMemory</code>. 165 */ 166 public int getReferenceCount() { 167 return count; 168 } 169 170 /** Wait until the reference count of this <code>ScopedMemory</code> goes down to zero. 171 * 172 * @throws java.lang.InterruptedException If another thread interrupts this thread 173 * while it is waiting. 174 */ 175 public void join() throws InterruptedException { 176 // TODO 177 } 178 179 /** Wait at most until the time designated by the <code>time</code> parameter for the 180 * reference count of this <code>ScopedMemory</code> to go down to zero. 181 * 182 * @param time If this time is an absolute time, the wait is bounded by that point 183 * in time. If the time is a relative time (or a member of the 184 * <code>RationalTime</code> subclass of <code>RelativeTime</code>) the 185 * wait is bounded by the specified interval from some time between the 186 * time <code>join<code> is called and the time it starts waiting for 187 * the reference count to reach zero. 188 * @throws java.lang.InterruptedException If another thread interrupts this thread 189 * while it is waiting. 190 */ 191 public void join(HighResolutionTime time) 192 throws InterruptedException { 193 // TODO 194 } 195 196 /** Combine <code>join()</code> and <code>enter()</code> such that no <code>enter()</code> 197 * from another thread can intervene between the two method invocations. The resulting 198 * method will wait for the reference count on this <code>ScopedMemory</code> to reach 199 * zero, then enter the <code>ScopedMemory</code> and execute the <code>run()</code> 200 * method from <code>logic</code> passed in the constructor. if no <code>Runnable</code> 201 * was passed, the maethod returns immediately. 202 * 203 * @throws java.lang.InterruptedException If another thread interrupts this thread while 204 * it is waiting. 205 */ 206 public void joinAndEnter() throws InterruptedException { 207 joinAndEnter(this.logic); 208 } 209 210 /** Combine <code>join()</code> and <code>enter()</code> such that no <code>enter()</code> 211 * from another thread can intervene between the two method invocations. The resulting 212 * method will wait for the reference count on this <code>ScopedMemory</code> to reach 213 * zero, then enter the <code>ScopedMemory</code> and execute the <code>run()</code> 214 * method from <code>logic</code> passed in the constructor. if no <code>Runnable</code> 215 * was passed, the maethod returns immediately. 216 * 217 * @param time The time that bounds the wait. 218 * @throws java.lang.InterruptedException If another thread interrupts this thread while 219 * it is waiting. 220 */ 221 public void joinAndEnter(HighResolutionTime time) 222 throws InterruptedException { 223 joinAndEnter(this.logic, time); 224 } 225 226 /** Combine <code>join()</code> and <code>enter()</code> such that no <code>enter()</code> 227 * from another thread can intervene between the two method invocations. The resulting 228 * method will wait for the reference count on this <code>ScopedMemory</code> to reach 229 * zero, then enter the <code>ScopedMemory</code> and execute the <code>run()</code> 230 * method from <code>logic</code> passed in the constructor. if no <code>Runnable</code> 231 * was passed, the maethod returns immediately. 232 * 233 * @param logic The <code>java.lang.Runnable</code> object which contains the code to execute. 234 * @throws java.lang.InterruptedException If another thread interrupts this thread while 235 * it is waiting. 236 */ 237 public void joinAndEnter(Runnable logic) throws InterruptedException { 238 // TODO 239 } 240 241 /** Combine <code>join()</code> and <code>enter()</code> such that no <code>enter()</code> 242 * from another thread can intervene between the two method invocations. The resulting 243 * method will wait for the reference count on this <code>ScopedMemory</code> to reach 244 * zero, then enter the <code>ScopedMemory</code> and execute the <code>run()</code> 245 * method from <code>logic</code> passed in the constructor. if no <code>Runnable</code> 246 * was passed, the method returns immediately. 247 * 248 * @param logic The <code>java.lang.Runnable</code> object which contains the code to execute. 249 * @param time The time that bounds the wait. 250 * @throws java.lang.InterruptedException If another thread interrupts this thread while 251 * it is waiting. 252 */ 253 public void joinAndEnter(Runnable logic, HighResolutionTime time) 254 throws InterruptedException { 255 // TODO 256 } 257 258 /** Set the argument to the portal object in the memory area represented by this instance 259 * of <code>ScopedMemory</code>. 260 * 261 * @param object The object which will become the portal for <code>this</code>. If null 262 * the previous portal object remains the portal object for <code>this</code> 263 * or if there was no previous portal object then there is still no 264 * portal object for <code>this</code>. 265 */ 266 public void setPortal(Object object) { 267 if (this.equals(MemoryArea.getMemoryArea(object))) portal = object; 268 } 269 270 /** Returns a user-friendly representation of this <code>ScopedMemory</code>. 271 * 272 * @return The string representation. 273 */ 274 public String toString() { 275 return "ScopedMemory: " + super.toString(); 276 } 277 278 /** Get the MemoryArea which contains this ScopedMemory for 279 * the current RealtimeThread. 280 */ 281 public MemoryArea getOuterScope() { 282 return RealtimeThread.currentRealtimeThread().outerScope(this); 283 } 284 285 /** Check to see if this ScopedMemory can have access to 286 * the given object. 287 */ 288 public void checkAccess(Object obj) { 289 // Stats.addCheck(); 290 if (obj != null) { 291 MemoryArea target = getMemoryArea(obj); 292 if ((this != target) && target.scoped && 293 (!RealtimeThread.currentRealtimeThread() 294 .checkAccess(this, target))) { 295 throwIllegalAssignmentError(obj, target); 296 } 297 } 298 } 299 300 /** Check to see if a newInstance can go through 301 */ 302 public void checkNewInstance(MemoryArea mem) { 303 if ((this != mem) && mem.scoped && 304 (!RealtimeThread.currentRealtimeThread() 305 .checkAccess(this, mem))) { 306 throw new IllegalAssignmentError("Illegal assignment during new instance!"); 307 } 308 } 309 310 /** Cannot call this on a ScopedMemory (doesn't cleanup MemBlocks 311 * appropriately). Should never need to, since that'll cause 312 * an access violation according to the spec. 313 */ 314 protected void setupMemBlock(RealtimeThread rt) 315 throws IllegalAccessException { 316 throw new IllegalAccessException(); 317 } 318 }