001    // Scheduler.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    
005    package javax.realtime;
006    import java.util.HashSet;
007    
008    /** An instance of <code>Scheduler</code> manages the execution of 
009     *  schedulable objects and may implement a feasibility algorithm. The
010     *  feasibility algorithm may determine if the known set of schedulable
011     *  objects, given their particular exection ordering (or priority
012     *  assignment), is a feasible schedule. Subclasses of <code>Scheduler</code>
013     *  are used for alternative scheduling policies and should define an
014     *  <code>instance()</code> class method to return the default
015     *  instance of the subclass. The name of the subclass should be
016     *  descriptive of the policy, allowing applications to deduce the
017     *  policy available for the scheduler obtained via
018     *  <code>getDefaultScheduler()</code> (e.g., <code>EDFScheduler</code>).
019     */
020    public abstract class Scheduler {
021        protected static Scheduler defaultScheduler = null;
022        private static VTMemory vt = null;
023        
024        /** Create an instance of <code>Scheduler</code>. */
025        protected Scheduler() {
026            addToRootSet();
027            if (vt == null) {
028                vt = new VTMemory();
029            }
030        }
031    
032        /** Inform the scheduler and cooperating facilities that the resource
033         *  demands (as expressed in the associated instances of
034         *  <code>SchedulingParameters, ReleaseParameters, MemoryParameters</code>
035         *  and <code>ProcessingGroupParameters</code>) of this instance of
036         *  <code>Schedulable</code> will be considered in the feasibility analysis
037         *  of the associated <code>Scheduler</code> until further notice. Whether
038         *  the resulting system is feasible or not, the addition is completed.
039         *
040         *  @param schedulable A reference to the given instance of <code>Schedulable</code>.
041         *  @return True, if the addition was successful. False, if not.
042         */
043        protected abstract void addToFeasibility(Schedulable schedulable);
044    
045        /** Trigger the execution of a schedulable object (like an
046         *  <code>AsyncEventHandler</code>.
047         *
048         *  @param schedulable The Schedulable object to make active.
049         */
050        public abstract void fireSchedulable(Schedulable schedulable);
051    
052        /** Gets a reference to the default scheduler.
053         *  In the RTJ spec, this is the PriorityScheduler, but we'll set it to whatever
054         *  we wish to focus on at the moment, since this is a hot research target.
055         *
056         *  Currently, there's a PriorityScheduler (for compliance), and a 
057         *  RoundRobinScheduler (for debugging).  Conceivably, one can put Schedulers 
058         *  in a containment hierarchy, and getDefaultScheduler() would
059         *  return the root.
060         *
061         *  @return A reference to the default scheduler.
062         */
063        public static Scheduler getDefaultScheduler() {
064            if (defaultScheduler == null) {
065                setDefaultScheduler(DebugScheduler.instance());
066                return getDefaultScheduler();
067            }
068            return defaultScheduler;
069        }
070    
071        /** Gets a string representing the policy of <code>this</code>.
072         *
073         *  @return A <code>java.lang.String</code> object which is the name
074         *          of the scheduling polixy used by <code>this</code>.
075         */
076        public abstract String getPolicyName();
077    
078        /** Queries the system about the feasibility of the set of scheduling
079         *  and release characteristics currently being considered.
080         */
081        public abstract boolean isFeasible();
082        protected abstract boolean isFeasible(Schedulable s, ReleaseParameters rp);
083    
084        /** Inform the scheduler and cooperating facilities that the resource
085         *  demands (as expressed in the associated instances of
086         *  <code>SchedulingParameters, ReleaseParameters, MemoryParameters</code>
087         *  and <code>ProcessingGroupParameters</code>) of this instance of
088         *  <code>Schedulable</code> should no longer be considered in the
089         *  feasibility analysis of the associated <code>Scheduler</code>
090         *  until further notice. Whether the resulting system is feasible
091         *  or not, the subtraction is completed.
092         *
093         *  @return True, if the removal was successful. False, if the removal
094         *          was unsuccessful.
095         */
096        protected abstract void removeFromFeasibility(Schedulable schedulable);
097    
098        /** Set the default scheduler. This is the scheduler given to instances
099         *  of <code>RealtimeThread</code> when they are constructed. The default
100         *  scheduler is set to the required <code>PriorityScheduler</code> at
101         *  startup.
102         *
103         *  @param scheduler The <code>Scheduler</code> that becomes the default
104         *                   scheduler assigned to new threads. If null nothing happens.
105         */
106        public static void setDefaultScheduler(Scheduler scheduler) {
107            defaultScheduler = scheduler;
108        }
109    
110        /** This method appears in many classes in the RTSJ and with various parameters.
111         *  The parameters are either new scheduling characteristics for an instance of
112         *  <code>Schedulable</code> or an instance of <code>Schedulable</code>. The
113         *  method first performs a feasibility analysis using the new scheduling
114         *  characteristics of either <code>this</code> or the given instance of
115         *  <code>Schedulable</code>. If the resulting system is feasible the method
116         *  replaces the current sheduling characteristics, of either <code>this</code>
117         *  or the given instance of <code>Schedulable</code> as appropriate, with the
118         *  new scheduling characteristics.
119         *
120         *  @param schedulable The instance of <code>Schedulable</code> to which the
121         *                     parameters will be assigned.
122         *  @param release The proposed release parameters.
123         *  @param memory The proposed memory parameters.
124         *  @return True, if the resulting system is feasible and the changes are made.
125         *          False, if the resulting system is not feasible and no changes are made.
126         */
127        public abstract boolean setIfFeasible(Schedulable schedulable,
128                                              ReleaseParameters release,
129                                              MemoryParameters memory);
130    
131        /** This method appears in many classes in the RTSJ and with various parameters.
132         *  The parameters are either new scheduling characteristics for an instance of
133         *  <code>Schedulable</code> or an instance of <code>Schedulable</code>. The
134         *  method first performs a feasibility analysis using the new scheduling
135         *  characteristics of either <code>this</code> or the given instance of
136         *  <code>Schedulable</code>. If the resulting system is feasible the method
137         *  replaces the current sheduling characteristics, of either <code>this</code>
138         *  or the given instance of <code>Schedulable</code> as appropriate, with the
139         *  new scheduling characteristics.
140         *
141         *  @param schedulable The instance of <code>Schedulable</code> to which the
142         *                     parameters will be assigned.
143         *  @param release The proposed release parameters.
144         *  @param memory The proposed memory parameters.
145         *  @param group The proposed processing group parameters.
146         *  @return True, if the resulting system is feasible and the changes are made.
147         *          False, if the resulting system is not feasible and no changes are made.
148         */
149    
150        public abstract boolean setIfFeasible(Schedulable schedulable,
151                                              ReleaseParameters release,
152                                              MemoryParameters memory,
153                                              ProcessingGroupParameters group);
154    
155        /** Chooses a thread to run */
156        protected abstract long chooseThread(long currentTime);
157    
158        /** Adds a thread to the thread list */
159        protected abstract void addThread(RealtimeThread thread);
160    
161        /** Removes a thread from the thread list */
162        protected abstract void removeThread(RealtimeThread thread);
163    
164        /** Used for adding a C thread that doesn't have any Java counterpart.
165         *  The convention is that the threadID for C threads is negative.
166         */
167        protected abstract void addThread(long threadID);
168    
169        /** Used for removing a C thread that doesn't have any Java counterpart. 
170         *  The convention is that the threadID for C threads is negative.
171         */
172        protected abstract void removeThread(long threadID);
173    
174        /** Stop running <code>threadID</code> until enableThread - 
175         *  used in the lock implementation to wait on a lock.
176         */
177        protected abstract void disableThread(long threadID);
178    
179        /** Enable <code>threadID</code>, allowing it run again - used in notify */
180        protected abstract void enableThread(long threadID);
181    
182        /** Cause the thread to block until the next period */
183        protected abstract void waitForNextPeriod(RealtimeThread rt);
184    
185        /** Switch every <code>microsecs</code> microseconds */
186        protected final native void setQuanta(long microsecs);
187    
188        /** Print out the status of the scheduler */
189        public final static void print() {
190            Scheduler sched = RealtimeThread.currentRealtimeThread().getScheduler();
191            if (sched == null) {
192                sched = Scheduler.getDefaultScheduler();
193            }
194            MemoryArea.startMem(vt);
195            NoHeapRealtimeThread.print("\n"+sched.getPolicyName()+": "+sched);
196            MemoryArea.stopMem();
197        }
198    
199       /** Run the runnable in an atomic section */
200        public final static void atomic(Runnable run) {
201            int state = beginAtomic();
202            run.run();
203            endAtomic(state);
204        }
205    
206        private final void addToRootSet() {
207            if (Math.sqrt(4)==0) {
208                jDisableThread(null, 0);
209                jEnableThread(null, 0);
210                jChooseThread(0);
211                jRemoveCThread(0);
212                jAddCThread(0);
213                jNumThreads();
214                (new RealtimeThread()).schedule();
215                (new RealtimeThread()).unschedule();
216                new NoSuchMethodException();
217                new NoSuchMethodException("");
218                print();
219            }
220        }
221    
222        final void addThreadToLists(final RealtimeThread thread) {
223            totalThreads++;
224            MemoryArea.startMem(vt);
225            int state = beginAtomic();
226            addToFeasibility(thread);
227            addThreadInC(thread, thread.getUID());
228            addThread(thread);
229            endAtomic(state);
230            MemoryArea.stopMem();
231        }
232    
233        final void removeThreadFromLists(final RealtimeThread thread) {
234            totalThreads--;
235            MemoryArea.startMem(vt);
236            int state = beginAtomic();
237            removeThread(thread);
238            removeThreadInC(thread);
239            removeFromFeasibility(thread);
240            endAtomic(state);
241            MemoryArea.stopMem();
242        }
243    
244        private final native void addThreadInC(Schedulable t, long threadID);
245        private final native long removeThreadInC(Schedulable t);
246        private final native static int beginAtomic();
247        private final native static void endAtomic(int state);
248    
249        final static void jDisableThread(final RealtimeThread rt, 
250                                         final long threadID) {
251            NoHeapRealtimeThread.print("\njDisableThread("+threadID+")");
252            disabledThreads++;
253            MemoryArea.startMem(vt);
254            Scheduler sched;
255            if (rt != null) { 
256                sched = rt.getScheduler();
257            } else {
258                sched = getDefaultScheduler();
259            }
260            if (sched != null) {
261                sched.disableThread(threadID);
262            } else {
263                throw new RuntimeException("\nNo scheduler!!!");
264            }
265            MemoryArea.stopMem();
266        }
267        
268        final static void jEnableThread(final RealtimeThread rt, 
269                                        final long threadID) {
270            NoHeapRealtimeThread.print("\njEnableThread("+threadID+")");
271            disabledThreads--;
272            MemoryArea.startMem(vt);
273            Scheduler sched;
274            if (rt != null) { 
275                sched = rt.getScheduler();
276            } else {
277                sched = getDefaultScheduler();
278            }
279            if (sched != null) {
280                sched.enableThread(threadID);
281            } else {
282                throw new RuntimeException("\nNo scheduler!!!");
283            }
284            MemoryArea.stopMem();
285        }
286    
287        final static void jAddCThread(final long threadID) {
288            totalThreads++;
289            getDefaultScheduler().addThread(threadID);
290        }
291    
292        final static void jRemoveCThread(final long threadID) {
293            totalThreads--;
294            getDefaultScheduler().removeThread(threadID);
295        }
296    
297        private static long totalThreads = 0;
298        private static long disabledThreads = 0;
299    
300        /** Return the total number of active threads in the system. */
301        final static long jNumThreads() { 
302            NoHeapRealtimeThread.print("\nActive threads: "+(totalThreads-disabledThreads));
303            return totalThreads-disabledThreads;
304        }
305    
306        final protected long jChooseThread(final long currentTime) {
307            MemoryArea.startMem(vt);
308            long temp = chooseThread(currentTime);
309            MemoryArea.stopMem();
310            return temp;
311        }
312      
313    }