001/* Director for the dynamic dataflow model of computation. 002 003 Copyright (c) 2001-2015 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 027 */ 028package ptolemy.domains.ddf.kernel; 029 030import java.util.Arrays; 031import java.util.HashMap; 032import java.util.HashSet; 033import java.util.Iterator; 034import java.util.LinkedList; 035import java.util.List; 036import java.util.Set; 037 038import ptolemy.actor.Actor; 039import ptolemy.actor.Director; 040import ptolemy.actor.FiringEvent; 041import ptolemy.actor.IOPort; 042import ptolemy.actor.NoTokenException; 043import ptolemy.actor.QueueReceiver; 044import ptolemy.actor.Receiver; 045import ptolemy.actor.TypedCompositeActor; 046import ptolemy.actor.parameters.ParameterPort; 047import ptolemy.actor.util.DFUtilities; 048import ptolemy.data.ArrayToken; 049import ptolemy.data.BooleanToken; 050import ptolemy.data.IntToken; 051import ptolemy.data.Token; 052import ptolemy.data.expr.Parameter; 053import ptolemy.data.expr.Variable; 054import ptolemy.data.type.BaseType; 055import ptolemy.kernel.ComponentPort; 056import ptolemy.kernel.CompositeEntity; 057import ptolemy.kernel.Entity; 058import ptolemy.kernel.Port; 059import ptolemy.kernel.util.Attribute; 060import ptolemy.kernel.util.IllegalActionException; 061import ptolemy.kernel.util.InternalErrorException; 062import ptolemy.kernel.util.NameDuplicationException; 063import ptolemy.kernel.util.NamedObj; 064import ptolemy.kernel.util.Workspace; 065 066/////////////////////////////////////////////////////////////////// 067//// DDFDirector 068 069/** 070 The dynamic dataflow (DDF) domain is a superset of the synchronous 071 dataflow(SDF) and Boolean dataflow(BDF) domains. In the SDF domain, 072 an actor consumes and produces a fixed number of tokens per firing. 073 This static information makes possible compile-time scheduling. In the 074 DDF domain, there are few constraints on the production and consumption 075 behavior of actors, and the schedulers make no attempt to construct a 076 compile-time schedule. Instead, each actor has a set of firing rules 077 (patterns) and can be fired if one of them is satisfied, i.e., one 078 particular firing pattern forms a prefix of sequences of unconsumed 079 tokens at input ports. The canonical actors in the DDF domain include 080 Select and Switch, which consume or produce tokens on different channels 081 based on the token received from the control port. You can also use 082 the two-channel versions BooleanSelect and BooleanSwitch. 083 <p> 084 The dynamic scheduler implemented in this director fires all enabled 085 and non-deferrable actors once in a basic iteration. A deferrable 086 actor is one that will not help one of the downstream actors become 087 enabled because that downstream actor either already has enough tokens on 088 the channel connecting those two actors or is waiting for tokens on 089 another channel. If no actor fires so far, which means there is no 090 enabled and non-deferrable actor, then among all enabled and deferrable 091 actors, this director fires those which have the smallest maximum number 092 of tokens on their output channels which satisfy the demand of destination 093 actors. If still no actor fires, then there is no enabled actor. A user 094 can treat several such basic iterations as a single iteration by adding 095 a parameter with name <i>requiredFiringsPerIteration</i> to an actor 096 (which is often a sink actor or an actor directly connected to output port 097 of the composite actor) and specifying the number of times this actor must 098 be fired in a single iteration. If the value of the parameter 099 <i>runUntilDeadlockInOneIteration</i> is a BooleanToken with value true, 100 one single iteration consists of repeating the basic iteration until 101 deadlock is reached (thus overriding the previous definition of one 102 iteration), which is the status of the model where all active 103 actors under the control of this director are unable to fire because 104 their firing rules are not satisfied. However, they may be able to fire 105 again during next iteration when tokens are transferred in from an outside 106 domain. Note <i>runUntilDeadlockInOneIteration</i> can be set to true 107 only when this director is not on the top level. 108 <p> 109 The algorithm implementing one basic iteration goes like this: 110 <pre> 111 E = set of enabled actors 112 D = set of deferrable enabled actors 113 </pre> 114 One basic(default) iteration consists of: 115 <pre> 116 if (E\D != empty set) { 117 fire (E\D) 118 } else if (D != empty set) { 119 fire minimax(D) 120 } else { 121 declare deadlock 122 } 123 </pre> 124 The function "minimax(D)" returns a subset of D with the smallest 125 maximum number of tokens on their output channels which satisfy the 126 demand of destination actors. 127 <p> 128 Note that any SDF model can be run with a DDF Director. However, the 129 notion of iteration is different. One could try to imitate the SDF 130 iteration in the DDF domain by controlling the number of firings in one 131 iteration for some actors, such as requiring a plotter to plot a fixed 132 number of points in each iteration. 133 <p> 134 In the DDF domain, the firing rule of any actor is specified by the token 135 consumption rates of its input ports. A general DDF actor could change 136 the consumption rates of its input ports after each firing of this actor. 137 For multiports, an array token could be used to specify different rates 138 for different channels connected to the same multiport. Note that in SDF, 139 all channels connected to the same multiport have the same rate. 140 <p> 141 Based on DDFSimpleSched in Ptolemy Classic, by Edward Lee. 142 See E. A. Lee et al., "The Almagest," documentation for Ptolemy Classic, 143 Vol. 1, Chapter 7, 1997. 144 145 @author Gang Zhou 146 @version $Id$ 147 @since Ptolemy II 4.1 148 @Pt.ProposedRating Yellow (zgang) 149 @Pt.AcceptedRating Yellow (cxh) 150 */ 151public class DDFDirector extends Director { 152 /** Construct a director in the default workspace with an empty string 153 * as its name. The director is added to the list of objects in 154 * the workspace. Increment the version number of the workspace. 155 * @exception IllegalActionException If the name has a period in it, or 156 * the director is not compatible with the specified container. 157 * @exception NameDuplicationException If the container already contains 158 * an entity with the specified name. 159 */ 160 public DDFDirector() 161 throws IllegalActionException, NameDuplicationException { 162 super(); 163 _init(); 164 } 165 166 /** Construct a director in the workspace with an empty name. 167 * The director is added to the list of objects in the workspace. 168 * Increment the version number of the workspace. 169 * @param workspace The workspace of this object. 170 * @exception IllegalActionException If the name has a period in it, or 171 * the director is not compatible with the specified container. 172 * @exception NameDuplicationException If the container already contains 173 * an entity with the specified name. 174 */ 175 public DDFDirector(Workspace workspace) 176 throws IllegalActionException, NameDuplicationException { 177 super(workspace); 178 _init(); 179 } 180 181 /** Construct a director in the given container with the given name. 182 * The container argument must not be null, or a NullPointerException 183 * will be thrown. 184 * If the name argument is null, then the name is set to the 185 * empty string. Increment the version number of the workspace. 186 * @param container The container of this director. 187 * @param name Name of this director. 188 * @exception IllegalActionException Not thrown in this base class. 189 * May be thrown in the derived classes if the director 190 * is not compatible with the specified container. 191 * @exception NameDuplicationException If the name collides with 192 * an attribute that already exists in the given container. 193 */ 194 public DDFDirector(CompositeEntity container, String name) 195 throws IllegalActionException, NameDuplicationException { 196 super(container, name); 197 _init(); 198 } 199 200 /////////////////////////////////////////////////////////////////// 201 //// parameters //// 202 203 /** A Parameter representing the number of times that postfire() may 204 * be called before it returns false. If the value is less than or 205 * equal to zero, then the execution will never return false in 206 * postfire(), and thus the execution can continue forever or until 207 * the model is deadlocked. 208 * The default value is an IntToken with the value zero. 209 */ 210 public Parameter iterations; 211 212 /** A Parameter representing the maximum capacity of each receiver 213 * controlled by this director. This is an integer that defaults to 0, 214 * which means the queue in each receiver is unbounded. To specify 215 * bounded queues, set this to a positive integer. 216 */ 217 public Parameter maximumReceiverCapacity; 218 219 /** A parameter indicating whether one iteration consists of 220 * repeated basic iterations until deadlock. If this parameter is 221 * true, the model will be executed until deadlock in one iteration. 222 * The default value is a BooleanToken with the value false. It 223 * cannot be set to true if this director is at the top level. 224 */ 225 public Parameter runUntilDeadlockInOneIteration; 226 227 /////////////////////////////////////////////////////////////////// 228 //// public methods //// 229 230 /** If the attribute being changed is <i>runUntilDeadlockInOneIteration</i> 231 * and it is set to be true, then verify this director is not at the 232 * top level. 233 * @param attribute The changed parameter. 234 * @exception IllegalActionException If this director is at top 235 * level and <i>runUntilDeadlockInOneIteration</i> is set to be true, 236 * or getToken() throws IllegalActionException. 237 */ 238 @Override 239 public void attributeChanged(Attribute attribute) 240 throws IllegalActionException { 241 if (attribute == runUntilDeadlockInOneIteration) { 242 _runUntilDeadlock = ((BooleanToken) runUntilDeadlockInOneIteration 243 .getToken()).booleanValue(); 244 245 if (_runUntilDeadlock && _isTopLevel()) { 246 // The reason we don't allow this is because we cannot 247 // pause the model easily if the whole execution is in 248 // one iteration. And the same effect can be achieved 249 // by setting the parameter iterations to zero anyway. 250 throw new IllegalActionException(this, 251 "Cannot set runUntilDeadlockInOneIteration to be " 252 + "true if this DDFDirector is at top level. " 253 + "Instead you should set the parameter iterations " 254 + "to be zero to achieve the same effect."); 255 } 256 } else { 257 super.attributeChanged(attribute); 258 } 259 } 260 261 /** Clone the director into the specified workspace. This calls the 262 * base class and then sets the attribute public members to refer 263 * to the attributes of the new director. 264 * @param workspace The workspace for the new director. 265 * @return A new director. 266 * @exception CloneNotSupportedException If a derived class contains 267 * an attribute that cannot be cloned. 268 */ 269 @Override 270 public Object clone(Workspace workspace) throws CloneNotSupportedException { 271 DDFDirector newObject = (DDFDirector) super.clone(workspace); 272 newObject._actorsInfo = new HashMap(); 273 newObject._actorsToCheckNumberOfFirings = new LinkedList(); 274 newObject._disabledActors = new HashSet(); 275 return newObject; 276 } 277 278 /** Set the flag indicating whether type resolution is disabled or not. 279 * This method is used in an ActorRecursion actor. When a composite 280 * actor is cloned into an ActorRecursion actor, type compatibility 281 * has already been checked, therefore there is no need to invalidate 282 * resolved types. 283 * @param flag The flag to be set. 284 */ 285 public void disableTypeResolution(boolean flag) { 286 _isTypeResolutionDisabled = flag; 287 } 288 289 /** Execute the model for one iteration. First scan all active actors 290 * to put all enabled and non-deferrable actors in a list and find the 291 * minimax actors. Fire all actors once in the list. If no actor has been 292 * fired, fire the minimax actors. If still no actor has been fired, 293 * a deadlock has been detected. This concludes one basic iteration, 294 * and by default also one iteration of this director. However, 295 * if some actor has a parameter named <i>requiredFiringsPerIteration</i> 296 * defined, continue to execute basic iterations until the actor has 297 * been fired at least the number of times given in that parameter. If 298 * more than one actor has such a parameter, then the iteration will 299 * continue until all are satisfied. If the parameter 300 * <i>runUntilDeadlockInOneIteration</i> has value true, one iteration 301 * consists of repeatedly executing basic iterations until the actors 302 * under control of this director have reached a deadlock. 303 * @exception IllegalActionException If any actor executed by this 304 * actor returns false in prefire(). 305 */ 306 @Override 307 public void fire() throws IllegalActionException { 308 boolean repeatBasicIteration = false; 309 if (_debugging) { 310 _debug("DDFDirector.fire()"); 311 } 312 do { 313 // The List to store actors that are enabled and not deferrable. 314 List toBeFiredActors = new LinkedList(); 315 316 // The list to store minimax actors. 317 List minimaxActors = new LinkedList(); 318 int minimaxSize = Integer.MAX_VALUE; 319 320 Iterator actors = ((TypedCompositeActor) getContainer()) 321 .deepEntityList().iterator(); 322 323 while (actors.hasNext()) { 324 // Scan all actors to find all enabled and not 325 // deferrable actors. 326 Actor actor = (Actor) actors.next(); 327 328 if (_disabledActors.contains(actor)) { 329 continue; 330 } 331 332 ActorInfo actorInfo = (ActorInfo) _actorsInfo.get(actor); 333 ActorEnablingStatus status = actorInfo.status; 334 335 if (status == ActorEnablingStatus.ENABLED_NOT_DEFERRABLE) { 336 toBeFiredActors.add(actor); 337 } 338 339 // Find set of minimax actors. 340 if (status == ActorEnablingStatus.ENABLED_DEFERRABLE) { 341 int newSize = actorInfo.maximumNumberOfTokens; 342 343 if (newSize < minimaxSize) { 344 minimaxActors.clear(); 345 minimaxActors.add(actor); 346 minimaxSize = newSize; 347 } else if (newSize == minimaxSize) { 348 minimaxActors.add(actor); 349 } 350 } 351 } 352 353 // No actor has been fired at the beginning of the 354 // basic iteration. 355 _firedOne = false; 356 357 // Fire all enabled and not deferrable actors. 358 Iterator enabledActors = toBeFiredActors.iterator(); 359 360 while (enabledActors.hasNext()) { 361 Actor actor = (Actor) enabledActors.next(); 362 boolean isActorFired = _fireActor(actor); 363 _firedOne = isActorFired || _firedOne; 364 } 365 366 // If no actor has been fired, fire the set of minimax actors. 367 if (!_firedOne) { 368 Iterator minimaxActorsIterator = minimaxActors.iterator(); 369 370 while (minimaxActorsIterator.hasNext()) { 371 Actor minimaxActor = (Actor) minimaxActorsIterator.next(); 372 boolean isActorFired = _fireActor(minimaxActor); 373 _firedOne = isActorFired || _firedOne; 374 } 375 } 376 377 if (_runUntilDeadlock) { 378 // Repeat basic iteration if at lease one actor 379 // has been fired. 380 repeatBasicIteration = _firedOne; 381 } else if (_firedOne) { 382 // Check to see if we need to repeat basic iteration to 383 // satisfy requiredFiringsPerIteration for some actors. 384 actors = _actorsToCheckNumberOfFirings.iterator(); 385 386 repeatBasicIteration = false; 387 388 while (actors.hasNext()) { 389 Actor actor = (Actor) actors.next(); 390 391 // If the actor has been deleted from the topology, 392 // there is no need to check. 393 if (actor.getContainer() == null) { 394 actors.remove(); 395 continue; 396 } 397 398 ActorInfo actorInfo = (ActorInfo) _actorsInfo.get(actor); 399 int requiredFirings = actorInfo.requiredFiringsPerIteration; 400 int firingsDone = actorInfo.numberOfFirings; 401 402 if (firingsDone < requiredFirings) { 403 repeatBasicIteration = true; 404 break; 405 } 406 } 407 } else { 408 // If no actor has been fired, declare deadlock 409 if (_debugging) { 410 _debug("deadlock detected"); 411 } 412 413 repeatBasicIteration = false; 414 } 415 } while (repeatBasicIteration && !_stopRequested); 416 } 417 418 /** Initialize the model controlled by this director. Initialize the 419 * actors associated with this director. Set all the state variables 420 * to the their initial values. The order in which the actors are 421 * initialized is arbitrary. If actors connected directly to output 422 * ports produce initial tokens, then send those tokens to the outside 423 * of the composite actor. 424 * @exception IllegalActionException If the initialize() method of 425 * one of the associated actors throws it. 426 */ 427 @Override 428 public void initialize() throws IllegalActionException { 429 _iterationCount = 0; 430 _runUntilDeadlock = ((BooleanToken) runUntilDeadlockInOneIteration 431 .getToken()).booleanValue(); 432 _actorsToCheckNumberOfFirings.clear(); 433 _disabledActors.clear(); 434 435 super.initialize(); 436 437 Iterator outputPorts = ((Actor) getContainer()).outputPortList() 438 .iterator(); 439 440 while (outputPorts.hasNext()) { 441 IOPort outputPort = (IOPort) outputPorts.next(); 442 443 for (int i = 0; i < outputPort.getWidthInside(); i++) { 444 while (outputPort.hasNewTokenInside(i)) { 445 Token token = outputPort.getInside(i); 446 447 if (_debugging) { 448 _debug("transferring initial tokens from " 449 + outputPort.getFullName()); 450 } 451 452 outputPort.send(i, token); 453 } 454 } 455 } 456 if (_debugging) { 457 _debug("DDFDirector.initialize() finished."); 458 } 459 } 460 461 /** Initialize the given actor. This method is called by the 462 * initialize() method of the director, and by the manager whenever 463 * an actor is added to the executing model as a mutation. It first 464 * calls the actor's initialize() method which may emit initial tokens. 465 * Then it updates the enabling status of the actor and all actors 466 * connected to this actor. Finally it records the value given by 467 * <i>requiredFiringsPerIteration</i> if the actor has such a parameter. 468 * Any change to this parameter during execution will be ignored. 469 * @param actor The actor to be initialized. 470 * @exception IllegalActionException If the 471 * <i>requiredFiringsPerIteration</i> parameter does not contain 472 * an IntToken. 473 */ 474 @Override 475 public void initialize(Actor actor) throws IllegalActionException { 476 super.initialize(actor); 477 478 // Since an actor may produce initial tokens during initialization, 479 // the enabling status of those directly connected actors as well 480 // as itself must be updated. 481 _updateConnectedActorsStatus(actor); 482 483 // Determine requiredFiringsPerIteration for this actor. 484 // The default value 0 means no requirement on this actor. 485 ActorInfo actorInfo = (ActorInfo) _actorsInfo.get(actor); 486 actorInfo.requiredFiringsPerIteration = 0; 487 488 Variable requiredFiringsPerIteration = (Variable) ((Entity) actor) 489 .getAttribute("requiredFiringsPerIteration"); 490 491 if (requiredFiringsPerIteration != null) { 492 Token token = requiredFiringsPerIteration.getToken(); 493 494 if (token instanceof IntToken) { 495 int value = ((IntToken) token).intValue(); 496 497 if (value > 0) { 498 actorInfo.requiredFiringsPerIteration = value; 499 } 500 501 _actorsToCheckNumberOfFirings.add(actor); 502 } else { 503 throw new IllegalActionException(this, actor, 504 "The variable " 505 + "requiredFiringsPerIteration must contain " 506 + "an IntToken."); 507 } 508 } 509 } 510 511 /** Call base class method to invalidate resolved types if the flag to 512 * disable type resolution is set to false. If the flag is true, 513 * override the base class method to skip invalidating resolved types. 514 * This method is used for an ActorRecursion actor. When a composite 515 * actor is cloned into an ActorRecursion actor, type compatibility 516 * has already been checked, therefore there is no need to invalidate 517 * resolved types. 518 */ 519 @Override 520 public void invalidateResolvedTypes() { 521 if (!_isTypeResolutionDisabled) { 522 super.invalidateResolvedTypes(); 523 } 524 } 525 526 /** Merge an opaque composite actor controlled by an inside DDFDirector 527 * with the outside domain controlled by this director. It aggregates 528 * the status variables for the inside actors with the status variables 529 * for the outside actors. This method can be used in ActorRecursion 530 * which clones a composite actor into itself and then merges with the 531 * outside DDF domain. 532 * @param insideDirector The inside DDFDirector to be merged. 533 */ 534 public void merge(DDFDirector insideDirector) { 535 _disabledActors.addAll(insideDirector._disabledActors); 536 _actorsToCheckNumberOfFirings 537 .addAll(insideDirector._actorsToCheckNumberOfFirings); 538 _actorsInfo.putAll(insideDirector._actorsInfo); 539 } 540 541 /** Return a new QueueReceiver. Set the capacity of the FIFO queue 542 * in the receiver to the value specified by the director parameter 543 * <i>maximumReceiverCapacity</i> if that value is greater than 0. 544 * @return A new QueueReceiver. 545 */ 546 @Override 547 public Receiver newReceiver() { 548 QueueReceiver receiver = new QueueReceiver(); 549 550 try { 551 int capacity = ((IntToken) maximumReceiverCapacity.getToken()) 552 .intValue(); 553 554 if (capacity > 0) { 555 receiver.setCapacity(capacity); 556 } 557 } catch (IllegalActionException e) { 558 throw new InternalErrorException(e); 559 } 560 561 return receiver; 562 } 563 564 /** Increment the number of iterations. Return false if the system 565 * has finished executing by reaching the iteration limit or the system 566 * is deadlocked. 567 * @return True if the Director wants to be fired again in the future. 568 * @exception IllegalActionException If the <i>iterations</i> parameter 569 * does not contain a legal value. 570 */ 571 @Override 572 public boolean postfire() throws IllegalActionException { 573 int iterationsValue = ((IntToken) iterations.getToken()).intValue(); 574 _iterationCount++; 575 576 if (iterationsValue > 0 && _iterationCount >= iterationsValue) { 577 if (_debugging) { 578 _debug("iteration limit reached"); 579 } 580 581 return false; 582 } 583 584 // The DDF domain is deadlocked if no actor is fired in the last 585 // basic iteration. However, if the DDF domain is embedded inside 586 // another domain, then we have to check whether transferring 587 // more tokens into the DDF domain will break the deadlock. 588 boolean isDeadlocked = !_firedOne; 589 590 if (isDeadlocked && isEmbedded()) { 591 Iterator inputPorts = ((Actor) getContainer()).inputPortList() 592 .iterator(); 593 594 while (inputPorts.hasNext()) { 595 IOPort inputPort = (IOPort) inputPorts.next(); 596 Receiver[][] deepReceivers = inputPort.deepGetReceivers(); 597 foundNotSatisfiedReceiver: for (int i = 0; i < deepReceivers.length; i++) { 598 for (int j = 0; j < deepReceivers[i].length; j++) { 599 QueueReceiver deepReceiver = (QueueReceiver) deepReceivers[i][j]; 600 IOPort port = deepReceiver.getContainer(); 601 602 // We don't consider the weird case where the input 603 // port is directly connected to an output port 604 // of the container. 605 if (port.getContainer() != getContainer()) { 606 int tokenConsumptionRate = _getTokenConsumptionRate( 607 deepReceiver); 608 609 if (deepReceiver.size() < tokenConsumptionRate) { 610 isDeadlocked = false; 611 break foundNotSatisfiedReceiver; 612 } 613 } 614 } 615 } 616 } 617 } 618 619 return super.postfire() && !isDeadlocked; 620 } 621 622 /** Check the input ports of the container composite actor (if there 623 * are any) to see whether they have enough tokens, and return true 624 * if they do. If there are no input ports, then also return true. 625 * Otherwise, return false. If an input port does not have a parameter 626 * <i>tokenConsumptionRate</i>, then skip checking on that port because 627 * it will transfer all tokens (if there are any) to the inside. Note 628 * the difference from SDF domain where the default rate is 1. Finally, 629 * initialize numberOfFirings to zero for those actors for which positive 630 * requiredFiringsPerIteration has been defined. 631 * @return true If all of the input ports of the container of this 632 * director have enough tokens. 633 * @exception IllegalActionException If any called method throws 634 * IllegalActionException. 635 */ 636 @Override 637 public boolean prefire() throws IllegalActionException { 638 if (_debugging) { 639 _debug("DDFDirector.prefire()\niterationCount " + _iterationCount); 640 } 641 642 super.prefire(); 643 644 Actor container = (Actor) getContainer(); 645 Iterator inputPorts = container.inputPortList().iterator(); 646 647 while (inputPorts.hasNext()) { 648 IOPort inputPort = (IOPort) inputPorts.next(); 649 650 // NOTE: If the port is a ParameterPort, then we should not 651 // insist on there being an input. 652 if (inputPort instanceof ParameterPort) { 653 continue; 654 } 655 656 int[] rate = _getTokenConsumptionRate(inputPort); 657 658 for (int i = 0; i < inputPort.getWidth(); i++) { 659 if (rate[i] >= 0 && !inputPort.hasToken(i, rate[i])) { 660 if (_debugging) { 661 _debug("Channel " + i + " of port " 662 + inputPort.getFullName() 663 + " does not have enough tokens: " + rate[i] 664 + ". Prefire returns false."); 665 } 666 if (_debugging) { 667 _debug("DDFDirector.prefire() returns false."); 668 } 669 return false; 670 } 671 } 672 } 673 674 Iterator actors = _actorsToCheckNumberOfFirings.iterator(); 675 676 while (actors.hasNext()) { 677 Actor actor = (Actor) actors.next(); 678 ActorInfo actorInfo = (ActorInfo) _actorsInfo.get(actor); 679 actorInfo.numberOfFirings = 0; 680 } 681 if (_debugging) { 682 _debug("DDFDirector.prefire() returns true."); 683 } 684 return true; 685 } 686 687 /** Return an array of suggested directors to use with an embedded 688 * ModalModel. Each director is specified by its full class 689 * name. The first director in the array will be the default 690 * director used by a modal model. 691 * @return An array of suggested directors to be used with ModalModel. 692 * @see ptolemy.actor.Director#suggestedModalModelDirectors() 693 */ 694 @Override 695 public String[] suggestedModalModelDirectors() { 696 String[] defaultSuggestions = { 697 "ptolemy.domains.modal.kernel.MultirateFSMDirector", 698 "ptolemy.domains.hdf.kernel.HDFFSMDirector", 699 "ptolemy.domains.modal.kernel.FSMDirector", 700 "ptolemy.domains.modal.kernel.NonStrictFSMDirector" }; 701 return defaultSuggestions; 702 } 703 704 /** Return true to indicate that a ModalModel under control 705 * of this director supports multirate firing. 706 * @return True indicating a ModalModel under control of this director 707 * supports multirate firing. 708 */ 709 @Override 710 public boolean supportMultirateFiring() { 711 return true; 712 } 713 714 /** Override the base class method to transfer enough tokens to complete 715 * an internal iteration. If the token consumption rate is defined for 716 * the port and there are not enough tokens, throw an exception. If the 717 * token consumption rate is not defined for the port, transfer all tokens 718 * (if there are any) contained by the port. Finally it updates enabling 719 * status for all inside opaque actors that receive data from this port. 720 * @param port The port to transfer tokens from. 721 * @return True if data are transferred. 722 * @exception IllegalActionException If the port is not an opaque 723 * input port, or if there are not enough input tokens available. 724 */ 725 @Override 726 public boolean transferInputs(IOPort port) throws IllegalActionException { 727 if (_debugging) { 728 _debug("Calling transferInputs on port: " + port.getFullName()); 729 } 730 731 if (!port.isInput() || !port.isOpaque()) { 732 throw new IllegalActionException(this, port, 733 "Attempted to transferInputs on a port is not an " 734 + "opaque input port."); 735 } 736 737 boolean wasTransferred = false; 738 739 int[] rate = _getTokenConsumptionRate(port); 740 741 for (int i = 0; i < port.getWidth(); i++) { 742 try { 743 // If the parameter tokenConsumptionRate is defined, 744 // _getTokenConsumptionRate(port) returns an array 745 // of non-negative int. 746 if (rate[i] >= 0) { 747 for (int k = 0; k < rate[i]; k++) { 748 if (port.hasToken(i)) { 749 Token t = port.get(i); 750 751 if (_debugging) { 752 _debug(getName(), 753 "transferring input from channel " + i 754 + " of input port " 755 + port.getName()); 756 } 757 758 port.sendInside(i, t); 759 wasTransferred = true; 760 } else { 761 throw new IllegalActionException(this, port, 762 "Channel " + i + "should consume " + rate[i] 763 + " tokens, but there were only " 764 + k 765 + " tokens available. Maybe the rate" 766 + " is set wrong?"); 767 } 768 } 769 770 // If the parameter tokenConsumptionRate is not defined, 771 // _getTokeConsumptionRate(port) returns an array of int 772 // each with vaule -1. 773 } else { 774 // If no rate was specified, then we transfer at most 775 // one token. 776 if (port.hasToken(i)) { 777 Token token = port.get(i); 778 779 if (_debugging) { 780 _debug(getName(), "transferring input from channel " 781 + i + " of port " + port.getName()); 782 } 783 784 port.sendInside(i, token); 785 wasTransferred = true; 786 } 787 } 788 } catch (NoTokenException ex) { 789 // this shouldn't happen. 790 throw new InternalErrorException(this, ex, null); 791 } 792 } 793 794 // Update enabling status for all inside opaque actors that receive 795 // data from this port. 796 Iterator insideSinkPorts = port.insideSinkPortList().iterator(); 797 798 while (insideSinkPorts.hasNext()) { 799 IOPort insideSinkPort = (IOPort) insideSinkPorts.next(); 800 Actor actor = (Actor) insideSinkPort.getContainer(); 801 802 // Skip it if the actor to be checked contains this director. 803 // In other words, the data directly go to output port instead 804 // of any inside actors. 805 if (getContainer() != actor) { 806 ActorInfo actorInfo = (ActorInfo) _actorsInfo.get(actor); 807 if (actorInfo == null) { 808 actorInfo = new ActorInfo(); 809 _actorsInfo.put(actor, actorInfo); 810 } 811 actorInfo.status = _getActorStatus(actor); 812 } 813 } 814 815 return wasTransferred; 816 } 817 818 /** Override the base class method to transfer enough tokens to 819 * fulfill the output production rate. If the token production rate 820 * is defined for the port and there are not enough tokens, throw an 821 * exception. If the token production rate is not defined for the port, 822 * transfer all tokens (if there are any) contained on the inside by 823 * the port. 824 * @param port The port to transfer tokens from. 825 * @return True if data are transferred. 826 * @exception IllegalActionException If the port is not an opaque 827 * output port, or if there are not enough output tokens available. 828 */ 829 @Override 830 public boolean transferOutputs(IOPort port) throws IllegalActionException { 831 if (_debugging) { 832 _debug("Calling transferOutputs on port: " + port.getFullName()); 833 } 834 835 if (!port.isOutput() || !port.isOpaque()) { 836 throw new IllegalActionException(this, port, 837 "Attempted to transferOutputs on a port that " 838 + "is not an opaque output port."); 839 } 840 841 boolean wasTransferred = false; 842 843 int[] rate = _getTokenProductionRate(port); 844 845 for (int i = 0; i < port.getWidthInside(); i++) { 846 try { 847 // If the parameter tokenProductionRate is defined, 848 // _getTokenProductionRate(port) returns an array 849 // of non-negative int. 850 if (rate[i] >= 0) { 851 for (int k = 0; k < rate[i]; k++) { 852 if (port.hasTokenInside(i)) { 853 Token token = port.getInside(i); 854 855 if (_debugging) { 856 _debug(getName(), 857 "transferring output from channel " + i 858 + " of port " + port.getName()); 859 } 860 861 port.send(i, token); 862 wasTransferred = true; 863 } else { 864 throw new IllegalActionException(this, port, 865 "Channel " + i + " should produce " 866 + rate[i] 867 + " tokens, but there were only " 868 + k 869 + " tokens available. Maybe the rate" 870 + " is set wrong?"); 871 } 872 } 873 874 // If the parameter tokenProductionRate is not defined, 875 // _getTokenProductionRate(port) returns an array of int 876 // each with value -1. 877 } else { 878 while (port.hasNewTokenInside(i)) { 879 Token token = port.getInside(i); 880 881 if (_debugging) { 882 _debug(getName(), 883 "transferring output from channel " + i 884 + " of port " + port.getName()); 885 } 886 887 port.send(i, token); 888 wasTransferred = true; 889 } 890 } 891 } catch (NoTokenException ex) { 892 // this shouldn't happen. 893 throw new InternalErrorException(this, ex, null); 894 } 895 } 896 897 return wasTransferred; 898 } 899 900 /////////////////////////////////////////////////////////////////// 901 //// protected methods //// 902 903 /** Iterate the actor once. Increment the firing number for it. 904 * Update the enabling status for each connected actor as well 905 * as itself. 906 * @param actor The actor to be fired. 907 * @return true if the actor is actually fired, false if not. 908 * @exception IllegalActionException If any called method throws 909 * IllegalActionException or the actor is not ready. 910 */ 911 protected boolean _fireActor(Actor actor) throws IllegalActionException { 912 if (_debugging) { 913 _debug(new FiringEvent(this, actor, FiringEvent.BEFORE_ITERATE)); 914 } 915 916 // Iterate once. 917 int returnValue = actor.iterate(1); 918 919 if (_debugging) { 920 _debug(new FiringEvent(this, actor, FiringEvent.AFTER_ITERATE)); 921 } 922 923 _updateConnectedActorsStatus(actor); 924 925 if (returnValue == STOP_ITERATING) { 926 if (_debugging) { 927 _debug("Actor " + ((NamedObj) actor).getFullName() 928 + " is disabled."); 929 } 930 931 _disabledActors.add(actor); 932 _actorsToCheckNumberOfFirings.remove(actor); 933 } 934 935 // If the returnValue is NOT_READY, this method returns false. 936 // Because the token consumption rates of input ports provide only 937 // a guideline for firing instead of a contract, we allow an enabled 938 // (as determined by the director) actor to return false in its 939 // prefire(). 940 boolean fired = false; 941 942 if (returnValue != NOT_READY) { 943 // At least one actor has been fired in this basic iteration. 944 fired = true; 945 946 // Increment the firing number. 947 if (_actorsToCheckNumberOfFirings.contains(actor)) { 948 ActorInfo actorInfo = (ActorInfo) _actorsInfo.get(actor); 949 actorInfo.numberOfFirings++; 950 } 951 } 952 953 return fired; 954 } 955 956 /** Determine actor enabling status. It must be one of the three: 957 * NOT_ENABLED, ENABLED_DEFERRABLE, ENABLED_NOT_DEFERRABLE. 958 * @param actor The actor to be checked. 959 * @return An int indicating actor enabling status. 960 * @exception IllegalActionException If any called method throws 961 * IllegalActionException. 962 */ 963 protected ActorEnablingStatus _getActorStatus(Actor actor) 964 throws IllegalActionException { 965 if (!_isEnabled(actor)) { 966 if (_debugging) { 967 _debug(((NamedObj) actor).getName() + ": " 968 + ActorEnablingStatus.NOT_ENABLED); 969 } 970 971 return ActorEnablingStatus.NOT_ENABLED; 972 } 973 974 if (_isDeferrable(actor)) { 975 if (_debugging) { 976 _debug(((NamedObj) actor).getName() + ": " 977 + ActorEnablingStatus.ENABLED_DEFERRABLE); 978 } 979 980 return ActorEnablingStatus.ENABLED_DEFERRABLE; 981 } 982 983 if (_debugging) { 984 _debug(((NamedObj) actor).getName() + ": " 985 + ActorEnablingStatus.ENABLED_NOT_DEFERRABLE); 986 } 987 988 return ActorEnablingStatus.ENABLED_NOT_DEFERRABLE; 989 } 990 991 /** Check each remote receiver to see whether the number of tokens 992 * in the receiver is greater than or equal to the 993 * <i>tokenConsumptionRate</i> of the containing port. The actor 994 * is deferrable if the above test is true for any receiver. At 995 * the same time, find the maximum number of tokens in all 996 * receivers, which is used to find minimax actors later on. 997 * @param actor The actor to be checked. 998 * @return true if the actor is deferrable, false if not. 999 * @exception IllegalActionException If any called method throws 1000 * IllegalActionException. 1001 */ 1002 protected boolean _isDeferrable(Actor actor) throws IllegalActionException { 1003 boolean deferrable = false; 1004 int maxSize = 0; 1005 1006 Iterator outputPorts = actor.outputPortList().iterator(); 1007 1008 while (outputPorts.hasNext()) { 1009 IOPort outputPort = (IOPort) outputPorts.next(); 1010 Receiver[][] farReceivers = outputPort.getRemoteReceivers(); 1011 1012 for (Receiver[] farReceiver2 : farReceivers) { 1013 if (farReceiver2 == null) { 1014 continue; 1015 } 1016 for (int j = 0; j < farReceiver2.length; j++) { 1017 QueueReceiver farReceiver = (QueueReceiver) farReceiver2[j]; 1018 IOPort port = farReceiver.getContainer(); 1019 1020 // Having a self-loop doesn't make it deferrable. 1021 if (port.getContainer() == outputPort.getContainer()) { 1022 continue; 1023 } 1024 1025 int tokenConsumptionRate = _getTokenConsumptionRate( 1026 farReceiver); 1027 1028 if (tokenConsumptionRate >= 0 1029 && farReceiver.size() >= tokenConsumptionRate) { 1030 deferrable = true; 1031 1032 // Here we find the maximum of the token numbers for 1033 // the actor's output channels which satisfy the demand 1034 // of destination actors while checking deferrability. 1035 // The advantage of this is that it only adds a small 1036 // additional operation for now. If later on we need 1037 // this information, we don't need to do traversing 1038 // again. The disadvantage is that 1) we can return 1039 // from this method as soon as deferrable == true if we 1040 // don't perform this additional operation. 2) We will 1041 // not need this information if it turns out not all 1042 // enabled actors are deferrable. Therefore another 1043 // approach is to perform this operation only when 1044 // needed, i.e., when all enabled actor are deferrable. 1045 if (farReceiver.size() > maxSize) { 1046 maxSize = farReceiver.size(); 1047 } 1048 } 1049 } 1050 } 1051 } 1052 1053 if (deferrable) { 1054 ActorInfo actorInfo = (ActorInfo) _actorsInfo.get(actor); 1055 actorInfo.maximumNumberOfTokens = maxSize; 1056 } 1057 1058 return deferrable; 1059 } 1060 1061 /** Check to see whether the actor is enabled. It is enabled if the 1062 * tokenConsumptionRate on each input port is satisfied by all 1063 * receivers contained by this port. 1064 * @param actor The actor to be checked. 1065 * @return true if the actor is enabled, false if not. 1066 * @exception IllegalActionException If any called method throws 1067 * IllegalActionException. 1068 */ 1069 protected boolean _isEnabled(Actor actor) throws IllegalActionException { 1070 Iterator inputPorts = actor.inputPortList().iterator(); 1071 1072 while (inputPorts.hasNext()) { 1073 IOPort inputPort = (IOPort) inputPorts.next(); 1074 int[] rate = _getTokenConsumptionRate(inputPort); 1075 1076 for (int i = 0; i < inputPort.getWidth(); i++) { 1077 if (rate[i] > 0 && !inputPort.hasToken(i, rate[i])) { 1078 return false; 1079 } 1080 } 1081 } 1082 1083 return true; 1084 } 1085 1086 /** Update the enabling status of the given actor and all actors 1087 * connected to this actor. This method gets called after the given 1088 * actor gets initialized or fired. 1089 * @param actor The actor to te checked. 1090 * @exception IllegalActionException If _getActorStatus(Actor) throws 1091 * IllegalActionException. 1092 */ 1093 protected void _updateConnectedActorsStatus(Actor actor) 1094 throws IllegalActionException { 1095 // Update enabling status for each connected actor. 1096 Iterator ports = ((Entity) actor).portList().iterator(); 1097 1098 while (ports.hasNext()) { 1099 ComponentPort port = (ComponentPort) ports.next(); 1100 Iterator deepConnectedPorts = port.deepConnectedPortList() 1101 .iterator(); 1102 1103 while (deepConnectedPorts.hasNext()) { 1104 Port deepConnectedPort = (Port) deepConnectedPorts.next(); 1105 Actor connectedActor = (Actor) deepConnectedPort.getContainer(); 1106 1107 // Skip it if the connectedActor to be checked contains 1108 // this director. 1109 if (getContainer() != connectedActor) { 1110 // Get an array of actor flags from HashMap. 1111 // Create it if none found. 1112 ActorInfo actorInfo; 1113 1114 if (_actorsInfo.containsKey(connectedActor)) { 1115 actorInfo = (ActorInfo) _actorsInfo.get(connectedActor); 1116 } else { 1117 actorInfo = new ActorInfo(); 1118 _actorsInfo.put(connectedActor, actorInfo); 1119 } 1120 1121 actorInfo.status = _getActorStatus(connectedActor); 1122 } 1123 } 1124 } 1125 1126 // Update enabling status for this actor. 1127 ActorInfo actorInfo; 1128 1129 if (_actorsInfo.containsKey(actor)) { 1130 actorInfo = (ActorInfo) _actorsInfo.get(actor); 1131 } else { 1132 actorInfo = new ActorInfo(); 1133 _actorsInfo.put(actor, actorInfo); 1134 } 1135 1136 actorInfo.status = _getActorStatus(actor); 1137 } 1138 1139 /////////////////////////////////////////////////////////////////// 1140 //// private methods //// 1141 1142 /** Get token consumption rate for the given port. If the port is an 1143 * input port of an actor controlled by this director, the default 1144 * rate is 1 unless explicitly specified by a <i>tokenConsumptionRate</i> 1145 * parameter. If the port is an input port of the container of this 1146 * director, the default value is -1 unless explicitly specified by 1147 * a <i>tokenConsumptionRate</i> parameter. The value -1 means consuming 1148 * all tokens (if there are any) contained by the port. 1149 * @param port The port to get token consumption rate. 1150 * @return An int array of token consumption rates. 1151 * @exception IllegalActionException If parameter throws it or the 1152 * length of tokenConsumptionRate array is less than port width. 1153 */ 1154 private int[] _getTokenConsumptionRate(IOPort port) 1155 throws IllegalActionException { 1156 int[] rate = new int[port.getWidth()]; 1157 1158 if (port.getContainer() != getContainer()) { 1159 Arrays.fill(rate, 1); 1160 } else { 1161 Arrays.fill(rate, -1); 1162 } 1163 1164 Variable rateVariable = DFUtilities.getRateVariable(port, 1165 "tokenConsumptionRate"); 1166 1167 if (rateVariable != null) { 1168 Token token = rateVariable.getToken(); 1169 1170 if (token != null) { 1171 // If token is ArrayToken, then each channel has a 1172 // corresponding input rate in the array. 1173 if (token instanceof ArrayToken) { 1174 Token[] tokens = ((ArrayToken) token).arrayValue(); 1175 1176 for (int i = 0; i < port.getWidth(); i++) { 1177 if (i < tokens.length) { 1178 rate[i] = ((IntToken) tokens[i]).intValue(); 1179 } 1180 } 1181 } else { // All the channels in the port have same 1182 1183 // tokenConsumptionRate. 1184 Arrays.fill(rate, ((IntToken) token).intValue()); 1185 } 1186 } 1187 } 1188 1189 return rate; 1190 } 1191 1192 /** Get token consumption rate for the given receiver. The port 1193 * containing the receiver can be an input port of an actor 1194 * controlled by this director or an output port of the container 1195 * of this director. In the latter case, it actually returns the 1196 * production rate. 1197 * @param receiver The receiver to get token consumption rate. 1198 * @return The token consumption rate of the given receiver. 1199 * @exception IllegalActionException If any called method throws 1200 * IllegalActionException. 1201 */ 1202 private int _getTokenConsumptionRate(Receiver receiver) 1203 throws IllegalActionException { 1204 int tokenConsumptionRate; 1205 1206 IOPort port = receiver.getContainer(); 1207 Variable rateVariable = null; 1208 Token token = null; 1209 Receiver[][] portReceivers = null; 1210 1211 // If DDF domain is inside another domain and the 1212 // receiver is contained by an opaque output port... 1213 // The default production rate is -1 which means all 1214 // tokens in the receiver are transferred to the outside. 1215 if (port.isOutput()) { 1216 rateVariable = DFUtilities.getRateVariable(port, 1217 "tokenProductionRate"); 1218 portReceivers = port.getInsideReceivers(); 1219 1220 if (rateVariable == null) { 1221 tokenConsumptionRate = -1; 1222 return tokenConsumptionRate; 1223 } else { 1224 token = rateVariable.getToken(); 1225 1226 if (token == null) { 1227 tokenConsumptionRate = -1; 1228 return tokenConsumptionRate; 1229 } 1230 } 1231 } 1232 1233 if (port.isInput()) { 1234 rateVariable = DFUtilities.getRateVariable(port, 1235 "tokenConsumptionRate"); 1236 portReceivers = port.getReceivers(); 1237 1238 if (rateVariable == null) { 1239 tokenConsumptionRate = 1; 1240 return tokenConsumptionRate; 1241 } else { 1242 token = rateVariable.getToken(); 1243 1244 if (token == null) { 1245 tokenConsumptionRate = 1; 1246 return tokenConsumptionRate; 1247 } 1248 } 1249 } 1250 1251 if (token instanceof ArrayToken) { 1252 Token[] tokens = ((ArrayToken) token).arrayValue(); 1253 1254 // Scan the contained receivers of the port to find 1255 // out channel index. 1256 int channelIndex = 0; 1257 foundChannelIndex: for (int m = 0; m < portReceivers.length; m++) { 1258 for (int n = 0; n < portReceivers[m].length; n++) { 1259 if (receiver == portReceivers[m][n]) { 1260 channelIndex = m; 1261 break foundChannelIndex; 1262 } 1263 } 1264 } 1265 1266 tokenConsumptionRate = ((IntToken) tokens[channelIndex]).intValue(); 1267 } else { 1268 tokenConsumptionRate = ((IntToken) token).intValue(); 1269 } 1270 1271 return tokenConsumptionRate; 1272 } 1273 1274 /** Get token production rate for the given port. The port argument 1275 * should always be an output port of the container of this director. 1276 * The convention is that if a parameter named <i>tokenproductionRate</i> 1277 * is defined, return the value in that parameter. Otherwise, return 1278 * an array of int each with value -1 which means the director should 1279 * transfer all tokens contained on the inside by the port to the outside. 1280 * Note the difference from SDF domain where the default rate is 1. 1281 * @param port The port to get token production rate. 1282 * @return An int array of token production rate. 1283 * @exception IllegalActionException If parameter throws it 1284 * or the length of tokenProductionRate array is less 1285 * than port inside width or the port in the argument is 1286 * not an output port of the container of this director. 1287 */ 1288 private int[] _getTokenProductionRate(IOPort port) 1289 throws IllegalActionException { 1290 if (port.getContainer() != getContainer()) { 1291 throw new IllegalActionException(this, "The port in the " 1292 + "argument is not an output port of the container of " 1293 + getName()); 1294 } 1295 1296 int[] rate = new int[port.getWidthInside()]; 1297 Arrays.fill(rate, -1); 1298 1299 Variable rateVariable = DFUtilities.getRateVariable(port, 1300 "tokenProductionRate"); 1301 1302 if (rateVariable != null) { 1303 Token token = rateVariable.getToken(); 1304 1305 if (token != null) { 1306 // If token is ArrayToken, then each channel has a 1307 // corresponding output rate in the array. 1308 if (token instanceof ArrayToken) { 1309 Token[] tokens = ((ArrayToken) token).arrayValue(); 1310 1311 if (tokens.length < port.getWidthInside()) { 1312 throw new IllegalActionException(this, "The length of " 1313 + "tokenProductionRate array is less than " 1314 + "the port inside width."); 1315 } 1316 1317 for (int i = 0; i < port.getWidthInside(); i++) { 1318 if (i < tokens.length) { 1319 rate[i] = ((IntToken) tokens[i]).intValue(); 1320 } 1321 } 1322 } else { // All the channels in the port has same 1323 1324 // tokenProductionRate. 1325 Arrays.fill(rate, ((IntToken) token).intValue()); 1326 } 1327 } 1328 } 1329 1330 return rate; 1331 } 1332 1333 /** Initialize the object. In this case, we give the DDFDirector 1334 * an <i>iterations</i> parameter with default value zero, 1335 * a <i>maximumReceiverCapacity</i> parameter with default value zero 1336 * and a <i>runUntilDeadlockInOneIteration</i> parameter with default 1337 * value false. 1338 */ 1339 private void _init() 1340 throws IllegalActionException, NameDuplicationException { 1341 iterations = new Parameter(this, "iterations"); 1342 iterations.setTypeEquals(BaseType.INT); 1343 iterations.setToken(new IntToken(0)); 1344 1345 maximumReceiverCapacity = new Parameter(this, 1346 "maximumReceiverCapacity"); 1347 maximumReceiverCapacity.setTypeEquals(BaseType.INT); 1348 maximumReceiverCapacity.setToken(new IntToken(0)); 1349 1350 runUntilDeadlockInOneIteration = new Parameter(this, 1351 "runUntilDeadlockInOneIteration"); 1352 runUntilDeadlockInOneIteration.setTypeEquals(BaseType.BOOLEAN); 1353 runUntilDeadlockInOneIteration.setToken(new BooleanToken(false)); 1354 } 1355 1356 /////////////////////////////////////////////////////////////////// 1357 //// private variables //// 1358 1359 /** A flag indicating whether type resolution is disabled. 1360 */ 1361 private boolean _isTypeResolutionDisabled = false; 1362 1363 /** A flag indicating whether at least one actor has been fired so far. 1364 */ 1365 private boolean _firedOne = false; 1366 1367 /** The number of iterations. 1368 */ 1369 private int _iterationCount = 0; 1370 1371 /** A boolean initialized with value in the parameter 1372 * runUntilDeadlockInOneIteration. 1373 */ 1374 private boolean _runUntilDeadlock; 1375 1376 /** A HashMap containing actors' information. Each actor is mapped to 1377 * an ActorInfo object. 1378 */ 1379 private HashMap _actorsInfo = new HashMap(); 1380 1381 /** A list to store those actors for which positive 1382 * requiredFiringsPerIteration has been defined. 1383 */ 1384 private LinkedList _actorsToCheckNumberOfFirings = new LinkedList(); 1385 1386 /** The set of actors that have returned false in their postfire() 1387 * methods and therefore become disabled. 1388 */ 1389 private Set _disabledActors = new HashSet(); 1390 1391 /////////////////////////////////////////////////////////////////// 1392 //// inner classes //// 1393 1394 /** This private class is data structure for recording an actor's 1395 * information during the execution. 1396 */ 1397 private static class ActorInfo { 1398 1399 // FindBugs suggests making this class static so as to decrease 1400 // the size of instances and avoid dangling references. 1401 1402 /** This field records the enabling status of the actor. 1403 */ 1404 public ActorEnablingStatus status; 1405 1406 /** This field records the number of firings of the actor. 1407 * It is reset to 0 at the beginning of each iteration of 1408 * the model the actor is in. 1409 */ 1410 public int numberOfFirings; 1411 1412 /** This field records the maximum number of tokens on the actor's 1413 * output channels which satisfy the demand of destination actors. 1414 * It is used to find minimax actors. 1415 */ 1416 public int maximumNumberOfTokens; 1417 1418 /** This field records the actor's required number of firings 1419 * per iteration of the model the actor is in. 1420 */ 1421 public int requiredFiringsPerIteration; 1422 } 1423}