001/* The DE domain director. 002 003 Copyright (c) 1998-2018 The Regents of the University of California. 004 All rights reserved. 005 Permission is hereby granted, without written agreement and without 006 license or royalty fees, to use, copy, modify, and distribute this 007 software and its documentation for any purpose, provided that the above 008 copyright notice and the following two paragraphs appear in all copies 009 of this software. 010 011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 015 SUCH DAMAGE. 016 017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022 ENHANCEMENTS, OR MODIFICATIONS. 023 024 PT_COPYRIGHT_VERSION_2 025 COPYRIGHTENDKEY 026 */ 027package ptolemy.domains.de.kernel; 028 029import java.util.ArrayList; 030import java.util.Collection; 031import java.util.HashMap; 032import java.util.HashSet; 033import java.util.Iterator; 034import java.util.List; 035import java.util.Set; 036 037import ptolemy.actor.Actor; 038import ptolemy.actor.ActorExecutionAspect; 039import ptolemy.actor.CompositeActor; 040import ptolemy.actor.Director; 041import ptolemy.actor.FiringEvent; 042import ptolemy.actor.IOPort; 043import ptolemy.actor.Manager; 044import ptolemy.actor.QuasiTransparentDirector; 045import ptolemy.actor.Receiver; 046import ptolemy.actor.SuperdenseTimeDirector; 047import ptolemy.actor.util.CausalityInterface; 048import ptolemy.actor.util.CausalityInterfaceForComposites; 049import ptolemy.actor.util.Dependency; 050import ptolemy.actor.util.Time; 051import ptolemy.data.BooleanToken; 052import ptolemy.data.IntToken; 053import ptolemy.data.Token; 054import ptolemy.data.expr.Parameter; 055import ptolemy.data.type.BaseType; 056import ptolemy.kernel.CompositeEntity; 057import ptolemy.kernel.util.Attribute; 058import ptolemy.kernel.util.DebugListener; 059import ptolemy.kernel.util.IllegalActionException; 060import ptolemy.kernel.util.InternalErrorException; 061import ptolemy.kernel.util.KernelException; 062import ptolemy.kernel.util.NameDuplicationException; 063import ptolemy.kernel.util.Nameable; 064import ptolemy.kernel.util.NamedObj; 065import ptolemy.kernel.util.Settable; 066import ptolemy.kernel.util.Workspace; 067 068/////////////////////////////////////////////////////////////////// 069//// DEDirector 070 071/** 072 <p>This director implements the discrete-event (DE) model of computation (MoC). 073 It should be used as the local director of a CompositeActor that is 074 to be executed according to the DE MoC. This director maintains a totally 075 ordered set of events and processes these events in the order defined on 076 their tags and depths. 077 </p><p> 078 An event is associated with a tag, which is a tuple of timestamp and 079 microstep. A timestamp indicates the model time when this event occurs. It 080 is an object of the {@link ptolemy.actor.util.Time} class. A microstep is an 081 integer which represents the index of the sequence of execution phases when 082 this director processes events with the same timestamp. Two tags are equal 083 if they have the same timestamp and microstep. If two events have the same 084 tag, they are called simultaneous events. 085 </p><p> 086 Microsteps can only be increased by calling the fireAt() method. For example, 087 when an actor requests to be fired again at the current model time, a 088 new event with the same timestamp but a bigger microstep (incremented by 1) 089 will be generated. 090 </p><p> 091 An event is also associated with a depth reflecting its priority, based 092 on which a DE director chooses the execution order for simultaneous events. 093 A depth is an integer and a larger value of depth indicates a lower priority. 094 The depth of an event is determined by topologically sorting all the ports 095 of actors according to their data dependencies over which there is no time 096 delay. 097 </p><p> 098 The order of events is defined as follows. An event A is said to be earlier 099 than another event B if A's timestamp is smaller than B's; or if A's 100 timestamp is the same as B's, and A's microstep is smaller than B's; or if 101 A's tag is the same as B's, and A's depth is smaller than B's. By giving 102 events this well-defined order, this director can handle simultaneous events 103 in a deterministic way. 104 </p><p> 105 The bottleneck in a typical DE simulator is in the maintenance of the 106 global event queue. This director uses the calendar queue as the global 107 event queue. This is an efficient algorithm with O(1) time complexity in 108 both enqueue and dequeue operations. Sorting in the 109 {@link ptolemy.actor.util.CalendarQueue} class is done according to the 110 order defined above. 111 </p><p> 112 The complexity of the calendar algorithm is sensitive to the length of the 113 event queue. When the size of the event queue becomes too long or changes 114 very often, the simulation performance suffers from the penalties of queuing 115 and dequeuing events. A few mechanisms are implemented to reduce such 116 penalties by keeping the event queue short. The first mechanism is to only 117 store in the event queue <i>pure</i> events and the <i>trigger</i> events 118 with the same timestamp and microstep as those of the director. See 119 {@link DEEvent} for explanation of these two types of events. What is more, 120 no duplicate trigger events are allowed in the event queue. Another mechanism 121 is that in a hierarchical model, each level keeps a local event queue. 122 A lower level only reports the earliest event to its upper level 123 to schedule a future firing. The last mechanism is to maintain a list which 124 records all actors that are disabled. Any triggers sent to the actors in 125 this list are discarded. 126 </p><p> 127 In the initialize() method, depths of actors and IO ports are statically 128 analyzed and calculated. They are not calculated in the preinitialize() 129 method because hierarchical models may change their structures during their 130 preinitialize() method. For example, a modal model does not specify its 131 initial state (and its refinement) until the end of its preinitialize() 132 method. See {@link ptolemy.domains.modal.kernel.FSMActor}. In order to support 133 mutation, this director recalculates the depths at the beginning of its next 134 iteration. 135 </p><p> 136 There are two types of depths: one is associated with IO ports, which 137 reflects the order of trigger events; the other one is associated with 138 actors, which is for pure events. The relationship between the depths of IO 139 ports and actors is that the depth of an actor is the smallest of the depths 140 of its IO ports. Pure events can only be produced by calling the fireAt() 141 method, and trigger events can only be produced by actors that produce 142 outputs. See {@link ptolemy.domains.de.kernel.DEReceiver#put(Token)}. 143 </p><p> 144 Directed loops of IO ports with no delay will trigger an exception. 145 These are called <i>causality loops</i>. Such loops can be broken with 146 actors whose output ports do not have an immediate dependence on their 147 input ports, such as the <i>TimeDelay</i> actor. Notice that the 148 <i>TimeDelay</i> actor breaks a causality loop even if the time 149 delay is set to 0.0. This is because DE uses a <i>superdense</i> 150 notion of time. The output is interpreted as being strictly later 151 than the input even though its time value is the same. 152 Whether a causality loop exists is determined by the 153 {@link ptolemy.actor.util.CausalityInterface} returned by each actor's 154 getCausalityInterface() method. 155 </p><p> 156 An input port in a DE model contains an instance of DEReceiver. 157 When a token is put into a DEReceiver, that receiver posts a trigger 158 event to the director. This director sorts trigger events in a global event 159 queue. 160 </p><p> 161 An iteration, in the DE domain, is defined as processing all the events 162 whose tags are equal to the current tag of the director (also called the 163 model tag). At the beginning of the fire() method, this director dequeues 164 a subset of the earliest events (the ones with smallest timestamp, microstep, 165 and depth) that have the same destination actor 166 from the global event queue. Then, this director fires that actor. 167 This actor must consume tokens from its input port(s), 168 and usually produces new events on its output port(s). These new events will 169 trigger the destination actors to fire. It is important that the actor 170 actually consumes tokens from its inputs, even if the tokens are solely 171 used to trigger reactions, because the actor will be fired repeatedly 172 until there are no more tokens in its input ports with the same tag, 173 or until the actor returns false in its prefire() method. The 174 director then keeps dequeuing and processing the earliest events from the 175 event queue until no more events have the same tag. 176 </p><p> 177 Note that each time this director fires an actor, it 178 also invokes postfire() on that actor. 179 Note that under this policy, it is possible for an actor to be fired and postfired 180 multiple times in an iteration. 181 This does not really correctly implement superdense time semantics, but it is 182 an approximation that will reject some models that should be able to be executed. 183 An actor like the TimeDelay will be fired (and postfired) multiple times 184 at a superdense time index if it is in a feedback loop. 185 </p><p> 186 A model starts from the time specified by <i>startTime</i>. This is blank 187 by default, which indicates that the start time is the current time of 188 the enclosing director, if there is one, and 0.0 otherwise. 189 The stop time of the execution can be set 190 using the <i>stopTime</i> parameter. The parameter has a default value 191 <i>Infinity</i>, which means the execution runs forever. 192 </p><p> 193 Execution of a DE model ends when the timestamp of the earliest event 194 exceeds the stop time. This stopping condition is checked inside 195 the postfire() method of this director. By default, execution also ends 196 when the global event queue becomes empty. Sometimes, the desired 197 behaviour is for the director to wait on an empty queue until another 198 thread makes new events available. For example, a DE actor may produce 199 events when a user hits a button on the screen. To prevent ending the 200 execution when there are no more events, set the 201 <i>stopWhenQueueIsEmpty</i> parameter to <code>false</code>. 202 </p><p> 203 Parameters <i>isCQAdaptive</i>, <i>minBinCount</i>, and 204 <i>binCountFactor</i>, are used to configure the calendar queue. 205 Changes to these parameters are ignored when the model is running. 206 </p><p> 207 If the parameter <i>synchronizeToRealTime</i> is set to <code>true</code>, 208 then the director will not process events until the real time elapsed 209 since the model started matches the timestamp of the event. 210 This ensures that the director does not get ahead of real time. However, 211 of course, this does not ensure that the director keeps up with real time. 212 </p><p> 213 This director tolerates changes to the model during execution. 214 The change should be queued with a component in the hierarchy using 215 requestChange(). While invoking those changes, the method 216 invalidateSchedule() is expected to be called, notifying the director 217 that the topology it used to calculate the priorities of the actors 218 is no longer valid. This will result in the priorities (depths of actors) 219 being recalculated the next time prefire() is invoked. 220 </p><p> 221 <b>Limitations</b>: According to [1], at each microstep, DE should 222 perform a fixed point iteration. This implementation does not do that, 223 and consequently, this director is not able to execute all correctly 224 constructed DE models. For an example, see 225 $PTII/ptolemy/domains/de/test/auto/DEFixedPointLimitation.xml. 226 That example has a DE opaque composite actor in a feedback loop. 227 In principle, there should be no causality loop. The actor output 228 should be able to be produced without knowing the input. However, 229 the inside director has to guarantee that when it fires any of 230 its contained actors, all inputs of a given microstep are available 231 to that actor. As a consequence, the opaque actor also needs to know 232 all of its inputs at the current microstep. Hence, a causality loop 233 is reported. We encourage the reader to make a variant of this director 234 that can handle such models. 235 </p><p> 236 <b>References</b>: 237 <br> 238 [1] Lee, E. A. and H. Zheng (2007). Leveraging Synchronous Language 239 Principles for Heterogeneous Modeling and Design of Embedded Systems. 240 EMSOFT, Salzburg, Austria, October, ACM. 241 242 @author Lukito Muliadi, Edward A. Lee, Jie Liu, Haiyang Zheng 243 @version $Id$ 244 @since Ptolemy II 0.2 245 @Pt.ProposedRating Green (hyzheng) 246 @Pt.AcceptedRating Yellow (hyzheng) 247 */ 248public class DEDirector extends Director implements SuperdenseTimeDirector { 249 250 /* NOTE: This implementation of DE has a very subtle bug documented in the 251 * following test: 252 * $PTII/ptolemy/domains/de/test/auto/knownFailedTests/DirectFeedback.xml 253 * This test exposes a subtle bug in DE that is probably not worth 254 * fixing because the only fix I can find would incur considerable 255 * overhead on every event transaction, and it is rather difficult to 256 * write an actor that will trigger the bug. The SuperdensTimeTest 257 * actor used in this test is such an actor, but as of this writing, 258 * there are no such actor in the library. 259 * 260 * The bug occurs when an actor declares that an output port does 261 * not depend on any input (something that is rather hard to do 262 * correctly), and then feeds back a signal directly 263 * from the output to an input. The bug is that an output token 264 * produced by the actor may be visible to the actor in the very same 265 * firing of the actor, or in postfire of the same iteration. This violates 266 * a principle in DE that when an actor firing begins, all inputs at 267 * the current superdense time are available. 268 */ 269 270 /** Construct a director in the default workspace with an empty string 271 * as its name. The director is added to the list of objects in 272 * the workspace. Increment the version number of the workspace. 273 * @exception NameDuplicationException If construction of Time objects fails. 274 * @exception IllegalActionException If construction of Time objects fails. 275 */ 276 public DEDirector() 277 throws IllegalActionException, NameDuplicationException { 278 super(); 279 _initParameters(); 280 } 281 282 /** Construct a director in the workspace with an empty name. 283 * The director is added to the list of objects in the workspace. 284 * Increment the version number of the workspace. 285 * @param workspace The workspace of this object. 286 * @exception NameDuplicationException If construction of Time objects fails. 287 * @exception IllegalActionException If construction of Time objects fails. 288 */ 289 public DEDirector(Workspace workspace) 290 throws IllegalActionException, NameDuplicationException { 291 super(workspace); 292 _initParameters(); 293 } 294 295 /** Construct a director in the given container with the given name. 296 * The container argument must not be null, or a 297 * NullPointerException will be thrown. 298 * If the name argument is null, then the name is set to the 299 * empty string. Increment the version number of the workspace. 300 * @param container Container of the director. 301 * @param name Name of this director. 302 * @exception IllegalActionException If the 303 * director is not compatible with the specified container. 304 * @exception NameDuplicationException If the container not a 305 * CompositeActor and the name collides with an entity in the container. 306 */ 307 public DEDirector(CompositeEntity container, String name) 308 throws IllegalActionException, NameDuplicationException { 309 super(container, name); 310 _initParameters(); 311 } 312 313 /////////////////////////////////////////////////////////////////// 314 //// parameters //// 315 316 /** The factor when adjusting the bin number. 317 * This parameter must contain an IntToken. 318 * Changes to this parameter are ignored when the model is running. 319 * The value defaults to 2. 320 */ 321 public Parameter binCountFactor; 322 323 /** A flag indicating whether this director should enforce 324 * microstep semantics, throwing an exception when actors 325 * deliver events at microstep 0. Such events can arise from 326 * attempting to deliver to the DE domain a continuous signal 327 * from the Continuous domain. This is a boolean that defaults 328 * to false. 329 */ 330 public Parameter enforceMicrostepSemantics; 331 332 /** Specify whether the calendar queue adjusts its bin number 333 * at run time. This parameter must contain a BooleanToken. 334 * If this parameter is true, the calendar queue will adapt 335 * its bin number with respect to the distribution of events. 336 * Changes to this parameter are ignored when the model is running. 337 * The value defaults to true. 338 */ 339 public Parameter isCQAdaptive; 340 341 /** The minimum (initial) number of bins in the calendar queue. 342 * This parameter must contain an IntToken. 343 * Changes to this parameter are ignored when the model is running. 344 * The value defaults to 2. 345 */ 346 public Parameter minBinCount; 347 348 /** Specify whether the execution stops when the queue is empty. 349 * This parameter must contain a 350 * BooleanToken. If this parameter is true, the 351 * execution of the model will be stopped when the queue is empty. 352 * The value defaults to true. 353 */ 354 public Parameter stopWhenQueueIsEmpty; 355 356 /** Specify whether the execution should synchronize to the 357 * real time. This parameter must contain a BooleanToken. 358 * If this parameter is true, then do not process events until the 359 * elapsed real time matches the time stamp of the events. 360 * The value defaults to false. 361 */ 362 public Parameter synchronizeToRealTime; 363 364 /////////////////////////////////////////////////////////////////// 365 //// public methods //// 366 367 /** Append the specified listener to the current set of debug listeners. 368 * If an event queue has been created, register the listener to that queue. 369 * @param listener The listener to be added to the list of listeners 370 * to which debug messages are sent. 371 * @see #removeDebugListener(DebugListener) 372 */ 373 @Override 374 public void addDebugListener(DebugListener listener) { 375 if (_eventQueue != null) { 376 synchronized (_eventQueueLock) { 377 _eventQueue.addDebugListener(listener); 378 } 379 } 380 381 super.addDebugListener(listener); 382 } 383 384 /** Update the director parameters when attributes are changed. 385 * Changes to <i>isCQAdaptive</i>, <i>minBinCount</i>, and 386 * <i>binCountFactor</i> parameters will only be effective on 387 * the next time when the model is executed. 388 * @param attribute The changed parameter. 389 * @exception IllegalActionException If the parameter set is not valid. 390 * Not thrown in this class. 391 */ 392 @Override 393 public void attributeChanged(Attribute attribute) 394 throws IllegalActionException { 395 if (attribute == stopWhenQueueIsEmpty) { 396 _stopWhenQueueIsEmpty = ((BooleanToken) stopWhenQueueIsEmpty 397 .getToken()).booleanValue(); 398 } else if (attribute == synchronizeToRealTime) { 399 _synchronizeToRealTime = ((BooleanToken) synchronizeToRealTime 400 .getToken()).booleanValue(); 401 } else if (attribute == enforceMicrostepSemantics) { 402 _enforceMicrostepSemantics = ((BooleanToken) enforceMicrostepSemantics 403 .getToken()).booleanValue(); 404 } else { 405 super.attributeChanged(attribute); 406 } 407 } 408 409 /** Cancel a requested firing of the given actor at the given model 410 * time microstep 1. 411 * @param actor The actor scheduled to be fired. 412 * @param time The requested time. 413 * @exception IllegalActionException If cancelling a firing is not 414 * supported by the current event queue. 415 */ 416 public void cancelFireAt(Actor actor, Time time) 417 throws IllegalActionException { 418 cancelFireAt(actor, time, 1); 419 } 420 421 /** Cancel a requested firing of the given actor at the given model 422 * time with the given microstep. 423 * @param actor The actor scheduled to be fired. 424 * @param time The requested time. 425 * @param index The microstep. 426 * @exception IllegalActionException If cancelling a firing is not 427 * supported by the current event queue. 428 */ 429 public void cancelFireAt(Actor actor, Time time, int index) 430 throws IllegalActionException { 431 if (_eventQueue == null) { 432 throw new IllegalActionException(this, 433 "Calling cancelFireAt() before preinitialize()."); 434 } 435 if (_debugging) { 436 _debug("DEDirector: Cancelling firing of actor " 437 + actor.getFullName() + " at " + time + " with microstep " 438 + index); 439 } 440 int depth = _getDepthOfActor(actor); 441 _eventQueue.remove(new DEEvent(actor, time, index, depth)); 442 } 443 444 /** Clone the object into the specified workspace. The new object is 445 * <i>not</i> added to the directory of that workspace (you must do this 446 * yourself if you want it there). 447 * The result is an attribute with no container. 448 * @param workspace The workspace for the cloned object. 449 * @exception CloneNotSupportedException Not thrown in this base class 450 * @return The new Attribute. 451 */ 452 @Override 453 public Object clone(Workspace workspace) throws CloneNotSupportedException { 454 DEDirector newObject = (DEDirector) super.clone(workspace); 455 newObject._disabledActors = null; 456 newObject._eventQueue = null; 457 newObject._eventQueueLock = new Object(); 458 newObject._exceedStopTime = false; 459 newObject._isInitializing = false; 460 newObject._microstep = 1; 461 newObject._noMoreActorsToFire = false; 462 newObject._stopFireRequested = false; 463 return newObject; 464 } 465 466 /** Return a string that describes the depths of actors and their ports. 467 * These depths are used to prioritize firings, where lower depths 468 * result in higher priorities. 469 * @return A string that describes the depths of actors and their ports. 470 * @exception IllegalActionException If there is a causality loop. 471 */ 472 public String describePriorities() throws IllegalActionException { 473 CompositeActor container = (CompositeActor) getContainer(); 474 CausalityInterfaceForComposites causality = (CausalityInterfaceForComposites) container 475 .getCausalityInterface(); 476 return causality.describeDepths(); 477 } 478 479 /** Fire actors according to events in the event queue. The actual 480 * selecting which events to process is done in _fire(). _fire() 481 * will return whether the previous firing was successful. According 482 * to this information, it is decided whether _fire() should be called 483 * again in order to keep processing events. After each actor firing, 484 * book keeping procedures are called, to keep track of the current 485 * state of the scheduler. The model time of the next events are also 486 * checked to see if we have produced an event of smaller timestamp. 487 * @see #_fire 488 * @exception IllegalActionException If we couldn't process an event 489 * or if an event of smaller timestamp is found within the event queue. 490 */ 491 @Override 492 public void fire() throws IllegalActionException { 493 if (_debugging) { 494 _debug("========= " + this.getName() + " director fires at " 495 + getModelTime() + " with microstep as " + _microstep); 496 } 497 498 // NOTE: This fire method does not call super.fire() 499 // because this method is very different from that of the super class. 500 // A BIG while loop that handles all events with the same tag. 501 while (true) { 502 int result = _fire(); 503 assert result <= 1 && result >= -1; 504 if (result == 1) { 505 continue; 506 } else if (result == -1) { 507 _noActorToFire(); 508 return; 509 } // else if 0, keep executing 510 511 // after actor firing, the subclass may wish to perform some book keeping 512 // procedures. However in this class the following method does nothing. 513 _actorFired(); 514 515 if (!_checkForNextEvent()) { 516 break; 517 } // else keep executing in the current iteration 518 } // Close the BIG while loop. 519 520 // Since we are now actually stopping the firing, we can set this false. 521 _stopFireRequested = false; 522 523 if (_debugging) { 524 _debug("DE director fired!"); 525 } 526 } 527 528 /** Schedule an actor to be fired at the specified time by posting 529 * a pure event to the director, and return the time at which 530 * the specified actor will be fired. If the requested time is in the past 531 * relative to the current time, then it will be increased to match 532 * current time. The caller to this method is responsible for throwing 533 * an exception if it is not acceptable for that time to differ from 534 * the requested time. 535 * <p> 536 * If this director is embedded within another model (the container 537 * has an executive director), and this method is being called between 538 * iterations of this director (which can only occur from a thread 539 * different from the one firing this director), then 540 * this method also delegates a request to the executive director 541 * to fire the container of this director at the requested time. 542 * If the executive director returns a value different from the 543 * specified time, then this method will use that revised value 544 * to schedule the firing of the specified actor, and will return 545 * that value. 546 * <p> 547 * A subtle corner case can occur in a multithreaded execution that 548 * will trigger an exception. In particular, it is possible for this 549 * director to delegate a request to its executive director, and 550 * for that request to be honored before it has posted the event 551 * on its own local event queue. This situation is avoided, for 552 * example, by putting this director within a ThreadedComposite 553 * actor. If this situation occurs, an exception will be thrown. 554 * @param actor The scheduled actor to fire. 555 * @param time The scheduled time to fire. 556 * @return The time at which the actor will be fired, which matches 557 * the argument. 558 * @exception IllegalActionException If the event queue is not ready, 559 * or if a threading error occurs that would result in returning 560 * a time value that is already in the past. 561 */ 562 @Override 563 public Time fireAt(Actor actor, Time time) throws IllegalActionException { 564 return fireAt(actor, time, 1); 565 } 566 567 /** Request a firing of the given actor at the given model 568 * time with the given microstep. Most actors will not want to use 569 * this method, but if you need for a firing to occur at microstep 0, 570 * then use this method to trigger that firing. Note that any actor 571 * that fires at microstep 0 is expected to not produce any output 572 * events at that firing. 573 * @param actor The actor scheduled to be fired. 574 * @param time The requested time. 575 * @param index The microstep. 576 * @return An instance of Time with value NEGATIVE_INFINITY, or 577 * if there is an executive director, the time at which the 578 * container of this director will next be fired 579 * in response to this request. 580 * @see #fireAtCurrentTime(Actor) 581 * @exception IllegalActionException If there is an executive director 582 * and it throws it. Derived classes may choose to throw this 583 * exception for other reasons. 584 */ 585 @Override 586 public Time fireAt(Actor actor, Time time, int index) 587 throws IllegalActionException { 588 if (_eventQueue == null) { 589 throw new IllegalActionException(this, 590 "Calling fireAt() before preinitialize()."); 591 } 592 if (_debugging) { 593 _debug("DEDirector: Actor " + actor.getFullName() 594 + " requests refiring at " + time + " with microstep " 595 + index); 596 } 597 // Normally, we do not need to delegate the request up 598 // the hierarchy. This will be done in postfire. 599 // We want to keep event queues at all levels in hierarchy 600 // as short as possible. So, this pure event is not reported 601 // to the higher level in hierarchy immediately. The postfire 602 // method of this director will report the next 603 // earliest event in the event queue to the higher level. 604 // However, if this request is occurring between iterations within 605 // an opaque composite actor, then postfire() will not 606 // be invoked again to pass this fireAt() request up 607 // the hierarchy to the executive director. We 608 // have to pass it up here. We need to do this before 609 // enqueueing the local event because the enclosing director 610 // may return a different time from the one we specified. 611 // We would like to prevent time from advancing while this request 612 // is passed up the chain. Otherwise, the enclosing executive 613 // director could respond to the fireAt() request before we 614 // get our own request posted on the event queue. This has the 615 // unfortunate cost of resulting in multiple nested synchronized 616 // blocks being possible, which will almost certainly trigger a 617 // deadlock. Hence, we cannot do the following within the synchronized 618 // block. Instead, we have to check for the error after the synchronized 619 // block and throw an exception. 620 Time result = time; 621 if (_delegateFireAt) { 622 if (result.compareTo(getModelTime()) < 0) { 623 // NOTE: There is no assurance in a multithreaded situation 624 // that time will not advance prior to the posting of 625 // this returned time on the local event queue, so 626 // an exception can still occur reporting an attempt 627 // to post an event in the past. 628 result = getModelTime(); 629 } 630 CompositeActor container = (CompositeActor) getContainer(); 631 if (_debugging) { 632 _debug("DEDirector: Requests refiring of container: " 633 + container.getName() + " at time " + time 634 + " with microstep " + index); 635 } 636 // Enqueue a pure event to fire the container of this director. 637 // Note that if the enclosing director is ignoring fireAt(), 638 // or if it cannot refire at exactly the requested time, 639 // then the following will throw an exception. 640 result = fireContainerAt(result, index); 641 } 642 synchronized (_eventQueueLock) { 643 if (!_delegateFireAt) { 644 // If we have not made a request to the executive director, 645 // then we can modify time here. If we have, then we can't, 646 // but if the time of that request is now in the past, 647 // we will throw an exception with an attempt to post 648 // an event in the past. 649 if (result.compareTo(getModelTime()) < 0) { 650 // NOTE: There is no assurance in a multithreaded situation 651 // that time will not advance prior to the posting of 652 // this returned time on the local event queue, so 653 // an exception can still occur reporting an attempt 654 // to post an event in the past. 655 result = getModelTime(); 656 } 657 } 658 if (result.compareTo(getModelTime()) == 0 && index <= _microstep 659 && !_isInitializing) { 660 // NOTE: Incrementing the microstep here is wrong if we are in initialize(). 661 index = _microstep + 1; 662 663 if (index == Integer.MAX_VALUE) { 664 throw new IllegalActionException(this, actor, 665 "Microstep has hit the maximum while scheduling a firing of " 666 + actor.getFullName() 667 + ". Perhaps the model has a stuttering Zeno Condition?"); 668 } 669 } 670 671 _enqueueEvent(actor, result, index); 672 673 // Findbugs: Multithreaded correctness, 674 // [M M MWN] Mismatched notify() [MWN_MISMATCHED_NOTIFY] 675 // This method calls Object.notify() or Object.notifyAll() 676 // without obviously holding a lock on the object. 677 // Calling notify() or notifyAll() without a lock 678 // held will result in an IllegalMonitorStateException 679 // being thrown. 680 // Actually, this seems to be Find Bugs error since the 681 // statement is within a synchronized (_eventQueueLock) block. 682 _eventQueueLock.notifyAll(); 683 } 684 return result; 685 } 686 687 /** Fire the actor actor at the current model time or, if synchronizeToRealTime 688 * is enabled and we are past the initialization phase of execution, 689 * then fire the actor at the model time that corresponds to the current 690 * real time. This model time is computed by subtracting the model start time 691 * recorded by this director at the beginning of the simulation from the 692 * system time and dividing by 1000, as the default unit of time is seconds. 693 * @param actor The actor to be fired. 694 * @return The model time the actor will be fired at. 695 * @exception IllegalActionException If thrown while creating a Time object 696 * or while calling fireAt. 697 */ 698 @Override 699 public Time fireAtCurrentTime(Actor actor) throws IllegalActionException { 700 if (_synchronizeToRealTime && !_isInitializing) { 701 long elapsedTime = elapsedTimeSinceStart(); 702 // NOTE: The Time constructor that takes a long argument interprets 703 // that long as a multiple of the time resolution. 704 // Hence, we use the static milliseconds() method. 705 Time modelTimeForCurrentRealTime = Time.milliseconds(this, 706 elapsedTime); 707 return fireAt(actor, modelTimeForCurrentRealTime); 708 } else { 709 // NOTE: We do not need to override the functionality of 710 // fireAtCurrentTime(Actor) because in 711 // the base class it does the right thing. In particular, it attempts 712 // to fire at the time returned by getModelTime(), but if by the time 713 // it enters the synchronized block that time is in the past, it 714 // adjusts the time to match current time. This is exactly what 715 // fireAtCurrentTime(Actor) should do. 716 return super.fireAtCurrentTime(actor); 717 } 718 } 719 720 /** Schedule an actor to be fired in the specified time relative to 721 * the current model time. 722 * @param actor The scheduled actor to fire. 723 * @param time The scheduled time to fire. 724 * @exception IllegalActionException If the specified time contains 725 * a negative time value, or event queue is not ready. 726 */ 727 public void fireAtRelativeTime(Actor actor, Time time) 728 throws IllegalActionException { 729 fireAt(actor, time.add(getModelTime())); 730 } 731 732 /** Return a causality interface for the composite actor that 733 * contains this director. This base class returns an 734 * instance of {@link CausalityInterfaceForComposites}, but 735 * subclasses may override this to return a domain-specific 736 * causality interface. 737 * @return A representation of the dependencies between input ports 738 * and output ports of the container. 739 */ 740 @Override 741 public CausalityInterface getCausalityInterface() { 742 return new DECausalityInterface((Actor) getContainer(), 743 defaultDependency()); 744 } 745 746 /** Get the current microstep. 747 * @return microstep of the current time. 748 * @see #getIndex() 749 * @see #setIndex(int) 750 * @see ptolemy.actor.SuperdenseTimeDirector 751 */ 752 public int getMicrostep() { 753 return _microstep; 754 } 755 756 /* Return the event queue. Note that this method is not synchronized. 757 * Any further accesses to this event queue needs synchronization. 758 * @return The event queue. 759 */ 760 /* Appears to not be used, and seems dangerous anyway 761 * since accesses to the event queue need to be synchronized. 762 public DEEventQueue getEventQueue() { 763 return _eventQueue; 764 } 765 */ 766 767 /** Return the timestamp of the next event in the queue. 768 * The next iteration time, for example, is used to estimate the 769 * run-ahead time, when a continuous time composite actor is embedded 770 * in a DE model. If there is no event in the event queue, a positive 771 * infinity object is returned. 772 * @return The time stamp of the next event in the event queue. 773 * @exception IllegalActionException If Time object cannot be created. 774 */ 775 @Override 776 public Time getModelNextIterationTime() throws IllegalActionException { 777 Time aFutureTime = Time.POSITIVE_INFINITY; 778 779 synchronized (_eventQueueLock) { 780 // Record the model next iteration time as the tag of the the earliest 781 // event in the queue. 782 if (_eventQueue.size() > 0) { 783 aFutureTime = _eventQueue.get().timeStamp(); 784 } 785 786 // Iterate the event queue to find the earliest event with a bigger tag 787 // ((either timestamp or microstop). If such an event exists, 788 // use its time as the model next iteration time. If no such event 789 // exists, it means that the model next iteration time still needs to 790 // be resolved. In other words, the model next iteration time is 791 // just the current time. 792 Object[] events = _eventQueue.toArray(); 793 for (Object event2 : events) { 794 DEEvent event = (DEEvent) event2; 795 Time eventTime = event.timeStamp(); 796 int eventMicrostep = event.microstep(); 797 if (eventTime.compareTo(getModelTime()) > 0 798 || eventMicrostep > _microstep) { 799 aFutureTime = eventTime; 800 break; 801 } 802 } 803 } 804 // Go through hierarchy to find the minimum step. 805 Director executiveDirector = ((CompositeActor) getContainer()) 806 .getExecutiveDirector(); 807 // Some composites, such as RunCompositeActor want to be treated 808 // as if they are at the top level even though they have an executive 809 // director, so be sure to check _isTopLevel(). 810 if (executiveDirector != null && !_isTopLevel()) { 811 812 Time aFutureTimeOfUpperLevel = localClock 813 .getLocalTimeForEnvironmentTime( 814 executiveDirector.getModelNextIterationTime()); 815 816 if (aFutureTime.compareTo(aFutureTimeOfUpperLevel) > 0) { 817 aFutureTime = aFutureTimeOfUpperLevel; 818 } 819 } 820 821 return aFutureTime; 822 } 823 824 /** Return the timestamp of the next event in the queue. This is 825 * different from getModelNextIterationTime as it just considers 826 * the local event queue and not that of directors higher up in 827 * the model hierarchy. 828 * @return The timestamp of the next event in the local event 829 * queue. 830 */ 831 public Time getNextEventTime() { 832 if (_eventQueue.size() == 0) { 833 return null; 834 } 835 return _eventQueue.get().timeStamp(); 836 } 837 838 /** Return the start time parameter value. 839 * <p> 840 * When the start time is too big, the double representation loses 841 * the specified time resolution. To avoid this loss, use the 842 * {@link #getModelStartTime()} instead.</p> 843 * @return the start time. 844 * @exception IllegalActionException If the enclosing director throws it. 845 * @deprecated As Ptolemy II 4.1, use {@link #getModelStartTime()} 846 * instead. 847 */ 848 @Deprecated 849 @Override 850 public final double getStartTime() throws IllegalActionException { 851 // This method is final for performance reason. 852 return getModelStartTime().getDoubleValue(); 853 } 854 855 /** Return the stop time. 856 * <p> 857 * When the stop time is too big, the double representation loses 858 * the specified time resolution. To avoid this loss, use the 859 * {@link #getModelStopTime()} instead.</p> 860 * @return the stop time. 861 * @exception IllegalActionException If getModelStopTime() throws it. 862 * @deprecated As Ptolemy II 4.1, use {@link #getModelStopTime()} 863 * instead. 864 */ 865 @Deprecated 866 @Override 867 public final double getStopTime() throws IllegalActionException { 868 // This method is final for performance reason. 869 return getModelStopTime().getDoubleValue(); 870 } 871 872 /** Return a superdense time index for the current time, 873 * where the index is equal to the microstep. 874 * @return A superdense time index. 875 * @see #setIndex(int) 876 * @see ptolemy.actor.SuperdenseTimeDirector 877 */ 878 @Override 879 public int getIndex() { 880 return _microstep; 881 } 882 883 /** Initialize all the contained actors by invoke the initialize() method 884 * of the super class. If any events are generated during the 885 * initialization, and the container is not at the top level, request a 886 * refiring. 887 * <p> 888 * The real start time of the model is recorded when this method 889 * is called. This method is <i>not</i> synchronized on the workspace, 890 * so the caller should be.</p> 891 * 892 * @exception IllegalActionException If the initialize() method of 893 * the super class throws it. 894 */ 895 @Override 896 public void initialize() throws IllegalActionException { 897 _isInitializing = true; 898 899 synchronized (_eventQueueLock) { 900 _eventQueue.clear(); 901 902 // Reset the following private variables. 903 _disabledActors = null; 904 _exceedStopTime = false; 905 _noMoreActorsToFire = false; 906 _stopFireRequested = false; 907 908 // Initialize the microstep to zero, even though 909 // DE normally wants to run with microstep 1 or higher. 910 // During initialization, some contained actors will request 911 // firings. One of those might be a Continuous subsystem, 912 // which will explicitly request a firing at microstep 0. 913 // Others will have their requests automatically set 914 // to microstep 1. Thus, with normal DE-only models, 915 // the only events in the event queue after initialization 916 // will all have microstep 1, and hence that is where the 917 // simulation will start. 918 _microstep = 0; 919 // This could be getting re-initialized during execution 920 // (e.g., if we are inside a modal model), in which case, 921 // if the enclosing director is a superdense time director, 922 // we should initialize to its microstep, not to our own. 923 // NOTE: Some (weird) directors pretend they are not embedded even 924 // if they are (e.g. in Ptides), so we call _isEmbedded() to give 925 // the subclass the option of pretending it is not embedded. 926 if (isEmbedded()) { 927 Nameable container = getContainer(); 928 if (container instanceof CompositeActor) { 929 Director executiveDirector = ((CompositeActor) container) 930 .getExecutiveDirector(); 931 // Some composites, such as RunCompositeActor want to be treated 932 // as if they are at the top level even though they have an executive 933 // director, so be sure to check _isTopLevel(). 934 if (executiveDirector instanceof SuperdenseTimeDirector 935 && !_isTopLevel()) { 936 _microstep = ((SuperdenseTimeDirector) executiveDirector) 937 .getIndex(); 938 } 939 } 940 } 941 } 942 // Release lock to invoke super.initialize(), because that invokes 943 // actors and they may need to post events. 944 super.initialize(); 945 946 synchronized (_eventQueueLock) { 947 // Register the stop time as an event such that the model is 948 // guaranteed to stop at that time. This event also serves as 949 // a guideline for an embedded Continuous model to know how much 950 // further to integrate into future. But only do this if the 951 // stop time is finite. 952 Time stopTime = getModelStopTime(); 953 if (!stopTime.isPositiveInfinite()) { 954 fireAt((Actor) getContainer(), stopTime, 1); 955 } 956 957 if (isEmbedded() && !_eventQueue.isEmpty()) { 958 // If the event queue is not empty and the container is not at 959 // the top level, ask the upper level director in the 960 // hierarchy to refire the container at the timestamp of 961 // the earliest event of the local event queue. 962 // This design allows the upper level director to keep a 963 // relatively short event queue. 964 _requestFiring(); 965 // Indicate that fireAt() request should be passed 966 // up the chain if they are made before the next iteration. 967 _delegateFireAt = true; 968 } else { 969 _delegateFireAt = false; 970 } 971 972 _isInitializing = false; 973 } 974 } 975 976 /** Indicate that a schedule for the model may no longer be valid. 977 * This forces the actor depths to be recalculated the next time 978 * they are accessed. 979 */ 980 @Override 981 public void invalidateSchedule() { 982 CompositeActor container = (CompositeActor) getContainer(); 983 CausalityInterfaceForComposites causality = (CausalityInterfaceForComposites) container 984 .getCausalityInterface(); 985 causality.invalidate(); 986 } 987 988 /** Return the object to use to obtain a mutex lock on this director. 989 * This class overrides the base class to return the event queue lock object. 990 * @return An object to use to obtain a lock on this director. 991 */ 992 @Override 993 public Object mutexLockObject() { 994 return _eventQueueLock; 995 } 996 997 /** Return a new receiver of the type DEReceiver. 998 * @return A new DEReceiver. 999 */ 1000 @Override 1001 public Receiver newReceiver() { 1002 if (_debugging && _verbose) { 1003 _debug("Creating a new DE receiver."); 1004 } 1005 1006 return new DEReceiver(); 1007 } 1008 1009 /** Return false if there are no more actors to be fired or the stop() 1010 * method has been called. Otherwise, if the director is an embedded 1011 * director and the local event queue is not empty, request the executive 1012 * director to refire the container of this director at the timestamp of 1013 * the first event in the event queue. 1014 * @return True If this director will be fired again. 1015 * @exception IllegalActionException If the postfire method of the super 1016 * class throws it, or the stopWhenQueueIsEmpty parameter does not contain 1017 * a valid token, or refiring can not be requested. 1018 */ 1019 @Override 1020 public boolean postfire() throws IllegalActionException { 1021 boolean result = super.postfire(); 1022 1023 // If any output ports still have tokens to transfer, 1024 // request a refiring at the current time. 1025 CompositeActor container = (CompositeActor) getContainer(); 1026 Iterator<IOPort> outports = container.outputPortList().iterator(); 1027 boolean moreOutputsToTransfer = false; 1028 while (outports.hasNext() && !moreOutputsToTransfer) { 1029 IOPort outport = outports.next(); 1030 for (int i = 0; i < outport.getWidthInside(); i++) { 1031 if (outport.hasNewTokenInside(i)) { 1032 moreOutputsToTransfer = true; 1033 break; 1034 } 1035 } 1036 } 1037 1038 // Reset the microstep to zero if the next event is 1039 // in the future. 1040 synchronized (_eventQueueLock) { 1041 if (!_eventQueue.isEmpty() && !moreOutputsToTransfer) { 1042 DEEvent next = _eventQueue.get(); 1043 if (next.timeStamp().compareTo(getModelTime()) > 0) { 1044 _microstep = 0; 1045 } 1046 } 1047 boolean stop = ((BooleanToken) stopWhenQueueIsEmpty.getToken()) 1048 .booleanValue(); 1049 1050 // Request refiring and/or stop the model. 1051 // There are two conditions to stop the model. 1052 // 1. There are no more actors to be fired (i.e. event queue is 1053 // empty), and either of the following conditions is satisfied: 1054 // a. the stopWhenQueueIsEmpty parameter is set to true. 1055 // b. the current model time equals the model stop time. 1056 // 2. The event queue is not empty, but the current time exceeds 1057 // the stop time. 1058 if (moreOutputsToTransfer) { 1059 fireContainerAt(getModelTime()); 1060 } else if (_noMoreActorsToFire && (stop 1061 || getModelTime().compareTo(getModelStopTime()) == 0)) { 1062 if (_debugging) { 1063 _debug("No more actors to fire and time to stop."); 1064 } 1065 _exceedStopTime = true; 1066 result = false; 1067 } else if (_exceedStopTime) { 1068 // If the current time is bigger than the stop time, 1069 // stop the model execution. 1070 result = false; 1071 } else if (isEmbedded() && !_eventQueue.isEmpty()) { 1072 // If the event queue is not empty and the container is an 1073 // embedded model, ask the upper level director in the 1074 // hierarchy to refire the container at the timestamp of the 1075 // first event of the local event queue. 1076 // This design allows the upper level director (actually all 1077 // levels in hierarchy) to keep a relatively short event queue. 1078 _requestFiring(); 1079 } 1080 } 1081 if (isEmbedded()) { 1082 // Indicate that fireAt() requests should be passed up the 1083 // hierarchy if they are made before the next iteration. 1084 _delegateFireAt = true; 1085 } 1086 // NOTE: The following commented block enforces that no events with 1087 // different tags can exist in the same receiver. 1088 // This is a quite different semantics from the previous designs, 1089 // and its effects are still under investigation and debate. 1090 // // Clear all of the contained actor's input ports. 1091 // for (Iterator actors = ((CompositeActor)getContainer()) 1092 // .entityList(Actor.class).iterator(); 1093 // actors.hasNext();) { 1094 // Entity actor = (Entity)actors.next(); 1095 // Iterator ports = actor.portList().iterator(); 1096 // while (ports.hasNext()) { 1097 // IOPort port = (IOPort)ports.next(); 1098 // if (port.isInput()) { 1099 // // Clear all receivers. 1100 // Receiver[][] receivers = port.getReceivers(); 1101 // if (receivers == null) { 1102 // throw new InternalErrorException(this, null, 1103 // "port.getReceivers() returned null! " 1104 // + "This should never happen. " 1105 // + "port was '" + port + "'"); 1106 // } 1107 // for (int i = 0; i < receivers.length; i++) { 1108 // Receiver[] receivers2 = receivers[i]; 1109 // for (int j = 0; j < receivers2.length; j++) { 1110 // receivers2[j].clear(); 1111 // } 1112 // } 1113 // } 1114 // } 1115 // } 1116 return result; 1117 } 1118 1119 /** Set the model time to the outside time if this director is 1120 * not at the top level. Check the time of the next event to decide 1121 * whether to fire. Return true if there are inputs to this composite 1122 * actor, or the time of the next event is equal to the current model 1123 * time. Otherwise, return false. 1124 * <p> 1125 * Note that microsteps are not synchronized. 1126 * </p><p> 1127 * Throw an exception if the current model time is greater than the next 1128 * event time. 1129 * @return True if the composite actor is ready to fire. 1130 * @exception IllegalActionException If there is a missed event, 1131 * or the prefire method of the super class throws it, or can not 1132 * query the tokens of the input ports of the container of this 1133 * director.</p> 1134 */ 1135 @Override 1136 public boolean prefire() throws IllegalActionException { 1137 1138 // NOTE: super.prefire() is not of much use, because we want 1139 // to set current time adjusted for accumulated suspend time. 1140 1141 if (_debugging) { 1142 _debug("DEDirector: Called prefire()."); 1143 } 1144 1145 // The following call sets the local time to match 1146 // the environment time (with drift and offset taken into account), 1147 // but it does not set the microstep. We do that below. 1148 boolean newActorFromProposeTime = super.prefire(); 1149 1150 // Have to also do this for the microstep. 1151 if (isEmbedded()) { 1152 Nameable container = getContainer(); 1153 if (container instanceof CompositeActor) { 1154 Director executiveDirector = ((CompositeActor) container) 1155 .getExecutiveDirector(); 1156 // Some composites, such as RunCompositeActor want to be treated 1157 // as if they are at the top level even though they have an executive 1158 // director, so be sure to check _isTopLevel(). 1159 if (executiveDirector instanceof SuperdenseTimeDirector 1160 && !_isTopLevel()) { 1161 _microstep = ((SuperdenseTimeDirector) executiveDirector) 1162 .getIndex(); 1163 } 1164 if (_debugging) { 1165 _debug("DEDirector: Set microstep to " + _microstep); 1166 } 1167 } 1168 } 1169 1170 // A top-level DE director is always ready to fire. 1171 if (_isTopLevel()) { 1172 if (_debugging) { 1173 _debug("Prefire returns " + newActorFromProposeTime); 1174 } 1175 return true && newActorFromProposeTime; 1176 } 1177 1178 // If embedded, check the timestamp of the next event to decide 1179 // whether this director is ready to fire. 1180 synchronized (_eventQueueLock) { 1181 Time modelTime = getModelTime(); 1182 Time nextEventTime = Time.POSITIVE_INFINITY; 1183 1184 if (!_eventQueue.isEmpty()) { 1185 DEEvent nextEvent = _eventQueue.get(); 1186 nextEventTime = nextEvent.timeStamp(); 1187 } 1188 1189 // If the model time is larger (later) than the first event 1190 // in the queue, then 1191 // catch up with the current model time by discarding 1192 // the old events. Do not, however, discard events whose 1193 // index but not time has passed. 1194 while (modelTime.compareTo(nextEventTime) > 0) { 1195 DEEvent skippedEvent = _eventQueue.take(); 1196 if (_debugging) { 1197 _debug("Skipping event at time (" + nextEventTime 1198 + ") destined for actor " 1199 + skippedEvent.actor().getFullName()); 1200 } 1201 if (!_eventQueue.isEmpty()) { 1202 DEEvent nextEvent = _eventQueue.get(); 1203 nextEventTime = nextEvent.timeStamp(); 1204 } else { 1205 nextEventTime = Time.POSITIVE_INFINITY; 1206 } 1207 } 1208 } 1209 // NOTE: An alternative would be to throw an exception. This means that the 1210 // enclosing director is breaking the fireAt() contract, since 1211 // it presumably returned a value indicating it would do the 1212 // firing and then failed to do it. However, we don't do that 1213 // because the old style of modal models (in the fsm domain) 1214 // will result in this exception being thrown. The 1215 // code to do that is below. 1216 /* 1217 if (modelTime.compareTo(nextEventTime) > 0) { 1218 throw new IllegalActionException(this, 1219 "DEDirector expected to be fired at time " 1220 + nextEventTime 1221 + " but instead is being fired at time " 1222 + modelTime); 1223 } 1224 */ 1225 1226 // If model time is strictly less than the next event time, 1227 // then there are no events on the event queue with this 1228 // model time, and hence, if there are also no input events, 1229 // then there is nothing to do, and we can return false. 1230 /* The following is no longer correct. 1231 * We need to ensure that postfire() is invoked so that fireAt() 1232 * gets called. Although fireAt() should have already been called 1233 * for pending events in the event queue, it may need to be done again 1234 * because we may have been suspending when the resulting fire occurred. 1235 * EAL 9/18/09 1236 if (!nextEventTime.equals(modelTime)) { 1237 // If the event timestamp is greater than the model timestamp, 1238 // we check if there's any external input. 1239 Iterator<?> inputPorts = container.inputPortList().iterator(); 1240 boolean hasInput = false; 1241 1242 while (inputPorts.hasNext() && !hasInput) { 1243 IOPort port = (IOPort) inputPorts.next(); 1244 1245 for (int i = 0; i < port.getWidth(); i++) { 1246 if (port.hasToken(i)) { 1247 hasInput = true; 1248 break; 1249 } 1250 } 1251 } 1252 1253 if (!hasInput) { 1254 // If there is no internal event, it is not the correct 1255 // time to fire. 1256 // NOTE: This may happen because the container is statically 1257 // scheduled by its director to fire at this time. 1258 // For example, a DE model in a Giotto model. 1259 result = false; 1260 } 1261 } 1262 */ 1263 1264 if (_debugging) { 1265 _debug("Prefire returns true."); 1266 } 1267 // Indicate that fireAt requests can be handled locally because 1268 // we are within an iteration. 1269 _delegateFireAt = false; 1270 return true && newActorFromProposeTime; 1271 } 1272 1273 /** Set the current timestamp to the model start time, invoke the 1274 * preinitialize() methods of all actors deeply contained by the 1275 * container. 1276 * <p> 1277 * This method should be invoked once per execution, before any 1278 * iteration. Actors cannot produce output data in their preinitialize() 1279 * methods. If initial events are needed, e.g. pure events for source 1280 * actor, the actors should do so in their initialize() method. 1281 * </p><p> 1282 * This method is <i>not</i> synchronized on the workspace, so the 1283 * caller should be.</p> 1284 * 1285 * @exception IllegalActionException If the preinitialize() method of the 1286 * container or one of the deeply contained actors throws it, or the 1287 * parameters, minBinCount, binCountFactor, and isCQAdaptive, do not have 1288 * valid tokens. 1289 */ 1290 @Override 1291 public void preinitialize() throws IllegalActionException { 1292 if (_eventQueue != null) { 1293 // This execution may be overlapped with the previous. 1294 // See https://wiki.eecs.berkeley.edu/ptexternal/Main/Main/NotifyAll 1295 synchronized (_eventQueueLock) { 1296 _isInitializing = true; 1297 // Initialize an event queue. 1298 _eventQueue = new DECQEventQueue( 1299 ((IntToken) minBinCount.getToken()).intValue(), 1300 ((IntToken) binCountFactor.getToken()).intValue(), 1301 ((BooleanToken) isCQAdaptive.getToken()) 1302 .booleanValue()); 1303 } 1304 } else { 1305 _isInitializing = true; 1306 // Initialize an event queue. 1307 _eventQueue = new DECQEventQueue( 1308 ((IntToken) minBinCount.getToken()).intValue(), 1309 ((IntToken) binCountFactor.getToken()).intValue(), 1310 ((BooleanToken) isCQAdaptive.getToken()).booleanValue()); 1311 } 1312 // Add debug listeners. 1313 if (_debugListeners != null) { 1314 Iterator<?> listeners = _debugListeners.iterator(); 1315 1316 while (listeners.hasNext()) { 1317 DebugListener listener = (DebugListener) listeners.next(); 1318 _eventQueue.addDebugListener(listener); 1319 } 1320 } 1321 1322 // Call the preinitialize method of the super class. 1323 super.preinitialize(); 1324 1325 if (getContainer() instanceof CompositeActor) { 1326 // Tests in ptolemy/configs/test expand the configuration which 1327 // results in the ModelDirectory getting expanded. In the 1328 // ModelDirectory, the container might be an EntityLibrary. 1329 // The Ptides director is calling preinitialize() in 1330 // attributeChanged(), which means that this code gets called. 1331 1332 // Do this here so that performance measurements 1333 // clearly indicate that the cost is in static analysis 1334 // done in preinitialize. 1335 CompositeActor container = (CompositeActor) getContainer(); 1336 CausalityInterfaceForComposites causality = (CausalityInterfaceForComposites) container 1337 .getCausalityInterface(); 1338 causality.checkForCycles(); 1339 } 1340 1341 _actorsFinished = new ArrayList(); 1342 1343 if (_debugging && _verbose) { 1344 _debug("## Depths assigned to actors and ports:"); 1345 _debug(describePriorities()); 1346 } 1347 _issueExecutionAspectWarning(); 1348 } 1349 1350 /** Unregister a debug listener. If the specified listener has not 1351 * been previously registered, then do nothing. 1352 * @param listener The listener to remove from the list of listeners 1353 * to which debug messages are sent. 1354 * @see #addDebugListener(DebugListener) 1355 */ 1356 @Override 1357 public void removeDebugListener(DebugListener listener) { 1358 if (_eventQueue != null) { 1359 synchronized (_eventQueueLock) { 1360 _eventQueue.removeDebugListener(listener); 1361 } 1362 } 1363 1364 super.removeDebugListener(listener); 1365 } 1366 1367 /** Resume the execution of an actor that was previously blocked because 1368 * it didn't have all the resources it needed for execution. This method 1369 * puts an event into the queue for the current time. 1370 * 1371 * @param actor The actor that resumes execution. 1372 * @exception IllegalActionException Not thrown here but in derived classes. 1373 */ 1374 @Override 1375 public void resumeActor(NamedObj actor) throws IllegalActionException { 1376 List<DEEvent> events = _actorsInExecution.get(actor); 1377 ActorExecutionAspect aspect = getExecutionAspect(actor); 1378 if (aspect == null) { 1379 throw new IllegalActionException(this, "Cannot resume actor " 1380 + actor.getName() + " because aspect cannot be found."); 1381 } 1382 NamedObj container = aspect.getContainer(); 1383 if (container == null) { 1384 throw new IllegalActionException(this, 1385 "Cannot get container of actor " + actor.getName()); 1386 } 1387 Director director = ((CompositeActor) container).getDirector(); 1388 if (director == null) { 1389 throw new IllegalActionException(this, 1390 "Cannot get director of container " + container.getName() 1391 + " of actor " + actor.getName()); 1392 } 1393 1394 Time time = director.getModelTime(); 1395 DEEvent event = events.get(0); 1396 events.remove(event); 1397 _actorsInExecution.put((Actor) actor, events); 1398 1399 if (event.ioPort() != null) { 1400 _enqueueTriggerEvent(event.ioPort(), time); 1401 } else { 1402 _enqueueEvent((Actor) actor, time, 1); 1403 } 1404 fireContainerAt(time); 1405 if (_actorsFinished == null) { 1406 _actorsFinished = new ArrayList(); 1407 } 1408 _actorsFinished.add((Actor) actor); 1409 } 1410 1411 /** Set the superdense time index. This should only be 1412 * called by an enclosing director. 1413 * @exception IllegalActionException Not thrown in this base class. 1414 * @see #getIndex() 1415 * @see ptolemy.actor.SuperdenseTimeDirector 1416 */ 1417 @Override 1418 public void setIndex(int index) throws IllegalActionException { 1419 if (_debugging) { 1420 _debug("Setting superdense time index to " + index); 1421 } 1422 _microstep = index; 1423 } 1424 1425 /** Request the execution of the current iteration to stop. 1426 * This is similar to stopFire(), except that the current iteration 1427 * is not allowed to complete. This is useful if there is actor 1428 * in the model that has a bug where it fails to consume inputs. 1429 * An iteration will never terminate if such an actor receives 1430 * an event. 1431 * If the director is paused waiting for events to appear in the 1432 * event queue, then it stops waiting, and calls stopFire() for all actors 1433 * that are deeply contained by the container of this director. 1434 */ 1435 @Override 1436 public void stop() { 1437 if (_eventQueue != null) { 1438 synchronized (_eventQueueLock) { 1439 _stopRequested = true; 1440 _eventQueueLock.notifyAll(); 1441 } 1442 } 1443 1444 super.stop(); 1445 } 1446 1447 /** Request the execution of the current iteration to complete. 1448 * If the director is paused waiting for events to appear in the 1449 * event queue, then it stops waiting, 1450 * and calls stopFire() for all actors 1451 * that are deeply contained by the container of this director. 1452 */ 1453 @Override 1454 public void stopFire() { 1455 if (_eventQueue != null) { 1456 synchronized (_eventQueueLock) { 1457 _stopFireRequested = true; 1458 _eventQueueLock.notifyAll(); 1459 } 1460 } 1461 1462 super.stopFire(); 1463 } 1464 1465 // FIXME: it is questionable whether the multirate FSMActor and FSMDirector 1466 // should be used in DE as the default? I will say NO. 1467 1468 /** Return an array of suggested directors to use with 1469 * ModalModel. Each director is specified by its full class 1470 * name. The first director in the array will be the default 1471 * director used by a modal model. 1472 * @return An array of suggested directors to be used with ModalModel. 1473 * @see ptolemy.actor.Director#suggestedModalModelDirectors() 1474 */ 1475 @Override 1476 public String[] suggestedModalModelDirectors() { 1477 String[] defaultSuggestions = new String[2]; 1478 defaultSuggestions[1] = "ptolemy.domains.modal.kernel.MultirateFSMDirector"; 1479 defaultSuggestions[0] = "ptolemy.domains.modal.kernel.FSMDirector"; 1480 return defaultSuggestions; 1481 } 1482 1483 /** Transfer data from an input port of the container to the ports 1484 * it is connected to on the inside. This transfers at most one token 1485 * on each channel, and overrides the base class to temporarily set 1486 * the microstep to match or exceed that of the enclosing director if 1487 * the enclosing director implements SuperdenseTimeDirector. 1488 * Otherwise, it sets the microstep to match or exceed 1 1489 * to ensure that inputs are interpreted as discrete values. 1490 * @param port The port to transfer tokens from. 1491 * @return True if at least one data token is transferred. 1492 * @exception IllegalActionException If the port is not an opaque 1493 * input port. 1494 */ 1495 @Override 1496 public boolean transferInputs(IOPort port) throws IllegalActionException { 1497 int defaultMicrostep = _defaultMicrostep; 1498 int previousMicrostep = _microstep; 1499 SuperdenseTimeDirector enclosingDirector = _enclosingSuperdenseTimeDirector(); 1500 if (enclosingDirector != null) { 1501 defaultMicrostep = enclosingDirector.getIndex(); 1502 } 1503 if (_microstep < defaultMicrostep) { 1504 try { 1505 _microstep = defaultMicrostep; 1506 return super.transferInputs(port); 1507 } finally { 1508 _microstep = previousMicrostep; 1509 } 1510 } 1511 return super.transferInputs(port); 1512 } 1513 1514 // NOTE: We used to override transferOutputs 1515 // to transfer ALL output tokens at boundary of 1516 // hierarchy to outside. See de/test/auto/transferInputsandOutputs.xml. 1517 // However, the right thing to do is to request a refiring at the current 1518 // if outputs remain to be transferred. So that's what we do now. 1519 1520 /** Invoke the wrapup method of the super class. Reset the private 1521 * state variables. 1522 * @exception IllegalActionException If the wrapup() method of 1523 * one of the associated actors throws it. 1524 */ 1525 @Override 1526 public void wrapup() throws IllegalActionException { 1527 super.wrapup(); 1528 _disabledActors = null; 1529 synchronized (_eventQueueLock) { 1530 _eventQueue.clear(); 1531 } 1532 _noMoreActorsToFire = false; 1533 _microstep = 0; 1534 } 1535 1536 /////////////////////////////////////////////////////////////////// 1537 //// protected methods //// 1538 1539 /** Perform book keeping procedures after an actor firing. 1540 * In this base class, do nothing. 1541 * @exception IllegalActionException Not thrown in this base class. 1542 * Derived classes may throw it if book keeping procedures are not 1543 * successful. 1544 */ 1545 protected void _actorFired() throws IllegalActionException { 1546 } 1547 1548 /** Enforces a firing of a DE director only handles events with the 1549 * same tag. Checks what is the model time of the earliest event 1550 * in the event queue. 1551 * @return true if the earliest event in the event queue is at the 1552 * same model time as the event that was just processed. Else if 1553 * that event's timestamp is in the future, return false. 1554 * @exception IllegalActionException If model time is set backwards. 1555 */ 1556 protected boolean _checkForNextEvent() throws IllegalActionException { 1557 // The following code enforces that a firing of a 1558 // DE director only handles events with the same tag. 1559 // If the earliest event in the event queue is in the future, 1560 // this code terminates the current iteration. 1561 // This code is applied on both embedded and top-level directors. 1562 synchronized (_eventQueueLock) { 1563 if (!_eventQueue.isEmpty()) { 1564 DEEvent next = _eventQueue.get(); 1565 1566 if (next.timeStamp().compareTo(getModelTime()) > 0) { 1567 // If the next event is in the future time, 1568 // jump out of the big while loop in fire() and 1569 // proceed to postfire(). 1570 return false; 1571 } else if (next.microstep() > _microstep) { 1572 // If the next event has a bigger microstep, 1573 // jump out of the big while loop in fire() and 1574 // proceed to postfire(). 1575 return false; 1576 } else if (next.timeStamp().compareTo(getModelTime()) < 0 1577 || next.microstep() < _microstep) { 1578 throw new IllegalActionException( 1579 "The tag of the next event (" + next.timeStamp() 1580 + "." + next.microstep() 1581 + ") can not be less than" 1582 + " the current tag (" + getModelTime() 1583 + "." + _microstep + ") !"); 1584 } else { 1585 // The next event has the same tag as the current tag, 1586 // indicating that at least one actor is going to be 1587 // fired at the current iteration. 1588 // Continue the current iteration. 1589 } 1590 } 1591 } 1592 return true; 1593 } 1594 1595 /** Disable the specified actor. All events destined to this actor 1596 * will be ignored. If the argument is null, then do nothing. 1597 * @param actor The actor to disable. 1598 */ 1599 protected void _disableActor(Actor actor) { 1600 if (actor != null) { 1601 if (_debugging) { 1602 _debug("Actor ", ((Nameable) actor).getName(), " is disabled."); 1603 } 1604 1605 if (_disabledActors == null) { 1606 _disabledActors = new HashSet<Actor>(); 1607 } 1608 1609 _disabledActors.add(actor); 1610 } 1611 } 1612 1613 /** Put a pure event into the event queue to schedule the given actor to 1614 * fire at the specified timestamp. 1615 * <p> 1616 * The default microstep for the queued event is equal to one, 1617 * unless the time is equal to the current time, where the microstep 1618 * will be the current microstep plus one. 1619 * </p><p> 1620 * The depth for the queued event is the minimum of the depths of 1621 * all the ports of the destination actor. 1622 * </p><p> 1623 * If there is no event queue or the given actor is disabled, then 1624 * this method does nothing.</p> 1625 * 1626 * @param actor The actor to be fired. 1627 * @param time The timestamp of the event. 1628 * @param defaultMicrostep If the requested firing time is in the future, 1629 * then use this defaultMicrostep for the microstep. 1630 * @exception IllegalActionException If the time argument is less than 1631 * the current model time, or the depth of the actor has not be calculated, 1632 * or the new event can not be enqueued. 1633 */ 1634 protected void _enqueueEvent(Actor actor, Time time, int defaultMicrostep) 1635 throws IllegalActionException { 1636 if (_eventQueue == null 1637 || _disabledActors != null && _disabledActors.contains(actor)) { 1638 return; 1639 } 1640 1641 // Adjust the microstep if it is less than or equal to the current 1642 // microstep. 1643 int microstep = defaultMicrostep; 1644 if (time.compareTo(getModelTime()) == 0 && microstep <= _microstep) { 1645 // If during initialization, do not increase the microstep. 1646 // This is based on the assumption that an actor only requests 1647 // one firing during initialization. In fact, if an actor requests 1648 // several firings at the same time, 1649 // only the first request will be granted. 1650 if (!_isInitializing) { 1651 microstep = _microstep + 1; 1652 1653 if (microstep == Integer.MAX_VALUE) { 1654 throw new IllegalActionException(this, actor, 1655 "Microstep has hit the maximum while scheduling a firing of " 1656 + actor.getFullName() 1657 + ". Perhaps the model has a stuttering Zeno Condition?"); 1658 } 1659 } 1660 } else if (time.compareTo(getModelTime()) < 0) { 1661 throw new IllegalActionException(actor, 1662 "Attempt to queue an event in the past:" 1663 + " Current time is " + getModelTime() 1664 + " while event time is " + time); 1665 } 1666 1667 int depth = _getDepthOfActor(actor); 1668 1669 if (_debugging) { 1670 _debug("DEDirector: enqueue a pure event: ", 1671 ((NamedObj) actor).getName(), 1672 "time = " + time + " microstep = " + microstep + " depth = " 1673 + depth); 1674 } 1675 1676 DEEvent newEvent = new DEEvent(actor, time, microstep, depth); 1677 synchronized (_eventQueueLock) { 1678 _eventQueue.put(newEvent); 1679 } 1680 } 1681 1682 /** Put a trigger event into the event queue. A trigger event is 1683 * an event destined for the specified port that will convey 1684 * data to that port at the current time and microstep. 1685 * The depth for the queued event is the 1686 * depth of the destination IO port. The microstep of 1687 * the enqueued event will be the greater of the current 1688 * microstep and 1. That is, an event destined for a port 1689 * is never queued with microstep less than 1. 1690 * <p> 1691 * If the event queue is not ready or the actor containing the destination 1692 * port is disabled, do nothing. 1693 * 1694 * @param ioPort The destination IO port. 1695 * @exception IllegalActionException If the time argument is not the 1696 * current time, or the depth of the given IO port has not be calculated, 1697 * or the new event can not be enqueued. 1698 */ 1699 protected void _enqueueTriggerEvent(IOPort ioPort) 1700 throws IllegalActionException { 1701 _enqueueTriggerEvent(ioPort, localClock.getLocalTime()); 1702 } 1703 1704 /** Put a trigger event into the event queue with a timestamp that can be 1705 * different from the current model time. 1706 * Only resource schedulers can enqueue trigger events with future timestamps. 1707 * @param ioPort The destination IO port. 1708 * @param time The timestamp of the new event. 1709 * @exception IllegalActionException If the time argument is not the 1710 * current time, or the depth of the given IO port has not be calculated, 1711 * or the new event can not be enqueued. 1712 */ 1713 private void _enqueueTriggerEvent(IOPort ioPort, Time time) 1714 throws IllegalActionException { 1715 Actor actor = (Actor) ioPort.getContainer(); 1716 if (_eventQueue == null 1717 || _disabledActors != null && _disabledActors.contains(actor)) { 1718 return; 1719 } 1720 1721 /* NOTE: We would like to throw an exception if the microstep is 1722 * zero, but this breaks models with CT inside DE. 1723 * The CTDirector does not have a notion of superdense time. 1724 * Ideally, we could detect that is coming from a submodel that 1725 * does not implement SuperdenseTimeDirector, and hence doesn't 1726 * know any better. 1727 * Unfortunately, it is rather difficult to determine where 1728 * the event originated, since it could have come from arbitrarily 1729 * deep in the hierarchy. At a minimum, this would create 1730 * a dependency on domains/modal. 1731 */ 1732 if (_microstep < 1 && _enforceMicrostepSemantics) { 1733 throw new IllegalActionException(this, ioPort.getContainer(), 1734 "Received a non-discrete event at port " + ioPort.getName() 1735 + " of actor " + ioPort.getContainer().getName() 1736 + ". Discrete events are required to have microstep greater than zero," 1737 + " but this one has microstep " + _microstep 1738 + ". Perhaps a Continuous submodel is sending a continuous rather than" 1739 + " discrete signal?"); 1740 } 1741 int depth = _getDepthOfIOPort(ioPort); 1742 1743 int microstep = _microstep; 1744 if (microstep < 1) { 1745 microstep = 1; 1746 } 1747 1748 if (_aspectsPresent) { 1749 if (_aspectForActor.get(actor) != null 1750 && _aspectForActor.get(actor).isWaitingForResource(actor)) { 1751 Object[] eventArray = _eventQueue.toArray(); 1752 for (Object object : eventArray) { 1753 DEEvent event = (DEEvent) object; 1754 if (event.actor().equals(actor)) { 1755 if (event.timeStamp().compareTo(time) == 0 1756 && event.microstep() == 1) { 1757 microstep = microstep + 1; 1758 } else if (event.timeStamp().compareTo(time) < 0) { 1759 time = event.timeStamp(); 1760 microstep = microstep + 1; 1761 } 1762 } 1763 } 1764 } 1765 } 1766 1767 if (_debugging) { 1768 _debug("enqueue a trigger event for ", ((NamedObj) actor).getName(), 1769 " time = " + time + " microstep = " + microstep 1770 + " depth = " + depth); 1771 } 1772 1773 // Register this trigger event. 1774 DEEvent newEvent = new DEEvent(ioPort, time, microstep, depth); 1775 synchronized (_eventQueueLock) { 1776 _eventQueue.put(newEvent); 1777 } 1778 } 1779 1780 /** Advance the current model tag to that of the earliest event in 1781 * the event queue, and fire all actors that have requested or 1782 * are triggered to be fired at the current tag. If 1783 * <i>synchronizeToRealTime</i> is true, then before firing, wait 1784 * until real time matches or exceeds the timestamp of the 1785 * event. Note that the default unit for time is seconds. 1786 * <p> 1787 * Each actor is fired repeatedly (prefire(), fire()), 1788 * until either it has no more input tokens, or its prefire() method 1789 * returns false. Note that if the actor fails to consume its 1790 * inputs, then this can result in an infinite loop. 1791 * Each actor that is fired is then postfired once at the 1792 * conclusion of the iteration. 1793 * </p><p> 1794 * If there are no events in the event queue, then the behavior 1795 * depends on the <i>stopWhenQueueIsEmpty</i> parameter. If it is 1796 * false, then this thread will stall until events become 1797 * available in the event queue. Otherwise, time will advance to 1798 * the stop time and the execution will halt.</p> 1799 * 1800 * @return 0 if firing was successful, and the next event in event 1801 * queue should be checked for processing; 1802 * -1 if there's no actor to fire, and we should not keep firing; 1803 * 1 if there's no actor to fire, but the next event should be 1804 * checked for processing. 1805 * @exception IllegalActionException If the firing actor throws it, or 1806 * event queue is not ready, or an event is missed, or time is set 1807 * backwards. 1808 */ 1809 protected int _fire() throws IllegalActionException { 1810 // Find the next actor to be fired. 1811 Actor actorToFire = _getNextActorToFire(); 1812 1813 // Check whether the actor to be fired is null. 1814 // -- If the actor to be fired is null, 1815 // There are two conditions that the actor to be fired 1816 // can be null. 1817 if (actorToFire == null) { 1818 if (_isTopLevel()) { 1819 // Case 1: 1820 // If this director is an executive director at 1821 // the top level, a null actor means that there are 1822 // no events in the event queue. 1823 if (_debugging) { 1824 _debug("No more events in the event queue."); 1825 } 1826 1827 // Setting the following variable to true makes the 1828 // postfire method return false. 1829 // Do not do this if _stopFireRequested is true, 1830 // since there may in fact be actors to fire, but 1831 // their firing has been deferred. 1832 if (!_stopFireRequested) { 1833 _noMoreActorsToFire = true; 1834 } 1835 } else { 1836 // Case 2: 1837 // If this director belongs to an opaque composite model, 1838 // which is not at the top level, the director may be 1839 // invoked by an update of an external parameter port. 1840 // Therefore, no actors contained by the composite model 1841 // need to be fired. 1842 // NOTE: There may still be events in the event queue 1843 // of this director that are scheduled for future firings. 1844 if (_debugging) { 1845 _debug("No actor requests to be fired " 1846 + "at the current tag."); 1847 } 1848 } 1849 // Nothing more needs to be done in the current iteration. 1850 // Simply return. 1851 // Since we are now actually stopping the firing, we can set this false. 1852 _stopFireRequested = false; 1853 return -1; 1854 } 1855 1856 // NOTE: Here we used to check to see whether 1857 // the actor to be fired is the container of this director, 1858 // and if so, return to give the outside domain a chance to react 1859 // to that event. This strategy assumed that the 1860 // topological sort would always assign the composite actor the 1861 // lowest priority, which would guarantee that all the inside actors 1862 // have fired (reacted to their triggers) before the composite 1863 // actor is what is returned. However, the priority no longer 1864 // seems to always be lower. A better strategy is to continue 1865 // firing until we have exhausted all events with the current 1866 // tag and microstep. 1867 if (actorToFire == getContainer()) { 1868 /* What we used to do (before 5/17/09): 1869 // Since we are now actually stopping the firing, we can set this false. 1870 _stopFireRequested = false; 1871 return; 1872 */ 1873 return 1; 1874 } 1875 1876 if (_debugging) { 1877 _debug("****** Actor to fire: " + actorToFire.getFullName()); 1878 } 1879 1880 // Keep firing the actor to be fired until there are no more input 1881 // tokens available in any of its input ports with the same tag, or its prefire() 1882 // method returns false. 1883 boolean refire; 1884 1885 do { 1886 refire = false; 1887 1888 // NOTE: There are enough tests here against the 1889 // _debugging variable that it makes sense to split 1890 // into two duplicate versions. 1891 if (_debugging) { 1892 // Debugging. Report everything. 1893 // If the actor to be fired is not contained by the container, 1894 // it may just be deleted. Put this actor to the 1895 // list of disabled actors. 1896 if (!((CompositeEntity) getContainer()) 1897 .deepContains((NamedObj) actorToFire)) { 1898 _debug("Actor no longer under the control of this director. Disabling actor."); 1899 _disableActor(actorToFire); 1900 break; 1901 } 1902 1903 _debug(new FiringEvent(this, actorToFire, 1904 FiringEvent.BEFORE_PREFIRE)); 1905 1906 if (!actorToFire.prefire()) { 1907 _debug("*** Prefire returned false."); 1908 break; 1909 } 1910 1911 _debug(new FiringEvent(this, actorToFire, 1912 FiringEvent.AFTER_PREFIRE)); 1913 1914 _debug(new FiringEvent(this, actorToFire, 1915 FiringEvent.BEFORE_FIRE)); 1916 1917 actorToFire.fire(); 1918 _debug(new FiringEvent(this, actorToFire, 1919 FiringEvent.AFTER_FIRE)); 1920 1921 _debug(new FiringEvent(this, actorToFire, 1922 FiringEvent.BEFORE_POSTFIRE)); 1923 1924 if (!actorToFire.postfire()) { 1925 _debug("*** Postfire returned false:", 1926 ((Nameable) actorToFire).getName()); 1927 1928 // This actor requests not to be fired again. 1929 _disableActor(actorToFire); 1930 break; 1931 } 1932 1933 _debug(new FiringEvent(this, actorToFire, 1934 FiringEvent.AFTER_POSTFIRE)); 1935 } else { 1936 // No debugging. 1937 // If the actor to be fired is not contained by the container, 1938 // it may just be deleted. Put this actor to the 1939 // list of disabled actors. 1940 if (!((CompositeEntity) getContainer()) 1941 .deepContains((NamedObj) actorToFire)) { 1942 _disableActor(actorToFire); 1943 break; 1944 } 1945 if (!actorToFire.prefire()) { 1946 break; 1947 } 1948 1949 actorToFire.fire(); 1950 // NOTE: It is the fact that we postfire actors now that makes 1951 // this director not comply with the actor abstract semantics. 1952 // However, it's quite a redesign to make it comply, and the 1953 // semantics would not be backward compatible. It really needs 1954 // to be a new director to comply. 1955 if (!actorToFire.postfire()) { 1956 // This actor requests not to be fired again. 1957 _disableActor(actorToFire); 1958 break; 1959 } 1960 1961 } 1962 1963 // Check all the input ports of the actor to see whether there 1964 // are more input tokens to be processed. 1965 // FIXME: This particular situation can only occur if either the 1966 // actor failed to consume a token, or multiple 1967 // events with the same destination were queued with the same tag. 1968 // In theory, both are errors. One possible fix for the latter 1969 // case would be to requeue the token with a larger microstep. 1970 // A possible fix for the former (if we can detect it) would 1971 // be to throw an exception. This would be far better than 1972 // going into an infinite loop. 1973 Iterator<?> inputPorts = actorToFire.inputPortList().iterator(); 1974 1975 while (inputPorts.hasNext() && !refire) { 1976 IOPort port = (IOPort) inputPorts.next(); 1977 1978 // iterate all the channels of the current input port. 1979 for (int i = 0; i < port.getWidth(); i++) { 1980 if (port.hasNewToken(i)) { 1981 if (_debugging) { 1982 _debug("Port named " + port.getName() 1983 + " still has input on channel " + i 1984 + ". Refire the actor."); 1985 } 1986 // refire only if can be scheduled. 1987 if (!_aspectsPresent || _schedule( 1988 (NamedObj) actorToFire, getModelTime())) { 1989 refire = true; 1990 1991 // Found a channel that has input data, 1992 // jump out of the for loop. 1993 break; 1994 } else if (_aspectsPresent) { 1995 if (_actorsInExecution == null) { 1996 _actorsInExecution = new HashMap(); 1997 } 1998 List<DEEvent> events = _actorsInExecution 1999 .get(actorToFire); 2000 if (events == null) { 2001 events = new ArrayList<DEEvent>(); 2002 } 2003 2004 events.add(new DEEvent(port, getModelTime(), 1, 2005 _getDepthOfActor(actorToFire))); 2006 _actorsInExecution.put(actorToFire, events); 2007 } 2008 } 2009 } 2010 } 2011 } while (refire); // close the do {...} while () loop 2012 // NOTE: On the above, it would be nice to be able to 2013 // check _stopFireRequested, but this doesn't actually work. 2014 // In particular, firing an actor may trigger a call to stopFire(), 2015 // for example if the actor makes a change request, as for example 2016 // an FSM actor will do. This will prevent subsequent firings, 2017 // incorrectly. 2018 return 0; 2019 } 2020 2021 /** Return the depth of an actor. 2022 * @param actor An actor whose depth is requested. 2023 * @return An integer indicating the depth of the given actor. 2024 * @exception IllegalActionException If the actor depth has 2025 * not been computed (this should not occur if the ioPort is under the control 2026 * of this director). 2027 */ 2028 protected int _getDepthOfActor(Actor actor) throws IllegalActionException { 2029 CompositeActor container = (CompositeActor) getContainer(); 2030 CausalityInterfaceForComposites causality = (CausalityInterfaceForComposites) container 2031 .getCausalityInterface(); 2032 return causality.getDepthOfActor(actor); 2033 } 2034 2035 /** Return the depth of an ioPort. 2036 * @param ioPort A port whose depth is requested. 2037 * @return An integer representing the depth of the specified ioPort. 2038 * @exception IllegalActionException If the ioPort does not have 2039 * a depth (this should not occur if the ioPort is under the control 2040 * of this director). 2041 */ 2042 protected int _getDepthOfIOPort(IOPort ioPort) 2043 throws IllegalActionException { 2044 CompositeActor container = (CompositeActor) getContainer(); 2045 CausalityInterfaceForComposites causality = (CausalityInterfaceForComposites) container 2046 .getCausalityInterface(); 2047 return causality.getDepthOfPort(ioPort); 2048 } 2049 2050 /** Dequeue the events that have the smallest tag from the event queue. 2051 * Return their destination actor. Advance the model tag to their tag. 2052 * If the timestamp of the smallest tag is greater than the stop time 2053 * then return null. If there are no events in the event queue, and 2054 * the stopWhenQueueIsEmpty parameter is set to true, then return null. 2055 * Both cases will have the effect of stopping the simulation. 2056 * <p> 2057 * If the stopWhenQueueIsEmpty parameter is false and the queue is empty, 2058 * then stall the current thread by calling wait() on the _eventQueue 2059 * until there are new events available. If the synchronizeToRealTime 2060 * parameter is true, then this method may suspend the calling thread 2061 * by using Object.wait(long) to let elapsed real time catch up with the 2062 * current model time.</p> 2063 * @return The next actor to be fired, which can be null. 2064 * @exception IllegalActionException If event queue is not ready, or 2065 * an event is missed, or time is set backwards. 2066 */ 2067 protected Actor _getNextActorToFire() throws IllegalActionException { 2068 if (_eventQueue == null) { 2069 throw new IllegalActionException( 2070 "Fire method called before the preinitialize method."); 2071 } 2072 2073 Actor actorToFire = null; 2074 DEEvent lastFoundEvent = null; 2075 DEEvent nextEvent = null; 2076 2077 // Keep taking events out until there are no more events that have the 2078 // same tag and go to the same destination actor, or until the queue is 2079 // empty, or until a stop is requested. 2080 // LOOPLABEL::GetNextEvent 2081 while (!_stopRequested) { 2082 // Get the next event from the event queue. 2083 if (_stopWhenQueueIsEmpty) { 2084 if (_eventQueue.isEmpty()) { 2085 // If the event queue is empty, 2086 // jump out of the loop: LOOPLABEL::GetNextEvent 2087 break; 2088 } 2089 } 2090 2091 if (isEmbedded()) { 2092 // If the director is not at the top level. 2093 if (_eventQueue.isEmpty()) { 2094 // This could happen if the container simply fires 2095 // this composite at times it chooses. Most directors 2096 // do this (SDF, SR, Continuous, etc.). It can also 2097 // happen if an input is provided to a parameter port 2098 // and the container is DE. 2099 // In all these cases, no actors inside need to be 2100 // fired. 2101 break; 2102 } 2103 // For an embedded DE director, the following code prevents 2104 // the director from reacting to future events with bigger 2105 // time values in their tags. 2106 // For a top-level DE director, there is no such constraint 2107 // because the top-level director is responsible to advance 2108 // simulation by increasing the model tag. 2109 nextEvent = _eventQueue.get(); 2110 2111 // An embedded director should process events 2112 // that only happen at the current tag. 2113 // If the event is in the past, that is an error, 2114 // because the event should have been consumed in prefire(). 2115 if (nextEvent.timeStamp().compareTo(getModelTime()) < 0) { 2116 // missed an event 2117 throw new IllegalActionException( 2118 "Fire: Missed an event: the next event tag " 2119 + nextEvent.timeStamp() + " :: " 2120 + nextEvent.microstep() 2121 + " is earlier than the current model tag " 2122 + getModelTime() + " :: " + _microstep 2123 + " !"); 2124 } 2125 2126 // If the event is in the future time, it is ignored 2127 // and will be processed later. There is some complexity 2128 // here for backward compatibility with directors that do 2129 // not support superdense time. If the enclosing director 2130 // does not support superdense time, then we ignore the 2131 // microstep. Otherwise, we require the microstep of 2132 // the event to match the microstep that was set in 2133 // prefire(), which matches the microstep of the enclosing 2134 // director. 2135 boolean microstepMatches = true; 2136 Nameable container = getContainer(); 2137 if (container instanceof CompositeActor) { 2138 Director executiveDirector = ((CompositeActor) container) 2139 .getExecutiveDirector(); 2140 // Some composites, such as RunCompositeActor want to be treated 2141 // as if they are at the top level even though they have an executive 2142 // director, so be sure to check _isTopLevel(). 2143 if (executiveDirector instanceof SuperdenseTimeDirector 2144 && !_isTopLevel()) { 2145 // If the next event microstep in the past (which it should 2146 // not be normally), then we will consider it to match. 2147 microstepMatches = nextEvent.microstep() <= _microstep; 2148 } 2149 } 2150 2151 int comparison = nextEvent.timeStamp() 2152 .compareTo(getModelTime()); 2153 if (comparison > 0 || comparison == 0 && !microstepMatches) { 2154 // reset the next event 2155 nextEvent = null; 2156 2157 // jump out of the loop: LOOPLABEL::GetNextEvent 2158 break; 2159 } 2160 } else { // if (!topLevel) 2161 // If the director is at the top level 2162 // If the event queue is empty, normally 2163 // a blocking read is performed on the queue. 2164 // However, there are two conditions that the blocking 2165 // read is not performed, which are checked below. 2166 if (_eventQueue.isEmpty()) { 2167 // The two conditions are: 2168 // 1. An actor to be fired has been found; or 2169 // 2. There are no more events in the event queue, 2170 // and the current time is equal to the stop time. 2171 if (actorToFire != null 2172 || getModelTime().equals(getModelStopTime())) { 2173 // jump out of the loop: LOOPLABEL::GetNextEvent 2174 break; 2175 } 2176 } 2177 2178 // Otherwise, if the event queue is empty, 2179 // a blocking read is performed on the queue. 2180 // stopFire() needs to also cause this to fall out! 2181 synchronized (_eventQueueLock) { 2182 while (_eventQueue.isEmpty() && !_stopRequested 2183 && !_stopFireRequested) { 2184 if (_debugging) { 2185 _debug("Queue is empty. Waiting for input events."); 2186 } 2187 2188 try { 2189 // NOTE: Release the read access held 2190 // by this thread to prevent deadlocks. 2191 // NOTE: If a ChangeRequest has been requested, 2192 // then _eventQueue.notifyAll() is called 2193 // and stopFire() is called, so we will stop 2194 // waiting for events. However, 2195 // CompositeActor used to call stopFire() before 2196 // queuing the change request, which created the risk 2197 // that the below wait() would be terminated by 2198 // a notifyAll() on _eventQueue with _stopFireRequested 2199 // having been set, but before the change request has 2200 // actually been filed. See CompositeActor.requestChange(). 2201 // Does this matter? It means that on the next invocation 2202 // of the fire() method, we could resume waiting on an empty queue 2203 // without having filed the change request. That filing will 2204 // no longer succeed in interrupting this wait, since 2205 // stopFire() has already been called. Only on the next 2206 // instance of change request would the first change 2207 // request get a chance to execute. 2208 workspace().wait(_eventQueueLock); 2209 } catch (InterruptedException e) { 2210 // If the wait is interrupted, 2211 // then stop waiting. 2212 break; 2213 } 2214 } // Close the blocking read while loop 2215 2216 // To reach this point, either the event queue is not empty, 2217 // or _stopRequested or _stopFireRequested is true, or an interrupted exception 2218 // happened. 2219 if (_eventQueue.isEmpty()) { 2220 // Stop is requested or this method is interrupted. 2221 // This can occur, for example, if a change has been requested. 2222 // jump out of the loop: LOOPLABEL::GetNextEvent 2223 return null; 2224 } 2225 // At least one event is found in the event queue. 2226 nextEvent = _eventQueue.get(); 2227 } // Close synchronized block 2228 } 2229 2230 // This is the end of the different behaviors of embedded and 2231 // top-level directors on getting the next event. 2232 // When this point is reached, the nextEvent can not be null. 2233 // In the rest of this method, this is not checked any more. 2234 2235 // If the actorToFire is null, find the destination actor associated 2236 // with the event just found. Store this event as lastFoundEvent and 2237 // go back to continue the GetNextEvent loop. 2238 // Otherwise, check whether the event just found goes to the 2239 // same actor to be fired. If so, dequeue that event and continue 2240 // the GetNextEvent loop. Otherwise, jump out of the GetNextEvent 2241 // loop. 2242 // TESTIT 2243 if (actorToFire == null) { 2244 // If the actorToFire is not set yet, 2245 // find the actor associated with the event just found, 2246 // and update the current tag with the event tag. 2247 Time currentTime; 2248 int depth = 0; 2249 try { 2250 synchronized (_eventQueueLock) { 2251 lastFoundEvent = _eventQueue.get(); 2252 currentTime = _consultTimeRegulators( 2253 lastFoundEvent.timeStamp()); 2254 2255 // NOTE: Synchronize to real time here for backward compatibility, 2256 // but the preferred way to do this is now to use a 2257 // {@link SynchronizeToRealTime} attribute, which implements the 2258 // {@link TimeRegulator} interface. 2259 if (_synchronizeToRealTime) { 2260 // If synchronized to the real time. 2261 Manager manager = ((CompositeActor) getContainer()) 2262 .getManager(); 2263 while (!_stopRequested && !_stopFireRequested) { 2264 lastFoundEvent = _eventQueue.get(); 2265 currentTime = lastFoundEvent.timeStamp(); 2266 2267 if (currentTime 2268 .compareTo(getModelStopTime()) > 0) { 2269 // Next event is past the stop time of the model. 2270 // Do not stall. 2271 break; 2272 } 2273 2274 long elapsedTime = elapsedTimeSinceStart(); 2275 2276 // NOTE: We assume that the elapsed time can be 2277 // safely cast to a double. This means that 2278 // the DE domain has an upper limit on running 2279 // time of Double.MAX_VALUE milliseconds. 2280 double elapsedTimeInSeconds = elapsedTime 2281 / 1000.0; 2282 ptolemy.actor.util.Time elapsed = new ptolemy.actor.util.Time( 2283 this, elapsedTimeInSeconds); 2284 if (currentTime.compareTo(elapsed) <= 0) { 2285 // Enough real time has passed already. Do not stall. 2286 break; 2287 } 2288 2289 // NOTE: We used to do the following, but it had a limitation. 2290 // In particular, if any user code also calculated the elapsed 2291 // time and then constructed a Time object to post an event 2292 // on the event queue, there was no assurance that the quantization 2293 // would be the same, and hence it was possible for that event 2294 // to be in the past when posted, even if done in the same thread. 2295 // To ensure that the comparison of current time against model time 2296 // always yields the same result, we have to do the comparison using 2297 // the Time class, which is what the event queue does. 2298 /* 2299 if (currentTime.getDoubleValue() <= elapsedTimeInSeconds) { 2300 break; 2301 }*/ 2302 2303 long timeToWait = (long) (currentTime 2304 .subtract(elapsed).getDoubleValue() 2305 * 1000.0); 2306 2307 if (timeToWait > 0) { 2308 if (_debugging) { 2309 _debug("Waiting for real time to pass: " 2310 + timeToWait); 2311 } 2312 2313 try { 2314 // NOTE: The built-in Java wait() method 2315 // does not release the 2316 // locks on the workspace, which would block 2317 // UI interactions and may cause deadlocks. 2318 // SOLUTION: explicitly release read permissions. 2319 depth = _workspace 2320 .releaseReadPermission(); 2321 // Allow change requests to execute immediately while we are waiting. 2322 // This will have the side effect of executing any pending change requests. 2323 setDeferringChangeRequests(false); 2324 // Tell the manager what thread is waiting. 2325 manager.setWaitingThread( 2326 Thread.currentThread()); 2327 _eventQueueLock.wait(timeToWait); 2328 } catch (InterruptedException ex) { 2329 // Ignore and circulate around the loop. 2330 // The interrupt could be due to a change request, 2331 // which we will want to process. 2332 // This used to do the following with flawed reasoning: 2333 /* 2334 throw new IllegalActionException( 2335 this, 2336 ex, 2337 "Thread interrupted when waiting for" 2338 + " real time to match model time."); 2339 */ 2340 // The reasoning was: 2341 // Continue executing? 2342 // No, because this could be a problem if any 2343 // actor assumes that model time always exceeds 2344 // real time when synchronizeToRealTime is set. 2345 // 2346 // But this is flawed because we are in a while loop 2347 // that will check again for matching to real time. 2348 // EAL 10/27/15. 2349 } finally { 2350 setDeferringChangeRequests(true); 2351 manager.setWaitingThread(null); 2352 } 2353 } 2354 } // while 2355 // If stopFire() has been called, then the wait for real 2356 // time above was interrupted by a change request. Hence, 2357 // real time will not have reached the time of the first 2358 // event in the event queue. If we allow this method to 2359 // proceed, it will set model time to that event time, 2360 // which is in the future. This violates the principle 2361 // of synchronize to real time. Hence, we must return 2362 // without processing the event or incrementing time. 2363 2364 // NOTE: CompositeActor used to call stopFire() before 2365 // queuing the change request, which created the risk 2366 // that the above wait() would be terminated by 2367 // a notifyAll() on _eventQueue with _stopFireRequested 2368 // having been set, but before the change request has 2369 // actually been filed. See CompositeActor.requestChange(). 2370 // Does this matter? It means that on the next invocation 2371 // of the fire() method, we could resume processing the 2372 // same event, waiting for real time to elapse, without 2373 // having filed the change request. That filing will 2374 // no longer succeed in interrupting this wait, since 2375 // stopFire() has already been called. Alternatively, 2376 // before we get to the wait for real time in the next 2377 // firing, the change request could complete and be 2378 // executed. 2379 if (_stopRequested || _stopFireRequested) { 2380 return null; 2381 } 2382 } // if (_synchronizeToRealTime) 2383 } // sync 2384 } finally { 2385 if (depth > 0) { 2386 _workspace.reacquireReadPermission(depth); 2387 } 2388 } 2389 2390 // Consume the earliest event from the queue. The event must be 2391 // obtained here, since a new event could have been enqueued 2392 // into the queue while the queue was waiting. Note however 2393 // that this would usually be an error. Any other thread that 2394 // posts events in the event queue should do so in a change request, 2395 // which will not be executed during the above wait. 2396 // Nonetheless, we are conservative here, and take the earliest 2397 // event in the event queue. 2398 synchronized (_eventQueueLock) { 2399 lastFoundEvent = _eventQueue.take(); 2400 currentTime = lastFoundEvent.timeStamp(); 2401 actorToFire = lastFoundEvent.actor(); 2402 2403 // NOTE: The _enqueueEvent method discards the events 2404 // for disabled actors. 2405 if (_disabledActors != null 2406 && _disabledActors.contains(actorToFire)) { 2407 // This actor has requested not to be fired again. 2408 if (_debugging) { 2409 _debug("Skipping disabled actor: ", 2410 ((Nameable) actorToFire).getFullName()); 2411 } 2412 2413 actorToFire = null; 2414 2415 // start a new iteration of the loop: 2416 // LOOPLABEL::GetNextEvent 2417 continue; 2418 } 2419 2420 // Advance the current time to the event time. 2421 // NOTE: This is the only place that the model time changes. 2422 setModelTime(currentTime); 2423 2424 // Advance the current microstep to the event microstep. 2425 _microstep = lastFoundEvent.microstep(); 2426 if (_debugging) { 2427 _debug("Current time is: (" + currentTime + ", " 2428 + _microstep + ")"); 2429 } 2430 // Exceeding stop time means the current time is strictly 2431 // bigger than the model stop time. 2432 if (currentTime.compareTo(getModelStopTime()) > 0) { 2433 if (_debugging) { 2434 _debug("Current time has passed the stop time."); 2435 } 2436 2437 _exceedStopTime = true; 2438 return null; 2439 } 2440 } 2441 } else { // i.e., actorToFire != null 2442 // In a previous iteration of this while loop, 2443 // we have already found an event and the actor to react to it. 2444 // Check whether the newly found event has the same tag 2445 // and destination actor. If so, they are 2446 // handled at the same time. For example, a pure 2447 // event and a trigger event that go to the same actor. 2448 if (nextEvent.hasTheSameTagAs(lastFoundEvent) 2449 && nextEvent.actor() == actorToFire) { 2450 // Consume the event from the queue and discard it. 2451 // In theory, there should be no event with the same depth 2452 // as well as tag because 2453 // the DEEvent class equals() method returns true in this 2454 // case, and the CalendarQueue class does not enqueue an 2455 // event that is equal to one already on the queue. 2456 // Note that the Repeat actor, for one, produces a sequence 2457 // of outputs, each of which will have the same microstep. 2458 // These reduce to a single event in the event queue. 2459 // The DEReceiver in the downstream port, however, 2460 // contains multiple tokens. When the one event on 2461 // event queue is encountered, then the actor will 2462 // be repeatedly fired until it has no more input tokens. 2463 // However, there could be events with the same tag 2464 // and different depths, e.g. a trigger event and a pure 2465 // event going to the same actor. 2466 synchronized (_eventQueueLock) { 2467 _eventQueue.take(); 2468 } 2469 } else { 2470 // Next event has a future tag or a different destination. 2471 break; 2472 } 2473 } 2474 if (actorToFire != null && _aspectsPresent) { 2475 if (_actorsFinished.contains(actorToFire)) { 2476 _actorsFinished.remove(actorToFire); 2477 } else if (!_schedule((NamedObj) actorToFire, getModelTime())) { 2478 _nextScheduleTime.get(_aspectForActor.get(actorToFire)) 2479 .add(getModelTime()); 2480 if (_actorsInExecution == null) { 2481 _actorsInExecution = new HashMap(); 2482 } 2483 List<DEEvent> events = _actorsInExecution.get(actorToFire); 2484 if (events == null) { 2485 events = new ArrayList<DEEvent>(); 2486 } 2487 events.add(lastFoundEvent); 2488 _actorsInExecution.put(actorToFire, events); 2489 actorToFire = null; 2490 } 2491 } 2492 } // close the loop: LOOPLABEL::GetNextEvent 2493 2494 // Note that the actor to be fired can be null. 2495 return actorToFire; 2496 } 2497 2498 /** In DE, a warning is issued when execution aspects are used because 2499 * these might change the DE semantics of the execution. In Ptides, 2500 * this is not the case. 2501 * @exception IllegalActionException If thrown by getExecutionAspect(). 2502 */ 2503 protected void _issueExecutionAspectWarning() 2504 throws IllegalActionException { 2505 if (_executionAspects.size() > 0) { 2506 boolean _aspectUsed = false; 2507 if (getContainer() instanceof CompositeActor) { 2508 for (Object entity : ((CompositeActor) getContainer()) 2509 .entityList()) { 2510 Actor actor = (Actor) entity; 2511 if (getExecutionAspect((NamedObj) actor) != null) { 2512 _aspectUsed = true; 2513 break; 2514 } 2515 } 2516 } 2517 if (_aspectUsed) { 2518 //if (!MessageHandler.yesNoQuestion( 2519 System.out.println( 2520 "WARNING: The execution aspects in this model can " 2521 + "influence the timing of actors by delaying the \n" 2522 + "execution, potentially changing the behavior. " 2523 + "There is no guarantee that actors fire at the \n" 2524 + "time they request to be fired. \n" 2525 + "Use Ptides for deterministic DE behavior that is " 2526 + "not influenced by execution aspects. \n"); 2527 //+ "Continue?")) { 2528 //stop(); 2529 //} 2530 } 2531 } 2532 } 2533 2534 /** There are no actor to fire. In this base class, do nothing. Subclasses 2535 * may override this method in case there is no actor to fire. 2536 * @exception IllegalActionException Not thrown in this base class. 2537 * Derived classes may throw it if unable to get the next actuation 2538 * event. 2539 */ 2540 protected void _noActorToFire() throws IllegalActionException { 2541 } 2542 2543 /** Schedule an actor for execution on a ExecutionAspect. If the actor can 2544 * execute this method returns true. If resources are not available this 2545 * method returns false. 2546 * 2547 * @param actor The actor. 2548 * @param timestamp The time the actor requests to be scheduled. 2549 * @return True if actor was scheduled and can be fired. 2550 * @exception IllegalActionException Thrown if parameters cannot be read, actor cannot be 2551 * scheduled or container cannot be fired at future time. 2552 */ 2553 @Override 2554 protected boolean _schedule(NamedObj actor, Time timestamp) 2555 throws IllegalActionException { 2556 boolean schedule = super._schedule(actor, timestamp); 2557 if (!schedule) { 2558 ActorExecutionAspect scheduler = getExecutionAspect(actor); 2559 if (scheduler != null) { 2560 ((CompositeActor) scheduler.getContainer()).getDirector() 2561 .fireAt((Actor) scheduler, getModelTime() 2562 .add(_nextScheduleTime.get(scheduler))); 2563 } else { 2564 throw new InternalErrorException(this, null, 2565 "_getExecutionAspect(" + actor.getFullName() 2566 + ") returned null?"); 2567 } 2568 } 2569 return schedule; 2570 } 2571 2572 /** Actors and their matching events currently in execution and waiting 2573 * for resources. 2574 */ 2575 protected HashMap<Actor, List<DEEvent>> _actorsInExecution; 2576 2577 /** Actors that just got granted all the resources they needed for 2578 * execution but have not actually been fired yet. After the actor 2579 * is fired, it is removed from this list. 2580 */ 2581 protected List<Actor> _actorsFinished; 2582 2583 /////////////////////////////////////////////////////////////////// 2584 //// protected variables //// 2585 2586 /** The set of actors that have returned false in their postfire() 2587 * methods. Events destined for these actors are discarded and 2588 * the actors are never fired. 2589 */ 2590 protected Set<Actor> _disabledActors; 2591 2592 /** The queue used for sorting events. */ 2593 protected DEEventQueue _eventQueue; 2594 2595 /** The lock for the queue. */ 2596 protected Object _eventQueueLock = new Object(); 2597 2598 /** A local boolean variable indicating whether this director is in 2599 * initialization phase execution. 2600 */ 2601 protected boolean _isInitializing = false; 2602 2603 /** The current microstep. */ 2604 protected int _microstep = 1; 2605 2606 /** Set to true when it is time to end the execution. */ 2607 protected boolean _noMoreActorsToFire = false; 2608 2609 /** Flag that stopFire() has been called. */ 2610 protected boolean _stopFireRequested = false; 2611 2612 /////////////////////////////////////////////////////////////////// 2613 //// private methods //// 2614 2615 /** Return the nearest enclosing director that implements 2616 * SuperdenseTimeDirector, or null if there 2617 * is none. The enclosing SuperdenseTimeDirector director is a director 2618 * above this in the hierarchy, possibly separated by composite 2619 * actors with actors that implement the QuasiTransparentDirector 2620 * interface, such as FSMDirector or CaseDirector. 2621 * @return The enclosing ContinuousDirector, or null if there is none. 2622 */ 2623 private SuperdenseTimeDirector _enclosingSuperdenseTimeDirector() { 2624 if (_enclosingSuperdenseTimeDirectorVersion != _workspace 2625 .getVersion()) { 2626 // Update the cache. 2627 _enclosingSuperdenseTimeDirector = null; 2628 NamedObj container = getContainer().getContainer(); 2629 while (container != null) { 2630 if (container instanceof Actor) { 2631 Director director = ((Actor) container).getDirector(); 2632 if (director instanceof SuperdenseTimeDirector) { 2633 _enclosingSuperdenseTimeDirector = (SuperdenseTimeDirector) director; 2634 break; 2635 } 2636 if (!(director instanceof QuasiTransparentDirector)) { 2637 break; 2638 } 2639 } 2640 container = container.getContainer(); 2641 } 2642 _enclosingSuperdenseTimeDirectorVersion = _workspace.getVersion(); 2643 } 2644 return _enclosingSuperdenseTimeDirector; 2645 } 2646 2647 /** initialize parameters. Set all parameters to their default values. 2648 */ 2649 private void _initParameters() { 2650 _verbose = true; 2651 _defaultMicrostep = 1; 2652 try { 2653 stopWhenQueueIsEmpty = new Parameter(this, "stopWhenQueueIsEmpty"); 2654 stopWhenQueueIsEmpty.setExpression("true"); 2655 stopWhenQueueIsEmpty.setTypeEquals(BaseType.BOOLEAN); 2656 2657 synchronizeToRealTime = new Parameter(this, 2658 "synchronizeToRealTime"); 2659 synchronizeToRealTime.setExpression("false"); 2660 synchronizeToRealTime.setTypeEquals(BaseType.BOOLEAN); 2661 2662 isCQAdaptive = new Parameter(this, "isCQAdaptive"); 2663 isCQAdaptive.setExpression("true"); 2664 isCQAdaptive.setTypeEquals(BaseType.BOOLEAN); 2665 isCQAdaptive.setVisibility(Settable.EXPERT); 2666 2667 minBinCount = new Parameter(this, "minBinCount"); 2668 minBinCount.setExpression("2"); 2669 minBinCount.setTypeEquals(BaseType.INT); 2670 minBinCount.setVisibility(Settable.EXPERT); 2671 2672 binCountFactor = new Parameter(this, "binCountFactor"); 2673 binCountFactor.setExpression("2"); 2674 binCountFactor.setTypeEquals(BaseType.INT); 2675 binCountFactor.setVisibility(Settable.EXPERT); 2676 2677 enforceMicrostepSemantics = new Parameter(this, 2678 "enforceMicrostepSemantics"); 2679 enforceMicrostepSemantics.setExpression("false"); 2680 enforceMicrostepSemantics.setTypeEquals(BaseType.BOOLEAN); 2681 } catch (KernelException e) { 2682 throw new InternalErrorException( 2683 "Cannot set parameter:\n" + e.getMessage()); 2684 } 2685 } 2686 2687 /** Request that the container of this director be refired in some 2688 * future time specified by the first event of the local event queue. 2689 * This method is used when the director is embedded inside an opaque 2690 * composite actor. If the queue is empty, then throw an 2691 * IllegalActionException. 2692 * @exception IllegalActionException If the queue is empty, or 2693 * if the executive director does not respect the fireAt() call. 2694 */ 2695 protected void _requestFiring() throws IllegalActionException { 2696 DEEvent nextEvent = null; 2697 synchronized (_eventQueueLock) { 2698 nextEvent = _eventQueue.get(); 2699 } 2700 2701 if (_debugging) { 2702 CompositeActor container = (CompositeActor) getContainer(); 2703 _debug("DEDirector: Requests refiring of: " + container.getName() 2704 + " at time " + nextEvent.timeStamp()); 2705 } 2706 2707 // Enqueue a pure event to fire the container of this director. 2708 fireContainerAt(nextEvent.timeStamp(), nextEvent.microstep()); 2709 } 2710 2711 /////////////////////////////////////////////////////////////////// 2712 //// private variables //// 2713 2714 /** Indicator that calls to fireAt() should be delegated 2715 * to the executive director. 2716 */ 2717 private boolean _delegateFireAt = false; 2718 2719 /** Cache for the enclosing superdense time director. */ 2720 private SuperdenseTimeDirector _enclosingSuperdenseTimeDirector; 2721 2722 /** Cache version for the enclosing superdense time director. */ 2723 private long _enclosingSuperdenseTimeDirectorVersion = -1; 2724 2725 /** Cached value of enforceMicrostepSemantics parameter. */ 2726 private boolean _enforceMicrostepSemantics = false; 2727 2728 /** Set to true when the time stamp of the token to be dequeue 2729 * has exceeded the stopTime. 2730 */ 2731 private boolean _exceedStopTime = false; 2732 2733 /** Decide whether the simulation should be stopped when there's no more 2734 * events in the global event queue. By default, its value is 'true', 2735 * meaning that the simulation will stop under that circumstances. 2736 * Setting it to 'false', instruct the director to wait on the queue 2737 * while some other threads might enqueue events in it. 2738 */ 2739 private boolean _stopWhenQueueIsEmpty = true; 2740 2741 /** Specify whether the director should wait for elapsed real time to 2742 * catch up with model time. 2743 */ 2744 private boolean _synchronizeToRealTime; 2745 2746 /////////////////////////////////////////////////////////////////// 2747 //// inner classes //// 2748 2749 /** Causality interface for the DEDirector that reflects the limitations 2750 * from not having an implementation that computes a fixed point. 2751 * Specifically, this causality interface extends CausalityInterfaceForComposites 2752 * so that it can do the depth analysis internally, but for the ports 2753 * of the container, it declares that all outputs depend on all inputs. 2754 * This is necessary to ensure that if a DE opaque composite is fired 2755 * only when all inputs at the current microstep are known. See 2756 * $PTII/ptolemy/domains/de/test/auto/DEFixedPointLimitation.xml. 2757 */ 2758 private static class DECausalityInterface 2759 extends CausalityInterfaceForComposites { 2760 // FindBugs indicates that this should be a static class. 2761 2762 /** Construct a causality interface for the specified actor. 2763 * @param actor The actor for which this is a causality interface. 2764 * This is required to be an instance of CompositeEntity. 2765 * @param defaultDependency The default dependency of an output 2766 * port on an input port. 2767 * @exception IllegalArgumentException If the actor parameter is not 2768 * an instance of CompositeEntity. 2769 */ 2770 public DECausalityInterface(Actor actor, Dependency defaultDependency) 2771 throws IllegalArgumentException { 2772 super(actor, defaultDependency); 2773 } 2774 2775 /** Return a collection of the ports in this actor that depend on 2776 * or are depended on by the specified port. A port X depends 2777 * on a port Y if X is an output and Y is an input and 2778 * getDependency(X,Y) returns oTimesIdentity() 2779 * of the default dependency specified in the constructor. 2780 * <p> 2781 * This class presumes (but does not check) that the 2782 * argument is a port contained by the associated actor. 2783 * If the actor is an input, then it returns a collection of 2784 * all the outputs. If the actor is output, then it returns 2785 * a collection of all the inputs. 2786 * @param port The port to find the dependents of. 2787 * @return a collection of ports that depend on or are depended on 2788 * by the specified port. 2789 * @exception IllegalActionException Not thrown in this base class. 2790 */ 2791 @Override 2792 public Collection<IOPort> dependentPorts(IOPort port) 2793 throws IllegalActionException { 2794 if (port.isOutput()) { 2795 if (port.isInput()) { 2796 // Port is both input and output. 2797 HashSet<IOPort> result = new HashSet<IOPort>(); 2798 result.addAll(_actor.inputPortList()); 2799 result.addAll(_actor.outputPortList()); 2800 return result; 2801 } 2802 // Port is output and not input. 2803 return _actor.inputPortList(); 2804 } else if (port.isInput()) { 2805 // Port is input and not output. 2806 return _actor.outputPortList(); 2807 } else { 2808 // Port is neither input nor output. 2809 return _EMPTY_COLLECTION; 2810 } 2811 } 2812 2813 /** Return a collection of the input ports in this actor that are 2814 * in the same equivalence class with the specified input 2815 * port. This class returns a collection of all 2816 * the input ports of the container actor. 2817 * @param input The port to find the equivalence class of. 2818 * @return set of the input ports in this actor that are 2819 * in an equivalence class with the specified input. 2820 * @exception IllegalArgumentException If the argument is not 2821 * contained by the associated actor. 2822 * @exception IllegalActionException Not thrown in this base class. 2823 */ 2824 @Override 2825 public Collection<IOPort> equivalentPorts(IOPort input) 2826 throws IllegalActionException { 2827 if (input.getContainer() != _actor || !input.isInput()) { 2828 throw new IllegalArgumentException( 2829 "equivalentPort() called with argument " 2830 + input.getFullName() 2831 + " that is not an input port for " 2832 + _actor.getFullName()); 2833 } 2834 return _actor.inputPortList(); 2835 } 2836 2837 /** Return the dependency between the specified input port 2838 * and the specified output port. This class returns 2839 * the default dependency if the first port is an input 2840 * port owned by this actor and the second one is an output 2841 * port owned by this actor. Otherwise, it returns the 2842 * additive identity of the dependency. 2843 * @param input The input port. 2844 * @param output The output port. 2845 * @return The dependency between the specified input port 2846 * and the specified output port. 2847 * @exception IllegalActionException Not thrown in this base class. 2848 */ 2849 @Override 2850 public Dependency getDependency(IOPort input, IOPort output) 2851 throws IllegalActionException { 2852 if (input.isInput() && input.getContainer() == _actor 2853 && output.isOutput() && output.getContainer() == _actor) { 2854 return _defaultDependency; 2855 } 2856 return _defaultDependency.oPlusIdentity(); 2857 } 2858 } 2859}