001/* A Manager governs the execution of a model. 002 003 Copyright (c) 1997-2017 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 execute catches Exceptions and rethrows them as runtime exceptions. why? 028 requestInitialization is pickier about what actors are initialized. 029 added preinitialization analyses (i.e. constVariableModelAnalysis) 030 Look over exitAfterWrapup(). 031 */ 032package ptolemy.actor; 033 034import java.lang.ref.WeakReference; 035import java.util.Date; 036import java.util.HashMap; 037import java.util.LinkedList; 038import java.util.List; 039import java.util.ListIterator; 040import java.util.Map; 041import java.util.WeakHashMap; 042 043import ptolemy.kernel.ComponentEntity; 044import ptolemy.kernel.CompositeEntity; 045import ptolemy.kernel.util.ExceptionHandler; 046import ptolemy.kernel.util.IllegalActionException; 047import ptolemy.kernel.util.InternalErrorException; 048import ptolemy.kernel.util.KernelException; 049import ptolemy.kernel.util.Nameable; 050import ptolemy.kernel.util.NamedObj; 051import ptolemy.kernel.util.PtolemyThread; 052import ptolemy.kernel.util.Workspace; 053import ptolemy.util.MessageHandler; 054import ptolemy.util.StringUtilities; 055 056/////////////////////////////////////////////////////////////////// 057//// Manager 058 059/** 060 A Manager governs the execution of a model in a domain-independent way. 061 Its methods are designed to be called by a GUI, an applet, a command-line 062 interface, or the top-level code of an application. The manager can 063 execute the model in the calling thread or in a separate thread. 064 The latter is useful when the caller wishes to remain live during 065 the execution of the model. 066 067 <p> There are three methods that can be used to start execution of a 068 system attached to the manager. The execute() method is the most 069 basic way to execute a model. The model will be executed 070 <i>synchronously</i>, meaning that the execute() method will return 071 when execution has completed. Any exceptions that occur will be 072 thrown by the execute method to the calling thread, and will not be 073 reported to any execution listeners. The run() method also initiates 074 synchronous execution of a model, but additionally catches all 075 exceptions and passes them to the notifyListenersOfException() method 076 <i>without throwing them to the calling thread</i>. The startRun() 077 method, unlike the previous two techniques, begins <i>asynchronous</i> 078 execution of a model. This method starts a new thread for execution 079 of the model and then returns immediately. Exceptions are reported 080 using the notifyListenersOfException() method. 081 082 <p> In addition, execution can be manually driven, one phase at a 083 time, using the methods initialize(), iterate() and wrapup(). This is 084 most useful for testing purposes. For example, a type system check 085 only needs to get the resolved types, which are found during 086 initialize, so the test can avoid actually executing the system. 087 Also, when testing mutations, the model can be examined after each 088 toplevel iteration to ensure the proper behavior. 089 090 <p> A manager provides services for cleanly handling changes to the 091 topology. These include such changes as adding or removing an entity, 092 port, or relation, creating or destroying a link, and changing the 093 value or type of a parameter. Collectively, such changes are called 094 <i>mutations</i>. Usually, mutations cannot safely occur at arbitrary 095 points in the execution of a model. Models can queue mutations with 096 any object in the hierarchy or with the manager using the 097 requestChange() method. An object in the hierarchy simply delegates 098 the request to its container, so the request propagates up the 099 hierarchy until it gets to the top level composite actor, which 100 delegates to the manager, which performs the change at the earliest 101 opportunity. In this implementation of Manager, the changes are 102 executed between iterations. 103 104 <p> A service is also provided whereby an object can be registered 105 with the composite actor as a change listener. A change listener is 106 informed when mutations that are requested via requestChange() are 107 executed successfully, or when they fail with an exception. 108 109 <p> Manager can optimize the performance of an execution by making the 110 workspace <i>write protected</i> during an iteration, if all relevant 111 directors permit this. This removes some of the overhead of obtaining 112 read and write permission on the workspace. By default, directors do 113 not permit this, but many directors explicitly relinquish write access 114 to allow faster execution. Such directors are declaring that they 115 will not make changes to the topology during execution. Instead, any 116 desired mutations are delegated to the manager via the requestChange() 117 method. 118 119 <p> Many domains make use of static analyses for performing, e.g., 120 static scheduling of actor firings. In some cases, these analyses 121 must make use of global information. The class provides a centralized 122 mechanism for managing such global analyses. During preinitialize, 123 domains can invoke the getAnalysis and addAnalysis methods to create a 124 global analysis. It is up to the users of this mechanism to ensure 125 that a particular type of analysis is only created once, if that is 126 what is required. After preinitialize, the manager clears the list of 127 analyses, to avoid unnecessary memory usage, and to ensure that the 128 analyses are performed again on the next invocation of the model. 129 This is somewhat preferable to tying a cache of analysis information 130 to the version of the workspace, since the version number of the 131 workspace itself may change during preinitialize as domains add 132 annotation to the model. 133 134 @author Steve Neuendorffer, Lukito Muliadi, Edward A. Lee, Elaine Cheong, Contributor: Mudit Goel, John S. Davis II, Bert Rodiers, Daniel Crawl 135 @version $Id$ 136 @since Ptolemy II 0.2 137 @Pt.ProposedRating Green (neuendor) 138 @Pt.AcceptedRating Yellow (cxh) 139 */ 140public class Manager extends NamedObj implements Runnable { 141 142 /** Construct a manager in the default workspace with an empty string 143 * as its name. The manager is added to the list of objects in 144 * the workspace. Increment the version number of the workspace. 145 */ 146 public Manager() { 147 super(); 148 } 149 150 /** Construct a manager in the default workspace with the given name. 151 * If the name argument is null, then the name is set to the empty 152 * string. The manager is added to the list of objects in the workspace. 153 * Increment the version number of the workspace. 154 * @param name Name of this Manager. 155 * @exception IllegalActionException If the name has a period. 156 */ 157 public Manager(String name) throws IllegalActionException { 158 super(name); 159 } 160 161 /** Construct a manager in the given workspace with the given name. 162 * If the workspace argument is null, use the default workspace. 163 * The manager is added to the list of objects in the workspace. 164 * If the name argument is null, then the name is set to the 165 * empty string. Increment the version number of the workspace. 166 * 167 * @param workspace Object for synchronization and version tracking. 168 * @param name Name of this Manager. 169 * @exception IllegalActionException If the name has a period. 170 */ 171 public Manager(Workspace workspace, String name) 172 throws IllegalActionException { 173 super(workspace, name); 174 } 175 176 /////////////////////////////////////////////////////////////////// 177 //// public variables //// 178 // NOTE: The following names of states should fit into the sentence: 179 // "The model is ... " 180 181 /** Indicator that the model may be corrupted. 182 */ 183 public final static State CORRUPTED = new State("corrupted"); 184 185 /** Indicator that there is no currently active execution. 186 */ 187 public final static State IDLE = new State("idle"); 188 189 /** Indicator that width inference is being done. 190 */ 191 public final static State INFERING_WIDTHS = new State("infering widths"); 192 193 /** Indicator that the execution is in the initialize phase. 194 */ 195 public final static State INITIALIZING = new State("initializing"); 196 197 /** Indicator that the execution is in an iteration. 198 */ 199 public final static State ITERATING = new State("executing"); 200 201 /** Indicator that the execution is paused. 202 */ 203 public final static State PAUSED = new State("pausing execution"); 204 205 /** Indicator that the execution is paused on a breakpoint. 206 */ 207 public final static State PAUSED_ON_BREAKPOINT = new State( 208 "pausing execution on a breakpoint"); 209 210 /** Indicator that the execution is in the preinitialize phase. 211 */ 212 public final static State PREINITIALIZING = new State("preinitializing"); 213 214 /** Indicator that type resolution is being done. 215 */ 216 public final static State RESOLVING_TYPES = new State("resolving types"); 217 218 /** Indicator that the execution is throwing a throwable. 219 */ 220 public final static State THROWING_A_THROWABLE = new State( 221 "throwing a throwable"); 222 223 /** Indicator that the execution is in the wrapup phase. 224 */ 225 public final static State WRAPPING_UP = new State("wrapping up"); 226 227 /** Indicator that the execution is in the wrapup phase and about 228 * to exit. 229 */ 230 public final static State EXITING = new State("exiting"); 231 232 /////////////////////////////////////////////////////////////////// 233 //// public methods //// 234 235 /** Add a static analysis to this manager. A static analysis is 236 * simply an object that is recorded in a hash table and cleared 237 * at the end of preinitialize(), with no semantics associated 238 * with that object. The intent is for that object to serve as a 239 * repository for static analysis results, but clearing it and 240 * the end of preinitialize isn't quite right. The idea is that 241 * it is cleared at a point when the analysis has to be redone 242 * after that point. But doing this at the end of preinitialize 243 * means this won't work with models that mutate either during 244 * preinitialize() (as in higher- order actors) or during 245 * execution. 246 * 247 * @param name The name of the analysis. 248 * @param analysis The analysis to record. 249 * @see #getAnalysis(String) 250 */ 251 public void addAnalysis(String name, Object analysis) { 252 if (_nameToAnalysis == null) { 253 _nameToAnalysis = new HashMap<String, Object>(); 254 } 255 256 _nameToAnalysis.put(name, analysis); 257 } 258 259 /** Add a listener to be notified when the model execution changes state. 260 * If the specified listener is already a listener, do nothing. 261 * @param listener The listener. 262 * @see #removeExecutionListener(ExecutionListener) 263 */ 264 public void addExecutionListener(ExecutionListener listener) { 265 if (listener == null) { 266 return; 267 } 268 269 if (_executionListeners == null) { 270 _executionListeners = new LinkedList<WeakReference<ExecutionListener>>(); 271 } 272 273 // Do not add the same listener twice, so if it is already in the list, 274 // remove it. See NamedObj.addChangeListener(). -- tfeng 275 removeExecutionListener(listener); 276 277 _executionListeners.add(new WeakReference<ExecutionListener>(listener)); 278 } 279 280 /** Return the elapsed time (in milliseconds) since the start of execution 281 * of the model. The start of execution is defined to be the time after 282 * initialize() has been called and before any component has been iterated. 283 * @return The time in milliseconds since the start of execution of the model. 284 */ 285 public long elapsedTimeSinceStart() { 286 long currentTime = System.currentTimeMillis(); 287 return currentTime - _afterInitTime; 288 } 289 290 /** Enable or disable printing time and memory usage at the end of model 291 * execution. 292 * 293 * @param enabled Whether time and memory printing is enabled. 294 */ 295 public void enablePrintTimeAndMemory(boolean enabled) { 296 _printTimeAndMemory = enabled; 297 } 298 299 /** Execute the model. Begin with the initialization phase, followed 300 * by a sequence of iterations, followed by a wrapup phase. 301 * The sequence of iterations concludes when the postfire() method 302 * of the container (the top-level composite actor) returns false, 303 * or when the finish() method is called. 304 * <p> 305 * The execution is performed in the calling thread (the current thread), 306 * so this method returns only after execution finishes. 307 * If you wish to perform execution in a new thread, use startRun() 308 * instead. Even if an exception occurs during the execution, the 309 * wrapup() method is called (in a finally clause). 310 * <p> 311 * If an exception occurs during the execution, delegate to the 312 * exception handlers (if there are any) to handle these exceptions. 313 * If there are no exception handlers, it is up to the 314 * caller to handle (e.g. report) the exception. 315 * If you do not wish to handle exceptions, but want to execute 316 * within the calling thread, use run(). 317 * @see #run() 318 * @exception KernelException If the model throws it. 319 * @exception IllegalActionException If the model is already running, or 320 * if there is no container. 321 */ 322 public void execute() throws KernelException, IllegalActionException { 323 // NOTE: This method used to be synchronized, but holding the 324 // lock on the Manager for the duration of an execution creates 325 // endless possibilities for deadlock. So instead, we put 326 // a small barrier here and throw an exception if the model 327 // is already running. 328 synchronized (this) { 329 if (_state != IDLE) { 330 throw new IllegalActionException(this, 331 "Model is already running."); 332 } 333 } 334 335 // Make a record of the time execution starts. 336 long startTime = System.currentTimeMillis(); 337 338 _debug("-- Manager execute() called."); 339 340 // Reset this in case finish() has been called since the last run. 341 _finishRequested = false; 342 343 boolean completedSuccessfully = false; 344 345 // If we throw an throwable, we save it until after the 346 // finally clauses. 347 Throwable initialThrowable = null; 348 349 try { 350 try { 351 // Register the shutdown hook each time we register as 352 // opposed to each time a Manager is instantiated. 353 // See 354 // https://projects.ecoinformatics.org/ecoinfo/issues/7189 355 _registerShutdownHook(); 356 initialize(); 357 _afterInitTime = System.currentTimeMillis(); 358 if (_afterInitTime - startTime > minimumStatisticsTime) { 359 setStatusMessage(timeAndMemory(startTime)); 360 System.out.println("Manager.initialize() finished: " 361 + getStatusMessage()); 362 } 363 364 // Call iterate() until finish() is called or postfire() 365 // returns false. 366 _debug("-- Manager beginning to iterate."); 367 368 while (!_finishRequested) { 369 if (!iterate()) { 370 break; 371 } 372 373 if (_pauseRequested) { 374 // Have to synchronize on this to be able to wait 375 // during the pause. 376 synchronized (this) { 377 _setState(PAUSED); 378 try { 379 // Enable processing of change requests so that editing is live. 380 setDeferringChangeRequests(false); 381 while (_pauseRequested && !_finishRequested) { 382 try { 383 wait(); 384 } catch (InterruptedException e) { 385 // ignore. 386 } 387 } 388 } finally { 389 setDeferringChangeRequests(true); 390 } 391 } 392 } 393 } 394 395 completedSuccessfully = true; 396 } catch (Throwable throwable) { 397 // Catch anything that can be throw (Error, Exception etc.) 398 // Catching just KernelException will not work, since 399 // we want to be sure to rethrow things like LinkErrors. 400 // We use THROWING_A_THROWABLE in NonStrictTest.wrapup() 401 // so we be sure the actor fires and reads enough inputs. 402 _setState(THROWING_A_THROWABLE); 403 initialThrowable = throwable; 404 } 405 } finally { 406 try { 407 wrapup(); 408 } catch (Exception exception) { 409 // Caught an exception. Discard this exception 410 // if there is an exception thrown during the iteration. 411 // Otherwise, save the exception to be handled later. 412 if (initialThrowable == null) { 413 initialThrowable = exception; 414 } 415 } finally { 416 // Indicate that it is now safe to execute 417 // change requests when they are requested. 418 setDeferringChangeRequests(false); 419 420 // NOTE: This used to increment the workspace 421 // version, which would require that everything 422 // be re-done on subsequent runs. EAL 9/16/06 423 // _workspace.incrVersion(); 424 425 // Reset this for the next run. 426 _finishRequested = false; 427 428 // Wrapup may also throw an exception, 429 // So be sure to reset the state to idle! 430 if (_state != IDLE) { 431 _setState(IDLE); 432 } 433 434 // Wrapup may throw an exception, so put the following 435 // statement inside the finally block. 436 if (_printTimeAndMemory) { 437 setStatusMessage(timeAndMemory(startTime)); 438 System.out.println(getStatusMessage()); 439 } 440 441 if (completedSuccessfully && initialThrowable == null) { 442 // The Exit.tcl test needs this because otherwise 443 // we throw an exception in wrapup(), but 444 // notifyListenersOfSuccessfulCompletion() was 445 // called which causes MoMLSimpleApplication to 446 // exit before MoMLSimpleApplication was notified 447 // of the exception. 448 449 _notifyListenersOfSuccessfulCompletion(); 450 } 451 452 // Remove the _shutdownThread. 453 // See https://projects.ecoinformatics.org/ecoinfo/issues/7189 454 _disposeOfThreads(); 455 456 // Handle throwable with exception handlers, 457 // if there are any. 458 if (initialThrowable != null) { 459 if (_container == null || _container.get() == null) { 460 throw new InternalErrorException(this, initialThrowable, 461 "The container of the manager was null. " 462 + "Try calling composite.setManager()."); 463 } 464 // Look for attributes and entities that implement ExceptionHandler. 465 CompositeActor container = _container.get(); 466 List<ExceptionHandler> exceptionHandlersList = container 467 .attributeList(ExceptionHandler.class); 468 exceptionHandlersList.addAll( 469 container.entityList(ExceptionHandler.class)); 470 boolean exceptionHandled = false; 471 for (ExceptionHandler exceptionHandler : exceptionHandlersList) { 472 // Note that we allow multiple exception handlers 473 // to handle the same exception. So we iterate all 474 // of the exception handlers, at least until one 475 // those throws an exception. 476 if (exceptionHandler.handleException(container, 477 initialThrowable)) { 478 exceptionHandled = true; 479 } 480 } 481 if (exceptionHandled) { 482 initialThrowable = null; 483 _notifyListenersOfSuccessfulCompletion(); 484 } 485 } 486 487 // If the throwable has not been handled by exception handlers, 488 // throw it. 489 if (initialThrowable != null) { 490 if (initialThrowable instanceof RuntimeException) { 491 // We do not handle runtime exception. 492 // Throw it. 493 throw (RuntimeException) initialThrowable; 494 } else if (initialThrowable instanceof KernelException) { 495 // Since this class is declared to throw 496 // KernelException, if we have one, we throw it. 497 throw (KernelException) initialThrowable; 498 } else if (initialThrowable instanceof RuntimeException) { 499 // We do not handle runtime exception. 500 // Throw it. 501 throw (RuntimeException) initialThrowable; 502 } else { 503 // Ok, it is not a KernelException, so we 504 // rethrow it as the cause of a KernelException 505 throw new IllegalActionException(this, initialThrowable, 506 null); 507 } 508 } 509 } 510 } 511 /* 512 System.out.println("Manager.execute() finished: " 513 + timeAndMemory(startTime)); 514 */ 515 } 516 517 /** Cause the system to exit after wrapup(). 518 * If the ptolemy.ptII.exitAfterWrapup property is <b>not</b> 519 * set, then when wrapup() is almost finished, we call System.exit(). 520 * If the ptolemy.ptII.exitAfterWrapup property is set, then 521 * we throw an Exception. 522 */ 523 public void exitAfterWrapup() { 524 _exitAfterWrapup = true; 525 _setState(EXITING); 526 } 527 528 /** If the state is not IDLE, set a flag to request that execution 529 * stop and exit in a completely deterministic fashion at the end 530 * of the next toplevel iteration. This method may be called 531 * from within an actor to stop the execution of the model. This 532 * will result in stop() being called on the top level 533 * CompositeActor, although not necessarily immediately. Note 534 * that this method is allowed to be called if the model is 535 * paused and actors that implement the stop() method must 536 * properly respond to that method even if the model is paused. 537 * @see Executable#stop 538 */ 539 public void finish() { 540 // Set this regardless of whether the model is running to 541 // avoid race conditions. The model may not have gotten around 542 // to starting when finish is requested. 543 _finishRequested = true; 544 545 if (_debugging) { 546 _debug("finish() has been called."); 547 } 548 549 if (_state == IDLE) { 550 // Don't need to invoke _disposeOfThreads() 551 // here because it is invoked in the finally clause 552 // of execute(). 553 // if (_thread != null || _shutdownThread != null) { 554 // _disposeOfThreads(); 555 // } 556 return; 557 } 558 559 Nameable container = getContainer(); 560 561 if (!(container instanceof CompositeActor)) { 562 throw new InternalErrorException( 563 "Attempted to call finish() on an executing manager " 564 + "with no associated CompositeActor model"); 565 } 566 567 // Used to just call stopFire() here, but this does not set 568 // the flag in the director so that isStopRequested() returns 569 // true. We have to set that flag or the actor threads in 570 // threaded domains will not know that a stop has been requested 571 // (vs. a pause). 572 ((CompositeActor) container).stop(); 573 574 Thread unpauser = new UnpauserThread(); 575 unpauser.start(); 576 } 577 578 /** Get the analysis with the given name, or return null if no such 579 * analysis exists. 580 * @param name The name of the analysis. 581 * @return the analysis with the given name, or null. 582 * @see #addAnalysis(String, Object) 583 */ 584 public Object getAnalysis(String name) { 585 if (_nameToAnalysis == null) { 586 return null; 587 } else { 588 return _nameToAnalysis.get(name); 589 } 590 } 591 592 /** Get the real time at which the model began executing. 593 * @return The real time at which the model began executing. 594 */ 595 public long getRealStartTime() { 596 return _afterInitTime; 597 } 598 599 /** Return the top-level composite actor for which this manager 600 * controls execution. 601 * @return The composite actor that this manager is responsible for. 602 */ 603 @Override 604 public NamedObj getContainer() { 605 if (_container == null) { 606 return null; 607 } 608 return _container.get(); 609 } 610 611 /** Return the iteration count, which is the number of iterations 612 * that have been started (but not necessarily completed). 613 * @return The number of iterations started. 614 */ 615 public int getIterationCount() { 616 return _iterationCount; 617 } 618 619 /** Return the workspace version on the last completion of 620 * preinitializeAndResolveTypes(). This can be used to optimize 621 * away actions on repeated runs when the workspace hasn't changed 622 * between runs. 623 * @return the workspace version on the last completion of 624 * {@link #preinitializeAndResolveTypes()}. 625 */ 626 public long getPreinitializeVersion() { 627 return _preinitializeVersion; 628 } 629 630 /** Return the current state of execution of the manager. 631 * @return The state of execution. 632 */ 633 public State getState() { 634 return _state; 635 } 636 637 /** Return any messages, such as the amount of time consumed. 638 * This method is called to update the status bar, so the 639 * output should be short. 640 * @return the message 641 * @see #setStatusMessage(String) 642 */ 643 public String getStatusMessage() { 644 return _statusMessage; 645 } 646 647 /** Get the execution identifier object for a throwable. 648 * 649 * <p> An execution identifier is an object given to the Manager 650 * via setExecutionIdentifier(), and cleared during preinitialize(). 651 * If the Manager notifies a listener of a model error, 652 * getExecutionIdentifier() can be used to map that error back to 653 * the executionIdentifier object. 654 * 655 * @param throwable The throwable. 656 * @return The execution identifier object if one was set, otherwise null. 657 * @see #setExecutionIdentifier(Object) 658 */ 659 public Object getExecutionIdentifier(Throwable throwable) { 660 // See http://bugzilla.ecoinformatics.org/show_bug.cgi?id=4230 661 662 // "In SDF provenance records to the error table an exception 663 // thrown after the workflow stops. In PN, multiple exceptions 664 // may be thrown, and this happens during execution. Right now 665 // there's a problem with these errors getting 666 // recorded. Related/in addition: there's also difficulty 667 // knowing which execution errors are correlated with, since 668 // the same workflow may be executing and throwing errors in 669 // multiple windows. As Dan notes: Manager reports exceptions 670 // asynchronously; need a way to tie an exception to 671 // corresponding execution." 672 673 // "The issue is that the Manager notifies listeners of model 674 // errors asynchronously to avoid deadlocks. However, this 675 // makes it impossible for a listener to associate a specific 676 // execution cycle with a given error." 677 return _throwableToExecutionIdentifier.get(throwable); 678 } 679 680 /** Return a thread that is waiting and can be 681 * interrupted in the event that a change request is made, 682 * or null to indicate that there is no thread waiting. 683 * @return The thread that is waiting, or null to indicate 684 * that no thread is waiting. 685 * @see #setWaitingThread(Thread) 686 */ 687 public Thread getWaitingThread() { 688 return _waitingThread; 689 } 690 691 /** Initialize the model. This calls the preinitialize() method of 692 * the container, followed by the resolveTypes() and initialize() methods. 693 * Set the Manager's state to PREINITIALIZING and INITIALIZING as 694 * appropriate. 695 * This method is read synchronized on the workspace. 696 * @exception KernelException If the model throws it. 697 * @exception IllegalActionException If the model is already running, or 698 * if there is no container. 699 */ 700 public synchronized void initialize() 701 throws KernelException, IllegalActionException { 702 try { 703 _workspace.getReadAccess(); 704 705 // Make sure that change requests are not executed when requested, 706 // but rather only executed when executeChangeRequests() is called. 707 setDeferringChangeRequests(true); 708 709 long startTime = new Date().getTime(); 710 preinitializeAndResolveTypes(); 711 if (System.currentTimeMillis() 712 - startTime > minimumStatisticsTime) { 713 setStatusMessage(timeAndMemory(startTime)); 714 System.out.println( 715 "preinitialize() finished: " + getStatusMessage()); 716 } 717 718 _setState(INITIALIZING); 719 if (_container == null || _container.get() == null) { 720 throw new InternalErrorException(this, null, 721 "The container of the manager was null. " 722 + "Try calling composite.setManager()."); 723 } 724 _container.get().initialize(); 725 726 // Since we have just initialized all actors, clear the 727 // list of actors pending initialization. 728 _actorsToInitialize.clear(); 729 730 executeChangeRequests(); 731 } finally { 732 _workspace.doneReading(); 733 } 734 } 735 736 /** Indicate that resolved types in the system may no longer be valid. 737 * This will force type resolution to be redone on the next iteration. 738 */ 739 public void invalidateResolvedTypes() { 740 _typesResolved = false; 741 } 742 743 /** Return true if exitAfterWrapup() was called. 744 * @return true if exitAfterWrapup was called. 745 */ 746 public boolean isExitingAfterWrapup() { 747 return _exitAfterWrapup; 748 } 749 750 /** Invoke one iteration of the model. An iteration consists of 751 * first performing changes queued with requestChange() 752 * and type resolution, if necessary, and then 753 * invoking prefire(), fire(), and postfire(), in that 754 * order. If prefire() returns false, then fire() and postfire() are not 755 * invoked, and true is returned. 756 * Otherwise, fire() will be called once, followed by 757 * postfire(). The return value of postfire() is returned. 758 * Note that this method ignores finish and pause requests 759 * and thus determines a minimum granularity of the execution. 760 * Set the state of the manager to ITERATING. 761 * This method is read synchronized on the workspace. 762 * 763 * @return True if postfire() is not called, otherwise, return 764 * the value returned by postfire(). 765 * 766 * @exception KernelException If the model throws it, or if there 767 * is no container. 768 */ 769 public boolean iterate() throws KernelException { 770 if (_container == null || _container.get() == null) { 771 throw new IllegalActionException(this, "No model to execute! " 772 + "Try calling composite.setManager()"); 773 } 774 775 boolean result = true; 776 777 long startTime = new Date().getTime(); 778 // Execute the change requests before acquiring read access on the 779 // workspace. The reason for this is that the change requests are safe 780 // anyway, since they acquire write access on the workspace. 781 // But while copying the change request list in the NamedObj 782 // executeChangeRequest method, this thread will try to acquire a lock 783 // on a local NamedObj object called _changeLock. 784 // If it blocks, it will hold a read lock on the workspace. 785 // Meanwhile, the thread that holds the lock on _changeLock 786 // may attempt to acquire write permission on the workspace (WHY???). 787 executeChangeRequests(); 788 try { 789 _workspace.getReadAccess(); 790 791 // We should infer the widths before preinitializing the container, since the latter 792 // will create the receivers for which it needs the widths of the relations. 793 if (IORelation._USE_NEW_WIDTH_INFERENCE_ALGO) { 794 _inferWidths(); 795 } 796 797 // Pre-initialize actors that have been added. 798 for (Actor actor : _actorsToInitialize) { 799 // Do not attempt to preinitialize transparent composite actors. 800 // Note that the cast is safe, as everything in Ptolemy that 801 // is an actor is also a ComponentEntity. 802 if (((ComponentEntity) actor).isOpaque()) { 803 actor.getExecutiveDirector().preinitialize(actor); 804 } 805 806 // NOTE: To see why this is no longer needed, see the comment 807 // above for the commented out call to validateSettables(). 808 /* 809 if (actor instanceof NamedObj) { 810 ((NamedObj) actor).validateSettables(); 811 } 812 */ 813 } 814 if (System.currentTimeMillis() 815 - startTime > minimumStatisticsTime) { 816 setStatusMessage(timeAndMemory(startTime)); 817 System.out 818 .println("Manager.iterate(): preinitialize() finished: " 819 + getStatusMessage()); 820 } 821 822 if (!_typesResolved) { 823 resolveTypes(); 824 _typesResolved = true; 825 } 826 827 _iterationCount++; 828 _setState(ITERATING); 829 830 // Perform domain-specific initialization on the actor. 831 // Do not attempt to initialize transparent composite actors. 832 // Note that the cast is safe, as everything in Ptolemy that 833 // is an actor is also a ComponentEntity. 834 for (Actor actor : _actorsToInitialize) { 835 if (((ComponentEntity) actor).isOpaque()) { 836 actor.getExecutiveDirector().initialize(actor); 837 } 838 } 839 840 _actorsToInitialize.clear(); 841 842 // Note that if prefire() returns false, then postfire() 843 // is *not* called and this method will return true, which 844 // indicate to a caller of this method that iterate() 845 // could be called again. This is because if prefire 846 // returns false, it means "I don't want to be fired now." 847 // If postfire returns false, it means "I don't want to 848 // ever be fired again." 849 CompositeActor container = _container.get(); 850 if (container.prefire()) { 851 container.fire(); 852 result = container.postfire(); 853 } 854 } finally { 855 _workspace.doneReading(); 856 } 857 858 return result; 859 } 860 861 /** Notify all the execution listeners of an exception. 862 * If there are no listeners, then print the exception information 863 * to the standard error stream. This is intended to be used by threads 864 * that are involved in an execution as a mechanism for reporting 865 * errors. As an example, in a threaded domain, each thread 866 * should catch all exceptions and report them using this method. 867 * This method is merely calls 868 * {@link #notifyListenersOfThrowable(Throwable)}. 869 * @param exception The exception. 870 */ 871 public void notifyListenersOfException(Exception exception) { 872 notifyListenersOfThrowable(exception); 873 } 874 875 /** Notify all the execution listeners of a Throwable. 876 * If there are no listeners, then print the throwable information 877 * to the standard error stream. This is intended to be used by threads 878 * that are involved in an execution as a mechanism for reporting 879 * errors. As an example, in a threaded domain, each thread 880 * should catch all exceptions and report them using this method. 881 * This method defers the actual reporting to a new thread 882 * because it requires obtaining a lock on this manager, and that 883 * could cause deadlock. 884 * @param throwable The throwable 885 */ 886 public void notifyListenersOfThrowable(final Throwable throwable) { 887 Thread thread = new ErrorReportingThread("Error reporting thread", 888 throwable); 889 thread.start(); 890 } 891 892 /** Set a flag requesting that execution pause at the next opportunity 893 * (between iterations). This method calls stopFire() on the 894 * toplevel composite actor to ensure that the manager's execution 895 * thread becomes active again. Actors are expected to react to 896 * stopFire() by returning as soon as possible from their fire() 897 * methods, thus completing an iteration. For example, in the case 898 * of PN, an iteration only ends if deadlock occurs, which may 899 * never happen. Calling stopFire() truncates the iteration. 900 * The thread controlling the execution (the one that calls execute()) 901 * will be suspended the next time through the iteration loop. 902 * To resume execution, call resume(). 903 * @see Executable#stopFire 904 */ 905 public void pause() { 906 _pauseRequested = true; 907 908 Nameable container = getContainer(); 909 910 if (!(container instanceof CompositeActor)) { 911 throw new InternalErrorException( 912 "Attempted to call pause() on an executing manager " 913 + "with no associated CompositeActor model"); 914 } 915 916 ((CompositeActor) container).stopFire(); 917 } 918 919 /** The thread that calls this method will wait until resume() has 920 * been called. 921 * 922 * <p>Note: This method will block. It should only be called 923 * from the executing thread (the thread that is executing the 924 * model). Do not call this method from the same thread that 925 * will call resume(). 926 * @param breakpointMessage The message to print when paused on a 927 * breakpoint. 928 */ 929 public void pauseOnBreakpoint(String breakpointMessage) { 930 // FIXME: Added by celaine. Review this. Works with 931 // DebugController to resume execution after a breakpoint. 932 // FIXME: in PN this could be called multiple times. make sure 933 // this still works with multiple threads. 934 try { 935 if (_state == ITERATING) { 936 // This will deadlock if called from, say, the UI 937 // thread, because execute() holds the lock. 938 synchronized (this) { 939 if (_state == ITERATING) { 940 // Set the new state to show that execution is paused 941 // on a breakpoint. 942 PAUSED_ON_BREAKPOINT.setDescription( 943 "pausing on breakpoint: " + breakpointMessage 944 + ". Click Resume to continue."); 945 _setState(PAUSED_ON_BREAKPOINT); 946 947 _resumeNotifyWaiting = true; 948 949 // Wait until resume() is called. 950 while (_resumeNotifyWaiting) { 951 wait(); 952 } 953 954 // resume() has been called, so reset the state of the 955 // execution. 956 _setState(ITERATING); 957 } else { //if (_state == ITERATING) { 958 throw new InternalErrorException("State was changed " 959 + "while pauseOnBreakpoint was called."); 960 } 961 } //synchronized(this) { 962 } else { //if (_state == ITERATING) { 963 throw new InternalErrorException("pauseOnBreakpoint occurred " 964 + "while not iterating the model."); 965 } 966 } catch (InterruptedException error) { 967 throw new InternalErrorException("Interrupted while trying to " 968 + "wait for resume() method to be called."); 969 } 970 } 971 972 /** Preinitialize the model. This calls the preinitialize() 973 * method of the container, followed by the resolveTypes() 974 * methods. Set the Manager's state to PREINITIALIZING. Note 975 * that this method may be invoked without actually running the 976 * method, but the calling code must make sure that the Manager's 977 * state is reset to IDLE. This method is read synchronized on 978 * the workspace. 979 * @exception KernelException If the model throws it. 980 * @exception IllegalActionException If the model is already running, or 981 * if there is no container. 982 */ 983 public synchronized void preinitializeAndResolveTypes() 984 throws KernelException { 985 try { 986 _workspace.getReadAccess(); 987 988 if (_state != IDLE) { 989 throw new IllegalActionException(this, 990 "The model is not idle, it is " 991 + _state.getDescription()); 992 } 993 994 if (_container == null || _container.get() == null) { 995 throw new IllegalActionException(this, "No model to run! " 996 + "Try calling composite.setManager()."); 997 } 998 999 _setState(PREINITIALIZING); 1000 1001 _exitAfterWrapup = false; 1002 _pauseRequested = false; 1003 _typesResolved = false; 1004 _iterationCount = 0; 1005 _executionIdentifier = null; 1006 1007 _resumeNotifyWaiting = false; 1008 1009 // NOTE: Used to call validateSettables() here with the following 1010 // note. However, this call is very expensive and means that 1011 // second runs are no faster than first runs. 1012 // NOTE: This is needed because setExpression() on parameters 1013 // does not necessarily trigger their evaluation. Thus, 1014 // if one calls setExpression() without calling validate(), 1015 // then the new value will never be seen. Note that the 1016 // MoML parser and Vergil's parameter editor both validate 1017 // variables. But if a model is created some other way, 1018 // for example in a test suite using Tcl or in Java, 1019 // then the user might not think to call validate(), and 1020 // it would seem counterintuitive to have to do so. 1021 // _container.validateSettables(); 1022 1023 // Clear the preinitialization analyses... Ensure that 1024 // We get current analysis. 1025 if (_nameToAnalysis != null) { 1026 _nameToAnalysis.clear(); 1027 _nameToAnalysis = null; 1028 } 1029 1030 // Initialize the topology. 1031 // NOTE: Some actors require that parameters be set prior 1032 // to preinitialize(). Hence, this occurs after the call 1033 // above to validateSettables(). This makes sense, since the 1034 // preinitialize() method may depend on these parameters. 1035 // E.g., in CT higher-order components, such as 1036 // ContinuousTransferFunction, during preinitialize(), 1037 // the inside of the higher-order components is constructed 1038 // based on the parameter values. 1039 // EAL 5/31/02. 1040 _container.get().preinitialize(); 1041 //_container.createReceivers(); // Undid this change temporarily since the move of createReceivers breaks HDF 1042 //_container.createSchedule(); // Undid this change temporarily since the move of createReceivers breaks HDF 1043 executeChangeRequests(); 1044 1045 // Infer widths (if not already done) 1046 // NOTE: This has most likely already been done, since it is done 1047 // when receivers are created, which occurs earlier in preinitialize(). 1048 if (IORelation._USE_NEW_WIDTH_INFERENCE_ALGO) { 1049 _inferWidths(); 1050 } 1051 1052 resolveTypes(); 1053 _typesResolved = true; 1054 _preinitializeVersion = _workspace.getVersion(); 1055 } finally { 1056 // Clear the preinitialization analyses. 1057 if (_nameToAnalysis != null) { 1058 _nameToAnalysis.clear(); 1059 _nameToAnalysis = null; 1060 } 1061 1062 _workspace.doneReading(); 1063 } 1064 } 1065 1066 /** If the workspace version has changed since the last invocation 1067 * of preinitializeAndResolveTypes(), then invoke it now and set 1068 * the state of the Manager to IDLE upon completion. This can be used 1069 * during editing a model to check types, to expand higher-order 1070 * components, or to establish connections between Publisher and 1071 * Subscriber actors. 1072 * @exception KernelException If thrown while preinitializing 1073 * and resolving types. 1074 */ 1075 public void preinitializeIfNecessary() throws KernelException { 1076 try { 1077 if (_preinitializeVersion != _workspace.getVersion()) { 1078 preinitializeAndResolveTypes(); 1079 } 1080 } finally { 1081 _setState(IDLE); 1082 } 1083 } 1084 1085 /** Invoke preinitialize() and wrapup(). 1086 * 1087 * <p>If the model has not been preinitialized since the last 1088 * change to its structure, that must be done now for the result 1089 * to be accurate. This is because higher-order components 1090 * and Publisher and Subscriber connections may not have yet 1091 * been created.</p> 1092 * 1093 * @param actor The actor upon which to call preinitialize() on 1094 * its toplevel. 1095 * @exception KernelException If thrown when a Manager is added to 1096 * the top level or if preinitialize() fails. 1097 */ 1098 public static void preinitializeThenWrapup(Actor actor) 1099 throws KernelException { 1100 // If preinitialize() has not yet been called, then we don't 1101 // yet know what Subscribers are using connected to the 1102 // Publisher. 1103 Manager manager = actor.getManager(); 1104 if (manager == null) { 1105 CompositeActor toplevel = (CompositeActor) ((NamedObj) actor) 1106 .toplevel(); 1107 manager = new Manager(toplevel.workspace(), "PubManager"); 1108 toplevel.setManager(manager); 1109 } 1110 try { 1111 // Create connections between Publishers and Subscribers. 1112 manager.preinitializeIfNecessary(); 1113 } finally { 1114 try { 1115 // FIXME: should this be synchronized on this? 1116 if (manager.getState() != IDLE 1117 && manager.getState() != WRAPPING_UP) { 1118 manager.wrapup(); 1119 } 1120 } catch (Throwable throwable) { 1121 // The Exit actor causes Manager.wrapup() to throw this. 1122 if (!manager.isExitingAfterWrapup()) { 1123 throw new IllegalActionException(actor, throwable, 1124 "Manager.wrapup() failed."); 1125 } 1126 } 1127 } 1128 } 1129 1130 /** Remove a listener from the list of listeners that are notified 1131 * of execution events. If the specified listener is not on the list, 1132 * do nothing. 1133 * @param listener The listener to remove. 1134 * @see #addExecutionListener(ExecutionListener) 1135 */ 1136 public void removeExecutionListener(ExecutionListener listener) { 1137 if (listener == null || _executionListeners == null) { 1138 return; 1139 } 1140 List<WeakReference<ExecutionListener>> toRemove = new LinkedList<WeakReference<ExecutionListener>>(); 1141 for (WeakReference<ExecutionListener> reference : _executionListeners) { 1142 if (reference.get() == listener) { 1143 toRemove.add(reference); 1144 } 1145 } 1146 _executionListeners.removeAll(toRemove); 1147 } 1148 1149 /** Queue an initialization request. 1150 * The specified actor will be initialized at an appropriate time, 1151 * in the iterate() method, by calling its preinitialize() 1152 * and initialize() methods. This method should be called when an 1153 * actor is added to a model through a mutation in order to properly 1154 * initialize the actor. 1155 * @param actor The actor to initialize. 1156 */ 1157 public void requestInitialization(Actor actor) { 1158 // Only initialize once. 1159 if (_actorsToInitialize.contains(actor)) { 1160 return; 1161 } 1162 // Only initialize containers. This avoids initializing an 1163 // actor twice when it is added as part of a container that is 1164 // being added. 1165 { 1166 NamedObj container = actor.getContainer(); 1167 1168 while (container != null) { 1169 if (_actorsToInitialize.contains(container)) { 1170 return; 1171 } 1172 1173 container = container.getContainer(); 1174 } 1175 } 1176 1177 // OK, then we need to initialize this actor. However, we 1178 // don't need to initialize any actors contained by this 1179 // actor. 1180 if (actor instanceof CompositeEntity) { 1181 List<Actor> list = new LinkedList<Actor>(_actorsToInitialize); 1182 for (Actor otherActor : list) { 1183 if (((CompositeEntity) actor) 1184 .deepContains((NamedObj) otherActor)) { 1185 _actorsToInitialize.remove(otherActor); 1186 } 1187 } 1188 } 1189 1190 // Lastly, add this actor to the actors to initialize. 1191 _actorsToInitialize.add(actor); 1192 } 1193 1194 /** Check types on all the connections and resolve undeclared types. 1195 * If the container is not an instance of TypedCompositeActor, 1196 * do nothing. 1197 * Set the Manager's state to RESOLVING_TYPES. 1198 * This method is write-synchronized on the workspace. 1199 * @exception TypeConflictException If a type conflict is detected. 1200 */ 1201 public void resolveTypes() throws TypeConflictException { 1202 if (!(_container.get() instanceof TypedCompositeActor)) { 1203 return; 1204 } 1205 1206 try { 1207 _workspace.getReadAccess(); 1208 _setState(RESOLVING_TYPES); 1209 1210 TypedCompositeActor 1211 .resolveTypes((TypedCompositeActor) _container.get()); 1212 } finally { 1213 _workspace.doneReading(); 1214 } 1215 } 1216 1217 /** If the model is paused, resume execution. This method must 1218 * be called from a different thread than that controlling the 1219 * execution, since the thread controlling the execution is 1220 * suspended. 1221 */ 1222 public void resume() { 1223 // Avoid the case when the director is not actually paused causing the 1224 // swing thread to block. 1225 if (_state == PAUSED) { 1226 synchronized (this) { 1227 if (_state == PAUSED) { 1228 _pauseRequested = false; 1229 notifyAll(); 1230 } else { 1231 throw new InternalErrorException("resume() should be the " 1232 + "only method that goes from " 1233 + "PAUSED to not paused"); 1234 } 1235 } 1236 } else if (_state == PAUSED_ON_BREAKPOINT) { 1237 synchronized (this) { 1238 if (_state == PAUSED_ON_BREAKPOINT) { 1239 // Notify all threads waiting to know whether resume() has 1240 // been called (threads that called waitForResume()). 1241 // 1242 // Works with DebugController to resume execution after a 1243 // breakpoint. 1244 if (_resumeNotifyWaiting) { 1245 _resumeNotifyWaiting = false; 1246 notifyAll(); 1247 } 1248 } 1249 } 1250 } 1251 } 1252 1253 /** Execute the model, catching all exceptions. Use this method to 1254 * execute the model within the calling thread, but to not throw 1255 * exceptions. Instead, the exception is handled using the 1256 * notifyListenersOfException() method. Except for its 1257 * exception handling, this method has exactly the same behavior 1258 * as execute(). 1259 */ 1260 @Override 1261 public void run() { 1262 try { 1263 execute(); 1264 } catch (Throwable throwable) { 1265 // If running tried to load in some native code using JNI 1266 // then we may get an Error here 1267 notifyListenersOfThrowable(throwable); 1268 1269 // Used to call _disposeOfThreads() here, but now exeucte() 1270 // calls it in its finally block. 1271 // } finally { 1272 // _disposeOfThreads(); 1273 1274 } 1275 } 1276 1277 /** Set the execution identifier object. Any throwables that occur 1278 * in current execution cycle are associated with this 1279 * identifier. The execution identifier is reset in 1280 * preinitialize(). 1281 * 1282 * @param executionIdentifier The execution identifier object 1283 * @see #getExecutionIdentifier(Throwable) 1284 */ 1285 public void setExecutionIdentifier(Object executionIdentifier) { 1286 _executionIdentifier = executionIdentifier; 1287 } 1288 1289 /** Set the status message, such as the amount of time consumed. 1290 * This method is called to update the status bar, so the 1291 * output should be short. 1292 * @param message The message to be displayed. 1293 * @see #getStatusMessage() 1294 */ 1295 public void setStatusMessage(String message) { 1296 _statusMessage = message; 1297 } 1298 1299 /** Indicate that the specified thread is waiting and can be 1300 * interrupted in the event that a change request is made. 1301 * @param thread The thread that is waiting, or null to indicate 1302 * that no thread is waiting. 1303 * @see #getWaitingThread() 1304 */ 1305 public void setWaitingThread(Thread thread) { 1306 _waitingThread = thread; 1307 } 1308 1309 /** Return a short description of the throwable. 1310 * @param throwable The throwable 1311 * @return If the throwable is an Exception, return "Exception", 1312 * if it is an Error, return "Error", if it is a Throwable, return 1313 * "Throwable". 1314 * @deprecated Instead ptolemy.util.MessageHandler.shortDescription() 1315 */ 1316 @Deprecated 1317 public static String shortDescription(Throwable throwable) { 1318 return MessageHandler.shortDescription(throwable); 1319 } 1320 1321 /** Start an execution in another thread and return. Any exceptions 1322 * that occur during the execution of the model are handled by 1323 * the notifyListenersOfException() method. 1324 * @exception IllegalActionException If the model is already running, 1325 * e.g. the state is not IDLE. 1326 */ 1327 public void startRun() throws IllegalActionException { 1328 if (_state != IDLE) { 1329 throw new IllegalActionException(this, 1330 "Model is " + _state.getDescription()); 1331 } 1332 1333 // Set this within the calling thread to avoid race conditions 1334 // where finish() might be called before the spawned thread 1335 // actually starts up. 1336 _finishRequested = false; 1337 _thread = new PtolemyRunThread(this, _container.get().getName()); 1338 // Priority set to the minimum to get responsive UI during execution. 1339 _thread.setPriority(Thread.MIN_PRIORITY); 1340 _thread.start(); 1341 } 1342 1343 /** If the state is not IDLE, set a flag to request that 1344 * execution stop and exit in a completely deterministic fashion 1345 * at the end of the next toplevel iteration. This method may 1346 * be called from within an actor to stop the execution of the model. 1347 * This will result in stop() being called on the top level 1348 * CompositeActor, although not necessarily immediately. 1349 * This is basically an alias for finish(). 1350 * 1351 * <p> Note that in general, it is best to get that director 1352 * and call finish() and stopFire() on the director than 1353 * it is to call Manager.stop().</p> 1354 * 1355 * <p> The reason that it is better to call Director.finish() 1356 * is that if Manager.stop() is called inside a RunCompositeActor 1357 * then only the inside execution will be stopped, not 1358 * the outside one. It is also not correct to call stop() 1359 * on the directory because Director.stop() requests immediate 1360 * stopping. To give determinate stopping, call Director.finish() 1361 * so that the current iteration is completed.</p> 1362 * 1363 * <p>In multithreaded domains, Director.stopFire is called 1364 * to request that all actors conclude ongoing firings.</p> 1365 */ 1366 public void stop() { 1367 finish(); 1368 } 1369 1370 /** Terminate the currently executing model with extreme prejudice. 1371 * This leaves the state of the manager in CORRUPTED, which means 1372 * that the model cannot be executed again. A new model must be 1373 * created, with a new manager, to execute again. 1374 * This method is not intended to be used as a normal route of 1375 * stopping execution. To normally stop execution, call the finish() 1376 * method instead. This method should be called only 1377 * when execution fails to terminate by normal means due to certain 1378 * kinds of programming errors (infinite loops, threading errors, etc.). 1379 * <p> 1380 * If the model execution was started in a separate thread (using 1381 * startRun()), then that thread is killed unceremoniously (using 1382 * a method that is now deprecated in Java, for obvious reasons). 1383 * This method also calls terminate on the toplevel composite actor. 1384 * <p> 1385 * This method is not synchronized because we want it to 1386 * execute as soon as possible. 1387 * @deprecated 1388 */ 1389 @Deprecated 1390 public void terminate() { 1391 // If the execution was started in a separate thread, kill that thread. 1392 // NOTE: This uses the stop() method, which is now deprecated in Java. 1393 // Indeed it should be, since it terminates a thread 1394 // nondeterministically, and can leave any objects that the thread 1395 // operating on in an inconsistent state. 1396 if (_thread != null) { 1397 // NOTE: stop() in java.lang.Thread has been deprecated 1398 _thread.stop(); 1399 1400 try { 1401 _thread.join(); 1402 } catch (InterruptedException e) { 1403 // This will usually get thrown, since we are 1404 // forcibly terminating 1405 // the thread. We just ignore it. 1406 } 1407 1408 _disposeOfThreads(); 1409 } 1410 1411 // Terminate the entire hierarchy as best we can. 1412 if (_container != null && _container.get() != null) { 1413 _container.get().terminate(); 1414 } 1415 _setState(CORRUPTED); 1416 } 1417 1418 /** Return a string with the elapsed time since startTime, and 1419 * the amount of memory used. 1420 * @param startTime The start time in milliseconds. For example, 1421 * the value returned by <code>(new Date()).getTime()</code>. 1422 * @return A string with the elapsed time since startTime, and 1423 * the amount of memory used. 1424 */ 1425 public static String timeAndMemory(long startTime) { 1426 Runtime runtime = Runtime.getRuntime(); 1427 long totalMemory = runtime.totalMemory() / 1024; 1428 long freeMemory = runtime.freeMemory() / 1024; 1429 return timeAndMemory(startTime, totalMemory, freeMemory); 1430 } 1431 1432 /** Return a string with the elapsed time since startTime, and 1433 * the amount of memory used. 1434 * This method takes a java.lang.Long object so that ptjacl 1435 * can properly pass a long number: 1436 * <pre> 1437 * set currentTime [java::call -noconvert java.lang.System currentTimeMillis] 1438 * java::call ptolemy.actor.Manager timeAndMemoryLong $x 1439 * </pre> 1440 * @param startTime The start time in milliseconds. For example, 1441 * the value returned by <code>(new Date()).getTime()</code>. 1442 * @return A string with the elapsed time since startTime, and 1443 * the amount of memory used. 1444 */ 1445 public static String timeAndMemoryLong(Long startTime) { 1446 1447 return timeAndMemory(startTime.longValue()); 1448 } 1449 1450 /** Return a string with the elapsed time since startTime, 1451 * and the amount of memory used. 1452 * the value returned by <code>(new Date()).getTime()</code>. 1453 * @param startTime The start time in milliseconds. For example, 1454 * the value returned by <code>(new Date()).getTime()</code>. 1455 * @param totalMemory The total amount of memory used in kilobytes. 1456 * @param freeMemory The total amount of memory free in kilobytes. 1457 * @return A string with the elapsed time since startTime, and 1458 * the amount of memory used. 1459 */ 1460 public static String timeAndMemory(long startTime, long totalMemory, 1461 long freeMemory) { 1462 return System.currentTimeMillis() - startTime + " ms. Memory: " 1463 + totalMemory + "K Free: " + freeMemory + "K (" 1464 + Math.round((double) freeMemory / (double) totalMemory * 100.0) 1465 + "%)"; 1466 } 1467 1468 /** If there is an active thread created by startRun(), then wait 1469 * for it to complete and return. The wait is accomplished by 1470 * calling the join() method on the thread. If there is no 1471 * active thread, then wait until the manager state is idle 1472 * by calling wait(). 1473 * @see #startRun() 1474 */ 1475 public void waitForCompletion() { 1476 if (_thread != null) { 1477 try { 1478 _thread.join(); 1479 } catch (InterruptedException ex) { 1480 // Ignore this and return. 1481 } 1482 } else { 1483 // NOTE: Previously, execute() was a synchronized method. 1484 // Result: This would almost certainly deadlock if called 1485 // from a thread apart from the executing thread because execute() 1486 // is synchronized, so the running thread holds the lock! 1487 // NOTE: Synchronizing here is not correct. 1488 // See Workspace.wait(Object) 1489 // synchronized (this) { 1490 while (getState() != IDLE && getState() != CORRUPTED) { 1491 try { 1492 workspace().wait(this); 1493 } catch (InterruptedException ex) { 1494 break; 1495 } 1496 } 1497 _disposeOfThreads(); 1498 // } 1499 } 1500 } 1501 1502 /** Wrap up the model by invoking the wrapup method of the toplevel 1503 * composite actor. 1504 * At the end of this model, the state is set to idle. 1505 * @exception KernelException If the model throws it. 1506 * @exception IllegalActionException If the model is idle or already 1507 * wrapping up, or if there is no container. 1508 */ 1509 public void wrapup() throws KernelException, IllegalActionException { 1510 try { 1511 // NOTE: This method used to be synchronized, but we cannot 1512 // hold the lock on the director during wrapup because it 1513 // will cause deadlock. Instead, we use a small barrier 1514 // here to check and set the state. 1515 synchronized (this) { 1516 if (_state == IDLE || _state == WRAPPING_UP) { 1517 throw new IllegalActionException(this, 1518 "Cannot wrap up. The current state is: " 1519 + _state.getDescription()); 1520 } 1521 1522 if (_container == null || _container.get() == null) { 1523 throw new IllegalActionException(this, "No model to run!"); 1524 } 1525 1526 _setState(WRAPPING_UP); 1527 } 1528 1529 // Wrap up the topology 1530 _container.get().wrapup(); 1531 1532 // Process all change requests. If the model reaches this wrap up 1533 // state due to the occurrence of an exception during execution, 1534 // some change requests may be pending. If these requests 1535 // are not processed, they will be left to the next execution. 1536 // Also, wrapping up execution may cause change requests to be queued. 1537 // Also, at the same time, re-enable immediate execution of 1538 // change requests. 1539 setDeferringChangeRequests(false); 1540 1541 // NOTE: This used to increment the workspace 1542 // version, which would require that everything 1543 // be re-done on subsequent runs. EAL 9/16/06 1544 // _workspace.incrVersion(); 1545 1546 if (_exitAfterWrapup) { 1547 // If the ptolemy.ptII.exitAfterWrapup property is set, 1548 // then we don't actually exit. 1549 StringUtilities.exit(0); 1550 } 1551 } finally { 1552 // We must set the state to IDLE here even if 1553 // we entered wrapup() and the state was IDLE or WRAPPING_UP. 1554 // If we don't set the state to IDLE, then if an accessor 1555 // has an error in wrapup, the model will always be 1556 // stuck in WRAPPING_UP. 1557 _setState(IDLE); 1558 } 1559 } 1560 1561 /////////////////////////////////////////////////////////////////// 1562 //// public variables //// 1563 1564 /** The minimum amount of time that may elapse during certain 1565 * operations before statistics are generated. The Manager and 1566 * other classes in Ptolemy will print out statistics if the 1567 * amount of time (in milliseconds) named by this variable 1568 * elapses during certain steps such as preinitialize(). 1569 * The initial default value is 10000, meaning that certain 1570 * operations can take up to 10 seconds before statistics 1571 * are printed. 1572 * @see ptolemy.kernel.CompositeEntity#statistics(String) 1573 */ 1574 public static int minimumStatisticsTime = 10000; 1575 1576 /** The amount of time to allow for the model to terminate 1577 * gracefully before shutting it down when the JVM is shut down 1578 * due to control-C, user logging out, etc. 1579 */ 1580 public static long SHUTDOWN_TIME = 30000L; 1581 1582 /////////////////////////////////////////////////////////////////// 1583 //// protected methods //// 1584 1585 /** Make this manager the manager of the specified composite 1586 * actor. If the composite actor is not null, then the manager is 1587 * removed from the directory of the workspace. If the composite 1588 * actor is null, then the manager is <b>not</b> returned to the 1589 * directory of the workspace, which may result in it being 1590 * garbage collected. This method should not be called directly. 1591 * Instead, call setManager in the CompositeActor class (or a 1592 * derived class). 1593 * @param compositeActor The composite actor that this manager will 1594 * manage. 1595 */ 1596 protected void _makeManagerOf(CompositeActor compositeActor) { 1597 if (compositeActor != null) { 1598 _workspace.remove(this); 1599 } else { 1600 _disposeOfThreads(); 1601 } 1602 1603 _container = new WeakReference<CompositeActor>(compositeActor); 1604 } 1605 1606 /** Notify listeners that execution has completed. 1607 * @deprecated Incomplete name, use 1608 * {@link #_notifyListenersOfSuccessfulCompletion()} 1609 */ 1610 @Deprecated 1611 protected synchronized void _notifyListenersOfCompletion() { 1612 _notifyListenersOfSuccessfulCompletion(); 1613 } 1614 1615 /** Notify listeners that execution has completed successfully. 1616 */ 1617 protected synchronized void _notifyListenersOfSuccessfulCompletion() { 1618 if (_debugging) { 1619 _debug("-- Manager completed execution with " + _iterationCount 1620 + " iterations"); 1621 } 1622 1623 if (_executionListeners != null) { 1624 ListIterator<WeakReference<ExecutionListener>> listeners = _executionListeners 1625 .listIterator(); 1626 1627 while (listeners.hasNext()) { 1628 WeakReference<ExecutionListener> reference = listeners.next(); 1629 ExecutionListener listener = reference.get(); 1630 1631 if (listener != null) { 1632 listener.executionFinished(this); 1633 } else { 1634 listeners.remove(); 1635 } 1636 } 1637 } 1638 } 1639 1640 /** Propagate the state change event to all the execution listeners. 1641 */ 1642 protected void _notifyListenersOfStateChange() { 1643 if (_debugging) { 1644 _debug("-- Manager state is now: " + _state.getDescription()); 1645 } 1646 1647 if (_executionListeners != null) { 1648 ListIterator<WeakReference<ExecutionListener>> listeners = _executionListeners 1649 .listIterator(); 1650 1651 while (listeners.hasNext()) { 1652 WeakReference<ExecutionListener> reference = listeners.next(); 1653 ExecutionListener listener = reference.get(); 1654 1655 if (listener != null) { 1656 listener.managerStateChanged(this); 1657 } else { 1658 listeners.remove(); 1659 } 1660 } 1661 } 1662 } 1663 1664 /** Register a shutdown hook to gracefully stop the execution of a model 1665 * if the JVM is shut down (by control-C, the user logging out, etc.). 1666 */ 1667 protected void _registerShutdownHook() { 1668 _shutdownThread = new Thread() { 1669 @Override 1670 public void run() { 1671 if (_state != IDLE) { 1672 System.out.println( 1673 "# Manager._registerShutdownHook(): State is " 1674 + _state 1675 + ", which is not IDLE. Waiting for model to stop."); 1676 } 1677 finish(); 1678 if (_thread != null && _thread.isAlive()) { 1679 try { 1680 // This seems dangerous. Could prevent the process 1681 // from dying. We use a timeout here of 30 seconds. 1682 _thread.join(SHUTDOWN_TIME); 1683 } catch (InterruptedException e) { 1684 // Failed to stop the thread. 1685 e.printStackTrace(); 1686 } 1687 } 1688 } 1689 }; 1690 try { 1691 Runtime.getRuntime().addShutdownHook(_shutdownThread); 1692 } catch (java.security.AccessControlException ex) { 1693 // This exception gets triggered by 1694 // http://ptolemy.eecs.berkeley.edu/ptolemyII/ptII10.0/ptII10.0.devel/ptolemy/vergil/Vergil.htm 1695 System.out.println("Warning: failed to add a shutdown hook." 1696 + "(Running a model in an applet always causes this)"); 1697 } 1698 } 1699 1700 /** Set the state of execution and notify listeners if the state 1701 * actually changes. 1702 * @param newState The new state. 1703 */ 1704 protected synchronized void _setState(State newState) { 1705 if (_state != newState) { 1706 _state = newState; 1707 _notifyListenersOfStateChange(); 1708 notifyAll(); 1709 } 1710 } 1711 1712 /////////////////////////////////////////////////////////////////// 1713 //// private methods //// 1714 1715 /** Dispose of the thread by removing it from the workspace and 1716 * setting it to null. Also, remove the shutdown thread. 1717 */ 1718 private void _disposeOfThreads() { 1719 // FIXME: Should we acquire the read lock on the Workspace and 1720 // then have a version of doneReading that cleans up? 1721 // FIXME: Should we check to see if the Manager is idle here? 1722 _thread = null; 1723 1724 // FIXME: Should this be synchronized? 1725 if (_shutdownThread != null) { 1726 Runtime.getRuntime().removeShutdownHook(_shutdownThread); 1727 _shutdownThread = null; 1728 } 1729 } 1730 1731 /** 1732 * Infer the width of the relations for which no width has been 1733 * specified yet. 1734 * This method will set the state to INFERING_WIDTHS and change 1735 * it back afterwards. 1736 * @exception IllegalActionException If the widths of the relations at 1737 * port are not consistent or if the width cannot be inferred 1738 * for a relation. 1739 */ 1740 private void _inferWidths() throws IllegalActionException { 1741 if (_container == null || _container.get() == null) { 1742 throw new NullPointerException("The container of the manager " 1743 + getFullName() + " was null. " 1744 + "Try calling composite.setManager()."); 1745 } 1746 if (_container.get().needsWidthInference()) { 1747 State previousState = _state; 1748 try { 1749 _setState(INFERING_WIDTHS); 1750 _container.get().inferWidths(); 1751 } finally { 1752 _setState(previousState); 1753 } 1754 } 1755 } 1756 1757 /////////////////////////////////////////////////////////////////// 1758 //// private variables //// 1759 // A list of actors with pending initialization. 1760 private List<Actor> _actorsToInitialize = new LinkedList<Actor>(); 1761 1762 /** The real time at which the model begins executing. */ 1763 private long _afterInitTime = 0; 1764 1765 // The top-level CompositeActor that contains this Manager 1766 private WeakReference<CompositeActor> _container = null; 1767 1768 /** An execution identifier. See 1769 * #getExecutionIdentifier(Throwable throwable) 1770 */ 1771 private Object _executionIdentifier; 1772 1773 // Listeners for execution events. This list has weak references. 1774 private List<WeakReference<ExecutionListener>> _executionListeners; 1775 1776 // Set to true if we should exit after wrapup(). 1777 private boolean _exitAfterWrapup = false; 1778 1779 // Flag indicating that finish() has been called. 1780 private boolean _finishRequested = false; 1781 1782 // Count the number of iterations completed. 1783 private int _iterationCount; 1784 1785 // The map that keeps track of analyses. 1786 private HashMap<String, Object> _nameToAnalysis; 1787 1788 // Flag indicating that pause() has been called. 1789 private boolean _pauseRequested = false; 1790 1791 // Version at which preinitialize last successfully executed. 1792 private long _preinitializeVersion = -1; 1793 1794 // Whether time and memory usage are printed at the end of model execution. 1795 private boolean _printTimeAndMemory = true; 1796 1797 // Flag for waiting on resume(); 1798 private boolean _resumeNotifyWaiting = false; 1799 1800 // The thread that is passed to Runtime.addShutdowHook(). 1801 private Thread _shutdownThread = null; 1802 1803 // The state of the execution. 1804 private volatile State _state = IDLE; 1805 1806 // A short status message. 1807 private String _statusMessage = ""; 1808 1809 // If startRun() is used, then this points to the thread that was 1810 // created. 1811 private PtolemyThread _thread; 1812 1813 // A map that associates throwables with execution identifiers. The map is 1814 // a WeakHashMap so that execution identifiers can be garbage collected. 1815 private Map<Throwable, Object> _throwableToExecutionIdentifier = new WeakHashMap<Throwable, Object>(); 1816 1817 // An indicator of whether type resolution needs to be done. 1818 private boolean _typesResolved = false; 1819 1820 /** A thread that is waiting, e.g. synchronized to real time, or null if there is none. */ 1821 private Thread _waitingThread; 1822 1823 /////////////////////////////////////////////////////////////////// 1824 //// inner class //// 1825 1826 /** Instances of this class represent phases of execution, or the 1827 * state of the manager. 1828 */ 1829 public static class State { 1830 // Constructor is private because only Manager instantiates this class. 1831 private State(String description) { 1832 _description = description; 1833 } 1834 1835 /** Get a description of the state. 1836 * @return A description of the state. 1837 */ 1838 public String getDescription() { 1839 return _description; 1840 } 1841 1842 // An utter hack... 1843 private void setDescription(String description) { 1844 _description = description; 1845 } 1846 1847 /** Print out the current state. 1848 */ 1849 @Override 1850 public String toString() { 1851 return "The model is " + getDescription(); 1852 } 1853 1854 private String _description; 1855 } 1856 1857 /** Notify listeners of an exception. 1858 */ 1859 private class ErrorReportingThread extends Thread { 1860 // This thread is a named inner class so that we can find it 1861 // by name when looking for memory leaks. 1862 1863 /** Construct an thread that reports errors. 1864 * @param name The name of the thread. 1865 */ 1866 public ErrorReportingThread(String name, Throwable throwable) { 1867 super(name); 1868 _throwable = throwable; 1869 } 1870 1871 /** Run the thread. 1872 */ 1873 @Override 1874 public void run() { 1875 synchronized (Manager.this) { 1876 // We use Throwables instead of Exceptions so that 1877 // we can catch Errors like 1878 // java.lang.UnsatisfiedLink. 1879 String errorMessage = MessageHandler.shortDescription( 1880 _throwable) + " occurred: " + _throwable.getClass() 1881 + "(" + _throwable.getMessage() + ")"; 1882 _debug("-- Manager notifying listeners of exception: " 1883 + _throwable); 1884 1885 if (_executionListeners == null) { 1886 System.err.println( 1887 "No executionListeners? Error message was: " 1888 + errorMessage); 1889 _throwable.printStackTrace(); 1890 } else { 1891 1892 // If the execution id is not null, map the 1893 // throwable to the id. 1894 if (_executionIdentifier != null) { 1895 _throwableToExecutionIdentifier.put(_throwable, 1896 _executionIdentifier); 1897 } 1898 1899 ListIterator<WeakReference<ExecutionListener>> listeners = _executionListeners 1900 .listIterator(); 1901 1902 while (listeners.hasNext()) { 1903 WeakReference<ExecutionListener> reference = listeners 1904 .next(); 1905 ExecutionListener listener = reference.get(); 1906 1907 if (listener != null) { 1908 listener.executionError(Manager.this, _throwable); 1909 } else { 1910 listeners.remove(); 1911 } 1912 } 1913 } 1914 } 1915 } 1916 1917 /** The throwable that is to be passed to the listeners. */ 1918 private Throwable _throwable; 1919 } 1920 1921 private class PtolemyRunThread extends PtolemyThread { 1922 // This thread is a named inner class so that we can find it 1923 // by name when looking for memory leaks. 1924 1925 public PtolemyRunThread(Runnable target, String name) { 1926 super(target, name); 1927 } 1928 1929 @Override 1930 public void run() { 1931 // The run() method will set _thread to null 1932 // upon completion of the run. 1933 Manager.this.run(); 1934 } 1935 } 1936 1937 private class UnpauserThread extends Thread { 1938 // This thread is a named inner class so that we can find it 1939 // by name when looking for memory leaks. 1940 1941 @Override 1942 public void run() { 1943 // NOTE: The execute() method used to be synchronized, 1944 // which would cause deadlock with this. 1945 // During wrapup, if the Manager is locked 1946 // and the ProcessDirector is waiting for threads 1947 // to end, then these unpausers 1948 // can't run, and the processes can't end. 1949 synchronized (Manager.this) { 1950 Manager.this.notifyAll(); 1951 } 1952 } 1953 } 1954}