1 // Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL]
6 import org.mozilla.javascript.*;
9 * A background thread. All threads created with <tt>xwt.thread</tt>
10 * are instances of this class. ThreadMessage objects can be enqueued
13 * INVARIANT: only one thread can be executing JavaScript scripts or
14 * accessing Box instances at any given time. For
15 * performance reasons, no locks are employed to enforce
18 public class ThreadMessage extends Thread implements Message {
20 private volatile static int threadcount = 0;
22 /** the JavaScript function that we are executing */
25 /** the ThreadMessage thread blocks on this before executing any JavaScript */
26 Semaphore go = new Semaphore();
28 /** The MessageQueue (main) thread blocks on this while the ThreadMessage thread is running JavaScript code */
29 Semaphore done = new Semaphore();
31 /** used to pool ThreadMessages that are not in use */
32 private static Queue spare = new Queue(50);
34 /** queue of functions waiting to be spawned; used if threadcount == Platform.maxThreads() */
35 private static Queue waiting = new Queue(50);
37 private ThreadMessage() { start(); }
38 private static Object[] emptyobj = new Object[] { };
40 /** creates a new thread to execute function <tt>f</tt> */
41 public static synchronized void newthread(Function f) {
42 ThreadMessage ret = (ThreadMessage)spare.remove(false);
44 if (threadcount < Platform.maxThreads()) ret = new ThreadMessage();
51 MessageQueue.add(ret);
54 /** attempts to put this thread into the background to perform a blocking operation; returns false if unable to do so */
55 public static boolean suspendThread() {
56 // put ourselves in the background
57 Thread thread = Thread.currentThread();
58 if (!(thread instanceof ThreadMessage)) {
59 Context cx = Context.enter();
60 if (Log.on) Log.log(ThreadMessage.class, "attempt to perform background-only operation in a foreground thread at " +
61 cx.interpreterSourceFile + ":" + cx.interpreterLine);
64 ThreadMessage mythread = (ThreadMessage)thread;
65 mythread.setPriority(Thread.MIN_PRIORITY);
66 mythread.done.release();
70 /** re-enqueues this thread */
71 public static void resumeThread() {
72 ThreadMessage mythread = (ThreadMessage)Thread.currentThread();
73 MessageQueue.add(mythread);
74 mythread.setPriority(Thread.NORM_PRIORITY);
81 Context cx = Context.enter();
85 f.call(cx, f.getParentScope(), f.getParentScope(), emptyobj);
86 } catch (EcmaError e) {
87 if (Log.on) Log.log(this, "WARNING: uncaught interpreter exception: " + e.getMessage());
88 if (Log.on) Log.log(this, " thrown from background thread at " + e.getSourceName() + ":" + e.getLineNumber());
89 } catch (JavaScriptException e) {
90 if (Log.on) Log.log(this, "WARNING: uncaught ecmascript exception: " + e.getMessage());
91 if (Log.on) Log.log(this, " thrown from background thread at " + e.sourceFile + ":" + e.line);
94 synchronized(waiting) {
95 if (waiting.size() > 0) {
96 f = (Function)waiting.remove(false);
97 MessageQueue.add(this);
98 } else if (spare.size() < 10) {
106 } catch (Throwable t) {
107 if (Log.on) Log.log(this, "caught throwable at thread entry point; this should never happen");
108 if (Log.on) Log.log(this, t);
109 if (Log.on) Log.log(this, "reaping thread");
114 /** this is invoked in the MessageQueue thread */
115 public void perform() {