001 // PriorityScheduler.java, created by cata 002 // Copyright (C) 2001 Catalin Francu <cata@mit.edu> 003 // Licensed under the terms of the GNU GPL; see COPYING for details. 004 package javax.realtime; 005 006 import java.util.HashSet; 007 import java.util.LinkedList; 008 import java.util.Iterator; 009 010 /** Class which represents the required (by RTSJ) priority-based scheduler. 011 * The default instance is the required priority scheduler which does 012 * fixed priority, preemptive scheduling. 013 */ 014 public class PriorityScheduler extends Scheduler { 015 // Real-time thread priorities 016 /** The maximum priority value used by the implementation. */ 017 static final int MAX_PRIORITY = 38; 018 /** The minimum priority value used by the implementation. */ 019 static final int MIN_PRIORITY = 11; 020 static final int NORM_PRIORITY = 021 (MAX_PRIORITY - MIN_PRIORITY) / 3 + MIN_PRIORITY; 022 023 static HashSet allThreads = null; 024 static HashSet disabledThreads = null; 025 // The runtime constraints for the threads we're maintaining 026 static ThreadConstraints thread[] = null; 027 public static RelativeTime defaultQuanta = null; 028 static PeriodicParameters mainThreadParameters = null; 029 static PeriodicParameters noRTParameters = null; 030 031 // The first threadID that we can allocate 032 long nextThreadID = 0; 033 // The number of threads we are maintaining 034 int nThreads = 0; 035 036 // The number of missed deadlines and thenumber of times that the 037 // scheduler was invoked 038 public static long missed = 0; 039 public static long invocations = 0; 040 public static long runningTimeMicros = 0; 041 042 // The thread that chooseThread selected upon the previous invocation, 043 // and how long we've allowed that thread to run 044 long runningThread = 0; 045 RelativeTime runningTime = null; 046 static PriorityScheduler instance = null; 047 048 /** Constructor for the required scheduler. */ 049 protected PriorityScheduler() { 050 super(); 051 if (thread == null) { 052 thread = new ThreadConstraints[10]; 053 allThreads = new HashSet(); 054 disabledThreads = new HashSet(); 055 defaultQuanta = new RelativeTime(2, 0); 056 runningTime = new RelativeTime(0, 0); 057 mainThreadParameters = 058 new PeriodicParameters(null, new RelativeTime(5, 0), 059 new RelativeTime(1, 0), null, null, null); 060 noRTParameters = 061 new PeriodicParameters(null, new RelativeTime(50, 0), 062 new RelativeTime(1, 0), null, null, null); 063 } 064 } 065 066 /** Return a reference to an instance of <code>PriorityScheduler</code>. 067 * 068 * @return A reference to an instance of <code>PriorityScheduler</code>. 069 */ 070 public static PriorityScheduler instance() { 071 if (instance == null) 072 ImmortalMemory.instance().enter(new Runnable() { 073 public void run() { 074 instance = new PriorityScheduler(); 075 } 076 }); 077 return instance; 078 } 079 080 /** Inform the scheduler and cooperating facilities that the resource demands, 081 * as expressed in associated instances of <code>SchedulingParameters, 082 * ReleaseParameters, MemoryParameters</code> and <code>ProcessingGroupParameters</code>, 083 * of this instance of <code>Schedulable</code> will be considered in the 084 * feasibility analysis of the associated <code>Scheduler</code> until 085 * further notice. Whether the resulting system is feasible or not, the addition 086 * is completed. 087 * 088 * @param schedulable The instance of <code>Schedulable</code> for which the 089 * changes are proposed. 090 */ 091 protected void addToFeasibility(final Schedulable schedulable) { 092 allThreads.add(schedulable); 093 thread[nThreads] = new ThreadConstraints(); 094 thread[nThreads].threadID = schedulable.getUID(); 095 thread[nThreads].schedulable = schedulable; 096 thread[nThreads].beginPeriod = null; 097 nThreads++; 098 } 099 100 protected native void addThreadInC(Schedulable t, long threadID); 101 102 /** Trigger the execution of a schedulable object (like 103 * an instance of <code>AsyncEventHandler</code>). 104 * 105 * @param schedulable The <code>Schedulable</code> object to make active. 106 */ 107 public void fireSchedulable(Schedulable schedulable) { 108 schedulable.run(); 109 } 110 111 /** Gets the maximum priority available for a thread managed by this scheduler. 112 * 113 * @return The value of the maximum priority. 114 */ 115 public int getMaxPriority() { 116 return MAX_PRIORITY; 117 } 118 119 /** Gets the maximum priority of the given instance of 120 * <code>java.lang.Thread</code>. If the given thread is scheduled by the 121 * required <code>PriorityScheduler</code> the maximum priority of the 122 * <code>PriorityScheduler</code> is returned; otherwise 123 * <code>Thread.MAX_PRIORITY</code> is returned. 124 * 125 * @param thread An instance of <code>java.lang.Thread</code>. If null, 126 * the maximum priority of the required 127 * <code>PriorityScheduler</code> is returned. 128 * @return The maximum priority of the given instance of 129 * <code>java.lang.Thread</code>. 130 */ 131 public static int getMaxPriority(Thread thread) { 132 return (allThreads.contains(thread)) ? 133 MAX_PRIORITY : Thread.MAX_PRIORITY; 134 } 135 136 /** Gets the minimum priority available for a thread managed by this scheduler. 137 * 138 * @return The value of the minimum priority. 139 */ 140 public int getMinPriority() { 141 return MIN_PRIORITY; 142 } 143 144 /** Gets the minimum priority of the given instance of 145 * <code>java.lang.Thread</code>. If the given thread is scheduled by the 146 * required <code>PriorityScheduler</code> the minimum priority of the 147 * <code>PriorityScheduler</code> is returned; otherwise 148 * <code>Thread.MIN_PRIORITY</code> is returned. 149 * 150 * @return The value of the minimum priority of the given instance of 151 * <code>java.lang.Thread</code>. 152 */ 153 public static int getMinPriority(Thread thread) { 154 return (allThreads.contains(thread)) ? 155 MIN_PRIORITY : Thread.MIN_PRIORITY; 156 } 157 158 /** Gets the normal priority available for a thread managed by this scheduler. 159 * 160 * @return The value of the normal priority. 161 */ 162 public int getNormPriority() { 163 return NORM_PRIORITY; 164 } 165 166 /** Gets the normal priority of the given instance of 167 * <code>java.lang.Thread</code>. If the given thread is scheduled by the 168 * required <code>PriorityScheduler</code> the normal priority of the 169 * <code>PriorityScheduler</code> is returned; otherwise 170 * <code>Thread.NORM_PRIORITY</code> is returned. 171 */ 172 public static int getNormPriority(Thread thread) { 173 return (allThreads.contains(thread)) ? 174 NORM_PRIORITY : Thread.NORM_PRIORITY; 175 } 176 177 /** Gets the policy name of <code>this</code>. 178 * 179 * @return The policy name (Fixed Priority) as a string. 180 */ 181 public String getPolicyName() { 182 return "EDF"; 183 } 184 185 /** Determines the load on the system. If the load is less then 1, the 186 * system is feasible. If the load is greater than or equal to 1, the 187 * system is not feasible. 188 * 189 * @param releaseParams The list of the <code>ReleaseParameters</code> 190 * to be considered when determining the load. 191 * @return The load of the system. 192 */ 193 private float load(LinkedList releaseParams) { 194 float l = 0.0f; 195 for (Iterator it = releaseParams.iterator(); it.hasNext(); ) { 196 ReleaseParameters rp = (ReleaseParameters)it.next(); 197 if (rp instanceof PeriodicParameters) 198 l += ((PeriodicParameters)rp).getCost().time() / 199 ((PeriodicParameters)rp).getPeriod().time(); 200 else l+= ((AperiodicParameters)rp).getCost().time() / 201 ((AperiodicParameters)rp).getDeadline().time(); 202 } 203 204 return l; 205 } 206 207 /** Queries the system about the feasibility of the set of 208 * <code>Schedulable</code> objects with respect to their include in the 209 * feasibility set and the constraints expressed by their associated 210 * parameter objects. 211 * 212 * @return True if the system is able to satisfy the constraints expressed 213 * by the parameter object of all instances of <code>Schedulable</code> 214 * currently in the feasibility set. False if the system cannot 215 * satisfy those constraints. 216 */ 217 public boolean isFeasible() { 218 return isFeasible(null, null); 219 } 220 221 protected boolean isFeasible(Schedulable s, ReleaseParameters rp) { 222 LinkedList params = new LinkedList(); 223 int i = 0; 224 boolean found = false; 225 for (Iterator it = allThreads.iterator(); it.hasNext(); ) { 226 Object obj = it.next(); 227 if (obj instanceof Schedulable) { 228 Schedulable sch = (Schedulable)obj; 229 if (sch == s) { 230 params.add(new ReleaseParameters(rp)); 231 found = true; 232 } 233 else if (sch.getReleaseParameters() != null) { 234 params.add(new ReleaseParameters(sch.getReleaseParameters())); 235 } 236 } 237 } 238 if ((!found) && (s != null) && (rp != null)) params.add(new ReleaseParameters(rp)); 239 240 return (load(params) < 1.0); 241 } 242 243 /** Inform <code>this</code> and cooperating facilities that the 244 * <code>ReleaseParameters</code> of the ginve instance of <code>Schedulable</code> 245 * should <i>not</i> be considered in feasibility analysis until further notified. 246 * 247 * @param schedulable The instance of <code>Schedulable</code> whose 248 * <code>ReleaseParameters</code> are to be removed from the 249 * feasibility set. 250 * @return True, if the removal was ssuccessful. False, if the removal was 251 * unsuccessful. 252 */ 253 protected void removeFromFeasibility(Schedulable schedulable) { 254 allThreads.remove(schedulable); 255 256 int i = 0; 257 while ((thread[i] == null || thread[i].schedulable != schedulable) 258 && i < nThreads) 259 i++; 260 if (i < nThreads) { 261 thread[i] = null; // To ensure deallocation 262 thread[i] = thread[--nThreads]; 263 } 264 } 265 266 /** The method appears in many classe in the RTSJ and with various parameters. 267 * The parameters are either new scheduling characteristics for an instance 268 * <code>Schedulable</code> or an instance of <code>Schedulable</code>. The 269 * method first performs a feasibility analysis using the new scheduling 270 * characteristics of the given instance of <code>Schedulable</code>. If the 271 * resultingsystem is feasible the method replaces the current scheduling 272 * characteristics, of either <code>this</code> or the given instance of 273 * <code>Schedulable</code> as appropriate, with the new scheduling characteristics. 274 * 275 * @param schedulable The instance of <code>Schedulable</code> for which the 276 * changes are proposed 277 * @param release The proposed release parameters. 278 * @param memory The proposed memory parameters. 279 * @return True, if the resulting system is feasible and the changes are made. 280 * False, if the resulting system is not feasible and no changes are made. 281 */ 282 public boolean setIfFeasible(Schedulable schedulable, 283 ReleaseParameters release, 284 MemoryParameters memory) { 285 return setIfFeasible(schedulable, release, memory, schedulable.getProcessingGroupParameters()); 286 } 287 288 /** The method appears in many classe in the RTSJ and with various parameters. 289 * The parameters are either new scheduling characteristics for an instance 290 * <code>Schedulable</code> or an instance of <code>Schedulable</code>. The 291 * method first performs a feasibility analysis using the new scheduling 292 * characteristics of the given instance of <code>Schedulable</code>. If the 293 * resultingsystem is feasible the method replaces the current scheduling 294 * characteristics, of either <code>this</code> or the given instance of 295 * <code>Schedulable</code> as appropriate, with the new scheduling characteristics. 296 * 297 * @param schedulable The instance of <code>Schedulable</code> for which the 298 * changes are proposed 299 * @param release The proposed release parameters. 300 * @param memory The proposed memory parameters. 301 * @param group The proposed processing group parameters. 302 * @return True, if the resulting system is feasible and the changes are made. 303 * False, if the resulting system is not feasible and no changes are made. 304 */ 305 public boolean setIfFeasible(Schedulable schedulable, 306 ReleaseParameters release, 307 MemoryParameters memory, 308 ProcessingGroupParameters group) { 309 if (isFeasible(schedulable, release)) { 310 schedulable.setReleaseParameters(release); 311 schedulable.setMemoryParameters(memory); 312 schedulable.setProcessingGroupParameters(group); 313 return true; 314 } 315 else return false; 316 } 317 318 319 /** Implements EDF (Earliest Deadline First) Algorithm */ 320 protected long chooseThread(long micros) { 321 long microsBegin = RealtimeClock.getTimeInC(); 322 invocations++; 323 AbsoluteTime now = new AbsoluteTime(0, (int)micros*1000); 324 325 if (nThreads == 0) 326 return (runningThread = 0); 327 328 ReleaseParameters rp = null; 329 int earliest = -1; // The periodic thread returned by EDF 330 // If earliest = -1, we'll choose the sporadic thread with the 331 // earliest starting time 332 int earliestSporadic = -1; 333 for (int i = 0; i < nThreads; i++) 334 if (thread[i] != null) { // if this thread is still alive 335 // First, if this was the running thread, reduce its workLeft 336 if (runningThread == thread[i].threadID) 337 thread[i].workLeft = thread[i].workLeft.subtract(runningTime); 338 339 // Second, update the thread parameters 340 if (thread[i].threadID == 1) 341 rp = mainThreadParameters; 342 else if (thread[i].schedulable instanceof RealtimeThread) 343 rp = thread[i].schedulable.getReleaseParameters(); 344 345 // If the thread has no real time parameters, make it aperiodic 346 if (rp == null) 347 rp = noRTParameters; 348 // System.out.println(rp); 349 if (thread[i].beginPeriod == null) { 350 // This is the first time we're handling this thread. 351 // If the thread is sporadic, we'll set its endPeriod when we run 352 // it for the first time. 353 thread[i].beginPeriod = now; 354 thread[i].endPeriod = (rp instanceof PeriodicParameters) ? 355 thread[i].beginPeriod.add(((PeriodicParameters)rp).getPeriod()) : 356 new AbsoluteTime(AbsoluteTime.endOfDays); 357 thread[i].workLeft = rp.getCost(); 358 thread[i].deadline = thread[i].beginPeriod.add(rp.getDeadline()); 359 } 360 else if (now.compareTo(thread[i].endPeriod) >= 0) { 361 // This thread is passing into a new period 362 // (1) Check to see if the thread missed its deadline 363 if (thread[i].schedulable instanceof RealtimeThread && 364 thread[i].workLeft.compareTo(RelativeTime.ZERO) == 1) { 365 missed++; 366 // AsyncEventHandler h = rp.getDeadlineMissHandler(); 367 // if (h != null) h.run(); 368 } 369 // (2) Update the thread constraints 370 thread[i].beginPeriod.set(thread[i].endPeriod); 371 if (rp instanceof PeriodicParameters) 372 thread[i].beginPeriod.add(((PeriodicParameters)rp).getPeriod(), 373 thread[i].endPeriod); 374 else 375 thread[i].endPeriod.set(AbsoluteTime.endOfDays); 376 thread[i].workLeft.set(rp.getCost()); 377 thread[i].beginPeriod.add(rp.getDeadline(), thread[i].deadline); 378 } 379 // Third, use the thread for the EDF algorithm The thread must 380 // (1) not be disabled, (2) have some work left to do during 381 // this period, (3) have the earliest deadline among all threads 382 if (!disabledThreads.contains(new Long(thread[i].threadID))) 383 if (rp instanceof PeriodicParameters || 384 (rp instanceof SporadicParameters && 385 thread[i].workLeft.compareTo(rp.getCost()) == -1)) { 386 // This thread is either periodic, or it is sporadic AND we have 387 // started running it, so now we have to finish this period in time 388 if (thread[i].workLeft.compareTo(RelativeTime.ZERO) == 1 && 389 (earliest == -1 || 390 thread[i].deadline.compareTo(thread[earliest].deadline)==-1)) 391 earliest = i; 392 } 393 else if (rp instanceof SporadicParameters && 394 thread[i].workLeft.compareTo(rp.getCost()) == 0) { 395 // This thread is sporadic and we haven't started this period yet, 396 // So we'll remember it in case we have nothing urgent to do 397 if (earliestSporadic == -1 || 398 thread[i].beginPeriod. 399 compareTo(thread[earliestSporadic].beginPeriod) == -1) 400 earliestSporadic = i; 401 } 402 403 } 404 405 // If nothing urgent, run a sporadic thread 406 if (earliest == -1 && earliestSporadic != -1) { 407 earliest = earliestSporadic; 408 // We're activating a new period for this sporadic thread, so we have to 409 // set startPeriod and endPeriod 410 thread[earliest].beginPeriod.set(now); 411 thread[earliest].beginPeriod 412 .add(((SporadicParameters)thread[earliest].schedulable. 413 getReleaseParameters()).getMinimumInterarrival(), 414 thread[earliest].endPeriod); 415 } 416 417 // If the thread has enough work left to do, give it a full 418 // quanta. Otherwise, give it only the time it needs. 419 if (earliest != -1) { 420 runningThread = thread[earliest].threadID; 421 if (thread[earliest].workLeft.compareTo(defaultQuanta) == -1) 422 runningTime.set(thread[earliest].workLeft.getMilliseconds(), 423 thread[earliest].workLeft.getNanoseconds()); 424 else 425 runningTime.set(defaultQuanta.getMilliseconds(), 426 defaultQuanta.getNanoseconds()); 427 setQuanta(runningTime.getMilliseconds()*1000); 428 runningTimeMicros += RealtimeClock.getTimeInC() - microsBegin; 429 return runningThread; 430 } 431 432 // Nothing to do, remain idle 433 runningTimeMicros += RealtimeClock.getTimeInC() - microsBegin; 434 return runningThread = 0; 435 } 436 437 protected void disableThread(long threadID) { 438 disabledThreads.add(new Long(threadID)); 439 } 440 441 protected void enableThread(long threadID) { 442 disabledThreads.remove(new Long(threadID)); 443 } 444 445 public void waitForNextPeriod(RealtimeThread rt) { 446 for (int i = 0; i < nThreads; i++) 447 if (thread[i] != null && thread[i].schedulable == rt) 448 thread[i].workLeft.set(0,0); 449 } 450 451 public void addThread(RealtimeThread rt) { 452 } 453 454 public void addThread(long threadID) { 455 } 456 457 public void removeThread(RealtimeThread rt) { 458 } 459 460 public void removeThread(long threadID) { 461 } 462 463 public String toString() { 464 return ""; 465 } 466 }