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