8fdb506508891924ca408a338bcc47371abb3d63
[org.ibex.core.git] / src / org / ibex / core / Scheduler.java
1 // Copyright 2000-2005 the Contributors, as shown in the revision logs.
2 // Licensed under the GNU General Public License version 2 ("the License").
3 // You may not use this file except in compliance with the License.
4
5 package org.ibex.core;
6
7 import java.io.IOException;
8
9 import org.ibex.js.*;
10 import org.ibex.util.*;
11 import org.ibex.graphics.*;
12 import org.ibex.plat.*;
13
14 /** Implements cooperative multitasking */
15 public class Scheduler {
16
17     // Public API Exposed to org.ibex /////////////////////////////////////////////////
18
19     private static Scheduler singleton;
20     public static void add(Callable t) { Log.debug(Scheduler.class, "scheduling " + t); Scheduler.runnable.append(t); }
21     public static void init() { if (singleton == null) (singleton = Platform.getScheduler()).run(); }
22
23     private static Callable current = null;
24
25     private static volatile boolean rendering = false;
26     private static volatile boolean again = false;
27
28     /** synchronizd so that we can safely call it from an event-delivery thread, in-context */
29     public static void renderAll() {
30         if (rendering) { again = true; return; }
31         synchronized(Scheduler.class) {
32             try {
33                 rendering = true;
34                 do {
35                     // FEATURE: this could be cleaner
36                     again = false;
37                     for(int i=0; i<Surface.allSurfaces.size(); i++) {
38                         Surface s = ((Surface)Surface.allSurfaces.elementAt(i));
39                         do { s.render(); } while(s.abort);
40                     }
41                 } while(again);
42             } finally {
43                 rendering = false;
44             }
45         }
46     }
47
48     
49
50     // API which must be supported by subclasses /////////////////////////////////////
51
52     /**
53      *  SCHEDULER INVARIANT: all scheduler implementations MUST invoke
54      *  Surface.renderAll() after performing a Callable if no tasks remain
55      *  in the queue.  A scheduler may choose to invoke
56      *  Surface.renderAll() more often than that if it so chooses.
57      */
58     public void run() { defaultRun(); }
59     public Scheduler() { }
60
61
62     // Default Implementation //////////////////////////////////////////////////////
63
64     protected static Queue runnable = new Queue(50);
65     public void defaultRun() {
66         while(true) {
67             current = (Callable)runnable.remove(true);
68             try {
69                 // FIXME hideous
70                 synchronized(this) {
71                     for(int i=0; i<Surface.allSurfaces.size(); i++) {
72                         Surface s = (Surface)Surface.allSurfaces.elementAt(i);
73                         if (current instanceof JS) {
74                             s._mousex = Integer.MAX_VALUE;
75                             s._mousey = Integer.MAX_VALUE;
76                         } else {
77                             s._mousex = s.mousex;
78                             s._mousey = s.mousey;
79                         }
80                     }
81                     Log.debug(Scheduler.class, "performing " + current);
82                     current.run(null);
83                 }
84                 renderAll();
85             } catch (JSExn e) {
86                 Log.info(Scheduler.class, "a JavaScript thread spawned with ibex.thread() threw an exception:");
87                 Log.info(Scheduler.class,e);
88             } catch (Exception e) {
89                 Log.info(Scheduler.class, "a Callable threw an exception which was caught by the scheduler:");
90                 Log.info(Scheduler.class, e);
91             } catch (Throwable t) {
92                 t.printStackTrace();
93             }
94             // if an Error is thrown it will cause the engine to quit
95         }
96     }
97 }