001: /*
002: * $RCSfile: J3dThread.java,v $
003: *
004: * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
006: *
007: * This code is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU General Public License version 2 only, as
009: * published by the Free Software Foundation. Sun designates this
010: * particular file as subject to the "Classpath" exception as provided
011: * by Sun in the LICENSE file that accompanied this code.
012: *
013: * This code is distributed in the hope that it will be useful, but WITHOUT
014: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: * version 2 for more details (a copy is included in the LICENSE file that
017: * accompanied this code).
018: *
019: * You should have received a copy of the GNU General Public License version
020: * 2 along with this work; if not, write to the Free Software Foundation,
021: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
022: *
023: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
024: * CA 95054 USA or visit www.sun.com if you need additional information or
025: * have any questions.
026: *
027: * $Revision: 1.6 $
028: * $Date: 2008/02/28 20:17:25 $
029: * $State: Exp $
030: */
031:
032: package javax.media.j3d;
033:
034: /**
035: * The J3dThread is the super class of all slave threads in Java 3D. It implements
036: * all of the common flow control constructs.
037: */
038:
039: abstract class J3dThread extends Thread {
040: /**
041: * These are the thread types that a message may affect
042: */
043: static final int BEHAVIOR_SCHEDULER = 0x01;
044: static final int SOUND_SCHEDULER = 0x02;
045: static final int INPUT_DEVICE_SCHEDULER = 0x04;
046: static final int RENDER_THREAD = 0x10;
047: // static final int COLLISION_THREAD = 0x20;
048: static final int UPDATE_GEOMETRY = 0x40;
049: static final int UPDATE_RENDER = 0x80;
050: static final int UPDATE_BEHAVIOR = 0x100;
051: static final int UPDATE_SOUND = 0x200;
052: static final int UPDATE_RENDERING_ATTRIBUTES = 0x400;
053: static final int UPDATE_RENDERING_ENVIRONMENT = 0x1000;
054: static final int UPDATE_TRANSFORM = 0x2000;
055:
056: /**
057: * The classification types.
058: */
059: static final int WORK_THREAD = 0x01;
060: static final int UPDATE_THREAD = 0x02;
061:
062: /**
063: * This runMonitor action puts the thread into an initial wait state
064: */
065: static final int WAIT = 0;
066:
067: /**
068: * This runMonitor action notifies MasterControl that this thread
069: * has completed and wait.
070: */
071: static final int NOTIFY_AND_WAIT = 1;
072:
073: /**
074: * This is used by Canvas3D Renderer to notify user thread
075: * that swap is completed.
076: */
077: static final int NOTIFY = 2;
078:
079: /**
080: * This runMonitor action tells the thread to run N number of
081: * iterations.
082: */
083: static final int RUN = 2;
084:
085: /**
086: * This runMonitor action tells the thread to stop running
087: */
088: static final int STOP = 3;
089:
090: /**
091: * This indicates that this thread has been activated by MC
092: */
093: boolean active = false;
094:
095: /**
096: * This indicates that this thread is alive and running
097: */
098: private volatile boolean running = true;
099:
100: /**
101: * This flag is set by the RUN action of runMonitor to indicate that the
102: * waiting thread has work to do.
103: */
104: private volatile boolean ready = false;
105:
106: /**
107: * The thread data for this thread
108: */
109: private J3dThreadData[] data = null;
110:
111: /**
112: * This indicates that this thread is started and able to accept work
113: */
114: private volatile boolean started = false;
115:
116: /**
117: * The time values passed into this thread
118: */
119: long referenceTime;
120:
121: /**
122: * Use to assign threadOpts WAIT_ALL_THREADS
123: */
124: long lastWaitTimestamp = 0;
125:
126: /**
127: * The type of this thread. It is one of the above constants.
128: */
129: int type;
130:
131: /**
132: * The classification of this thread. It is one of the above constants.
133: */
134: int classification = WORK_THREAD;
135:
136: /**
137: * The arguments passed in for this thread
138: */
139: Object[] args = null;
140:
141: /**
142: * Flag to indicate that user initiate a thread stop
143: */
144: volatile boolean userStop = false;
145:
146: /**
147: * Flag to indicate that this thread is waiting to be notify
148: */
149: private volatile boolean waiting = false;
150:
151: /**
152: * Some variables used to name threads correctly
153: */
154: private static int numInstances = 0;
155: private int instanceNum = -1;
156:
157: private synchronized int newInstanceNum() {
158: return (++numInstances);
159: }
160:
161: int getInstanceNum() {
162: if (instanceNum == -1)
163: instanceNum = newInstanceNum();
164: return instanceNum;
165: }
166:
167: /**
168: * This method is defined by all slave threads to implement
169: * one iteration of work.
170: */
171: abstract void doWork(long referenceTime);
172:
173: /**
174: * This constructor simply assigns the given id.
175: */
176: J3dThread(ThreadGroup t) {
177: super (t, "");
178: }
179:
180: /**
181: * This returns the thread data for this thread.
182: */
183: synchronized J3dThreadData getThreadData(View v, Canvas3D c) {
184: J3dThreadData threadData;
185: int i, j;
186: J3dThreadData[] newData;
187:
188: if (type != RENDER_THREAD) { // Regular Thread
189: if (data == null) {
190: data = new J3dThreadData[1];
191: data[0] = new J3dThreadData();
192: data[0].thread = this ;
193: data[0].threadType = type;
194: data[0].view = null;
195: data[0].canvas = null;
196: }
197: threadData = data[0];
198: } else { // Render thread
199:
200: // Note: each renderer has multiple thread data mappings
201: // for its render and swap threads
202:
203: if (data == null) {
204: data = new J3dThreadData[1];
205: data[0] = new J3dThreadData();
206: data[0].thread = this ;
207: data[0].threadType = type;
208: data[0].view = v;
209: data[0].canvas = c;
210: data[0].threadArgs = new Object[4];
211: threadData = data[0];
212: } else {
213: for (i = 0; i < data.length; i++) {
214: if (data[i].view == v && data[i].canvas == c) {
215: break;
216: }
217: }
218: if (i == data.length) {
219: newData = new J3dThreadData[data.length + 1];
220: for (j = 0; j < data.length; j++) {
221: newData[j] = data[j];
222: }
223: data = newData;
224: data[j] = new J3dThreadData();
225: data[j].thread = this ;
226: data[j].threadType = type;
227: data[j].view = v;
228: data[j].canvas = c;
229: data[j].threadArgs = new Object[4];
230: threadData = data[j];
231: } else {
232: threadData = data[i];
233: Object args[] = (Object[]) threadData.threadArgs;
234: args[0] = null;
235: args[1] = null;
236: args[2] = null;
237: args[3] = null;
238: }
239: }
240:
241: }
242:
243: return (threadData);
244: }
245:
246: /**
247: * This initializes this thread. Once this method returns, the thread is
248: * able to accept work.
249: */
250: void initialize() {
251: this .start();
252: while (!started) {
253: MasterControl.threadYield();
254: }
255: }
256:
257: /**
258: * This causes the threads run method to exit.
259: */
260: void finish() {
261: // NOTE: This spin loop is probably not necessary.
262: while (!waiting) {
263: MasterControl.threadYield();
264: }
265: runMonitor(STOP, 0, null);
266: }
267:
268: /**
269: * This thread controls the syncing of all the canvases attached to
270: * this view.
271: */
272: public void run() {
273: runMonitor(WAIT, 0, null);
274: while (running) {
275: doWork(referenceTime);
276: runMonitor(NOTIFY_AND_WAIT, 0, null);
277: }
278: // resource clean up
279: shutdown();
280: }
281:
282: synchronized void runMonitor(int action, long referenceTime,
283: Object[] args) {
284: switch (action) {
285: case WAIT:
286: started = true;
287: // Issue 279 - loop until ready
288: while (!ready && running) {
289: waiting = true;
290: try {
291: wait();
292: } catch (InterruptedException e) {
293: System.err.println(e);
294: }
295: waiting = false;
296: }
297: ready = false;
298: break;
299:
300: case NOTIFY_AND_WAIT:
301: VirtualUniverse.mc.runMonitor(MasterControl.THREAD_DONE,
302: null, null, null, this );
303: // Issue 279 - loop until ready
304: while (!ready && running) {
305: waiting = true;
306: try {
307: wait();
308: } catch (InterruptedException e) {
309: System.err.println(e);
310: }
311: waiting = false;
312: }
313: ready = false;
314: break;
315:
316: case RUN:
317: this .referenceTime = referenceTime;
318: this .args = args;
319: ready = true;
320: if (waiting) {
321: notify();
322: }
323: break;
324:
325: case STOP:
326: running = false;
327: if (waiting) {
328: notify();
329: }
330: break;
331: }
332: }
333:
334: void cleanupView() {
335: // renderer will reconstruct threadData next time
336: // in getThreadData
337: data = null;
338: }
339:
340: // default resource clean up method
341: void shutdown() {
342: }
343:
344: void cleanup() {
345: active = false;
346: running = true;
347: ready = false;
348: data = null;
349: started = true;
350: lastWaitTimestamp = 0;
351: classification = WORK_THREAD;
352: args = null;
353: userStop = false;
354: referenceTime = 0;
355:
356: }
357:
358: }
|