1 /*
2  * $RCSfile: BehaviorScheduler.java,v $
3  *
4  * Copyright 1997-2008 Sun Microsystems, Inc.  All Rights Reserved.
5  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6  *
7  * This code is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License version 2 only, as
9  * published by the Free Software Foundation.  Sun designates this
10  * particular file as subject to the "Classpath" exception as provided
11  * by Sun in the LICENSE file that accompanied this code.
12  *
13  * This code is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16  * version 2 for more details (a copy is included in the LICENSE file that
17  * accompanied this code).
18  *
19  * You should have received a copy of the GNU General Public License version
20  * 2 along with this work; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
22  *
23  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
24  * CA 95054 USA or visit www.sun.com if you need additional information or
25  * have any questions.
26  *
27  * $Revision: 1.9 $
28  * $Date: 2008/02/28 20:17:19 $
29  * $State: Exp $
30  */
31 
32 package javax.media.j3d;
33 
34 import java.util.ArrayList;
35 import java.util.logging.Level;
36 
37 class BehaviorScheduler extends J3dThread {
38 
39     /**
40      * The virtual universe that owns this BehaviorScheduler
41      */
42     VirtualUniverse univ = null;
43 
44     // reference to behaviourStructure processList
45     UnorderList processList[];
46 
47     // reference to scheduleList;
48     IndexedUnorderSet scheduleList;
49 
50     // reference to universe.behaviorStructure
51     BehaviorStructure behaviorStructure;
52 
53     // A count for BehaviorScheduler start/stop
54     int stopCount = -1;
55 
56     /**
57      * These are used for start/stop BehaviorScheduler
58      */
59     long lastStartTime;
60     long lastStopTime;
61 
62     // lock to ensure consistency of interval values read
63     Object intervalTimeLock = new Object();
64 
65     /**
66      * Some variables used to name threads correctly
67      */
68     private static int numInstances = 0;
69     private int instanceNum = -1;
70 
newInstanceNum()71     private synchronized int newInstanceNum() {
72 	return (++numInstances);
73     }
74 
getInstanceNum()75     int getInstanceNum() {
76 	if (instanceNum == -1)
77 	    instanceNum = newInstanceNum();
78 	return instanceNum;
79     }
80 
81 
BehaviorScheduler(ThreadGroup t, VirtualUniverse universe)82     BehaviorScheduler(ThreadGroup t, VirtualUniverse universe) {
83 	super(t);
84 	setName("J3D-BehaviorScheduler-" + getInstanceNum());
85         this.univ = universe;
86 	behaviorStructure = universe.behaviorStructure;
87 	scheduleList = behaviorStructure.scheduleList;
88 	processList = behaviorStructure.processList;
89 	type = J3dThread.BEHAVIOR_SCHEDULER;
90     }
91 
stopBehaviorScheduler(long[] intervalTime)92     void stopBehaviorScheduler(long[] intervalTime) {
93 
94 	stopCount = 2;
95 	VirtualUniverse.mc.sendRunMessage(univ, J3dThread.BEHAVIOR_SCHEDULER);
96 	while (!userStop ) {
97 	    MasterControl.threadYield();
98 	}
99 	synchronized (intervalTimeLock) {
100 	    intervalTime[0] = lastStartTime;
101 	    intervalTime[1] = lastStopTime;
102 	}
103     }
104 
startBehaviorScheduler()105     void startBehaviorScheduler() {
106 	// don't allow scheduler start until intervalTime is read
107 	synchronized (intervalTimeLock) {
108 	    stopCount = -1;
109 	    userStop = false;
110 	    VirtualUniverse.mc.setWork();
111 	}
112     }
113 
deactivate()114     void deactivate() {
115 	active = false;
116 	if (stopCount >= 0) {
117 	    userStop = true;
118 	}
119     }
120 
121     /**
122      * The main loop for the Behavior Scheduler.
123      * Main method for firing off vector of satisfied conditions that
124      * are contained in the condMet vector.  Method is synchronized
125      * because it is modifying the current wakeup vectors in the
126      * clean (emptying out satisfied conditions) and processStimulus
127      * (adding conditions again if wakeupOn called) calls.
128      */
doWork(long referenceTime)129     void doWork(long referenceTime) {
130 	BehaviorRetained arr[];
131 	UnorderList list;
132 	int i, size, interval;
133 
134 	lastStartTime = J3dClock.currentTimeMillis();
135 
136 	if (stopCount >= 0) {
137 	    VirtualUniverse.mc.sendRunMessage(univ, J3dThread.BEHAVIOR_SCHEDULER);
138 	    if (--stopCount == 0) {
139 		userStop = true;
140 	    }
141 	}
142 
143 
144 	for (interval = 0;
145 	     interval < BehaviorRetained.NUM_SCHEDULING_INTERVALS;
146 	     interval++) {
147 
148 	    list = processList[interval];
149 
150 	    if (list.isEmpty()) {
151 		continue;
152 	    }
153 	    arr = (BehaviorRetained []) list.toArray(false);
154 
155 	    size = list.arraySize();
156 
157 	    for (i = 0; i < size ; i++) {
158 		BehaviorRetained behavret = arr[i];
159 
160 
161 		synchronized (behavret) {
162 		    Behavior behav = (Behavior) behavret.source;
163 
164 		    if (!behav.isLive() ||
165 			!behavret.conditionSet ||
166 			(behavret.wakeupCondition == null)) {
167 			continue;
168 		    }
169 
170 		    if (behavret.wakeupCondition.trigEnum == null) {
171 			behavret.wakeupCondition.trigEnum =
172 			    new WakeupCriteriaEnumerator(behavret.wakeupCondition,
173 							 WakeupCondition.TRIGGERED_ELEMENTS);
174 		    } else {
175 			behavret.wakeupCondition.trigEnum.reset(
176 								behavret.wakeupCondition,
177 								WakeupCondition.TRIGGERED_ELEMENTS);
178 		    }
179 
180 		    // BehaviorRetained now cache the old
181 		    // wakeupCondition in order to
182 		    // reuse it without the heavyweight cleanTree()
183 		    // behavret.wakeupCondition.cleanTree();
184 
185 		    behavret.conditionSet = false;
186 		    WakeupCondition wakeupCond = behavret.wakeupCondition;
187 
188 		    synchronized (behavret) {
189 			behavret.inCallback = true;
190 			univ.inBehavior = true;
191 			try {
192 			    behav.processStimulus(wakeupCond.trigEnum);
193 			}
194 			catch (RuntimeException e) {
195 			    // Force behavior condition to be unset
196 			    // Issue 21: don't call cleanTree here
197 			    behavret.conditionSet = false;
198 			    System.err.println("Exception occurred during Behavior execution:");
199 			    e.printStackTrace();
200 			}
201 			catch (Error e) {
202 			    // Force behavior condition to be unset
203                             // Fix for issue 264
204 			    behavret.conditionSet = false;
205 			    System.err.println("Error occurred during Behavior execution:");
206 			    e.printStackTrace();
207 			}
208 			univ.inBehavior = false;
209 			behavret.inCallback = false;
210 		    }
211 		    // note that if the behavior wasn't reset, we need to make the
212 		    // wakeupcondition equal to null
213 		    if (behavret.conditionSet == false) {
214 			if (wakeupCond != null) {
215 			    wakeupCond.cleanTree(behaviorStructure);
216 			}
217 			behavret.wakeupCondition = null;
218 			behavret.active = false;
219 			scheduleList.remove(behavret);
220 		    } else {
221 			behavret.handleLastWakeupOn(wakeupCond,
222 						    behaviorStructure);
223 		    }
224 		}
225 	    }
226 	    list.clear();
227 	}
228 
229 	behaviorStructure.handleAWTEvent();
230 	behaviorStructure.handleBehaviorPost();
231 	lastStopTime = J3dClock.currentTimeMillis();
232 
233         if (MasterControl.isStatsLoggable(Level.FINE)) {
234             VirtualUniverse.mc.recordTime(MasterControl.TimeType.BEHAVIOR, (lastStopTime-lastStartTime)*1000000);
235         }
236     }
237 
free()238     void free() {
239 	behaviorStructure = null;
240 	getThreadData(null, null).thread = null;
241 	univ = null;
242 	for (int i=BehaviorRetained.NUM_SCHEDULING_INTERVALS-1;
243 	     i >= 0; i--) {
244 	    processList[i].clear();
245 	}
246 	scheduleList.clear();
247     }
248 }
249