001/* Thread class for process oriented domains. 002 003 Copyright (c) 1998-2014 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.actor.process; 029 030import java.io.InterruptedIOException; 031 032import ptolemy.actor.Actor; 033import ptolemy.actor.FiringEvent; 034import ptolemy.actor.FiringsRecordable; 035import ptolemy.actor.Manager; 036import ptolemy.kernel.Entity; 037import ptolemy.kernel.util.IllegalActionException; 038import ptolemy.kernel.util.NamedObj; 039import ptolemy.kernel.util.PtolemyThread; 040import ptolemy.kernel.util.Workspace; 041 042/////////////////////////////////////////////////////////////////// 043//// ProcessThread 044 045/** 046 Thread class acting as a process for process oriented domains. 047 <P> 048 In process oriented domains, each actor acts as a separate process and 049 its execution is not centrally controlled by the director. Each process 050 runs concurrently with other processes and is responsible for calling 051 its execution methods. 052 <P> 053 This class provides the mechanism to implement the above. 054 An instance of this class can be created by passing an actor as an 055 argument to the constructor. This class runs as a separate thread on 056 being started and calls the execution methods on the actor, repeatedly. 057 Specifically, it calls initialize(), and then repeatedly calls 058 the prefire(), fire() and postfire() methods 059 of the actor. Before termination, this calls the wrapup() method of 060 the actor. 061 <P> 062 If an actor returns false in its postfire() methods, the actor is 063 never fired again and the thread or process terminates after calling 064 wrapup() on the actor. 065 <P> 066 An instance of this class is associated with an instance of 067 ProcessDirector as well as an instance of Actor. The 068 _increaseActiveCount() of the director is called from the constructor 069 of this class, and the _decreaseActiveCount() method is called at the 070 end of the run() method, just before the thread terminates. 071 072 @author Mudit Goel, Neil Smyth, John S. Davis II, Contributors: Efrat Jaeger, Daniel Crawl 073 @version $Id$ 074 @since Ptolemy II 0.2 075 @Pt.ProposedRating Green (mudit) 076 @Pt.AcceptedRating Yellow (mudit) 077 */ 078public class ProcessThread extends PtolemyThread { 079 /** Construct a thread to be used for the execution of the 080 * iteration methods of the actor. This increases the count of active 081 * actors in the director. 082 * @param actor The actor to be executed. 083 * @param director The director responsible for the execution of 084 * the actor. 085 */ 086 public ProcessThread(Actor actor, ProcessDirector director) { 087 super(); 088 _actor = actor; 089 _director = director; 090 _manager = actor.getManager(); 091 092 if (_actor instanceof NamedObj) { 093 _name = ((NamedObj) _actor).getFullName(); 094 addDebugListener((NamedObj) _actor); 095 } else { 096 _name = "Unnamed"; 097 } 098 099 // Set the name of the thread to the full name of the actor. 100 setName(_name); 101 102 // This method is called here and not in the run() method as the 103 // count should be incremented before any thread is started 104 // or made active. This is because the second started thread might 105 // block on a read or write to this process and increment the block 106 // count even before this thread has incremented the active count. 107 // This results in false deadlocks. 108 _director.addThread(this); 109 } 110 111 /////////////////////////////////////////////////////////////////// 112 //// public methods //// 113 114 /** Return the actor being executed by this thread. 115 * @return The actor being executed by this thread. 116 */ 117 public Actor getActor() { 118 return _actor; 119 } 120 121 /** Initialize the actor, iterate it through the execution cycle 122 * until it terminates. At the end of the termination, calls wrapup 123 * on the actor. 124 */ 125 @Override 126 public void run() { 127 if (_debugging) { 128 _debug("-- Starting thread."); 129 } 130 131 Workspace workspace = _director.workspace(); 132 boolean iterate = true; 133 Throwable thrownWhenIterate = null; 134 Throwable thrownWhenWrapup = null; 135 136 try { 137 // Initialize the actor. 138 _actor.initialize(); 139 140 _actorInitialized(); 141 142 // While postfire() returns true and stop() is not called. 143 while (iterate) { 144 // NOTE: Possible race condition... actor.stop() 145 // might be called before we get to this. 146 // This will cause postfire() on the actor 147 // to return false, which will stop its execution. 148 if (_director.isStopFireRequested()) { 149 // And wait until the flag has been cleared. 150 if (_debugging) { 151 _debug("-- Thread pause requested. Get lock on director."); 152 } 153 154 int depth = 0; 155 try { 156 synchronized (_director) { 157 // Tell the director we're stopped (necessary 158 // for deadlock detection). 159 _director.threadHasPaused(this); 160 161 while (_director.isStopFireRequested()) { 162 // If a stop has been requested, in addition 163 // to a stopFire, then stop execution 164 // altogether and skip to wrapup(). 165 if (_director.isStopRequested()) { 166 if (_debugging) { 167 _debug("-- Thread stop requested, " 168 + "so cancel iteration."); 169 } 170 break; 171 } 172 173 if (_debugging) { 174 _debug("-- Thread waiting for " 175 + "canceled pause request."); 176 } 177 178 // NOTE: We cannot use workspace.wait(Object) here without 179 // introducing a race condition, because we have to release 180 // the lock on the _director before calling workspace.wait(_director). 181 if (depth == 0) { 182 depth = workspace.releaseReadPermission(); 183 } 184 _director.wait(); 185 } 186 _director.threadHasResumed(this); 187 if (_debugging) { 188 _debug("-- Thread resuming."); 189 } 190 } 191 } catch (InterruptedException ex) { 192 if (_debugging) { 193 _debug("-- Thread interrupted, " 194 + "so cancel iteration."); 195 } 196 break; 197 } finally { 198 if (depth > 0) { 199 // This has to happen outside the synchronized(_director) 200 // block to prevent deadlock. 201 workspace.reacquireReadPermission(depth); 202 } 203 } 204 } 205 206 if (_director.isStopRequested()) { 207 break; 208 } 209 210 // container is checked for null to detect the 211 // deletion of the actor from the topology. 212 if (((Entity) _actor).getContainer() != null) { 213 iterate = _iterateActor(); 214 } 215 } 216 } catch (Throwable t) { 217 thrownWhenIterate = t; 218 } finally { 219 220 try { 221 // NOTE: Deadlock risk here if wrapup is done inside 222 // a block synchronized on the _director, as it used to be. 223 // Holding a lock on the _director during wrapup() 224 // might cause deadlock with hierarchical models where 225 // wrapup() waits for internal actors to conclude, 226 // doing a wait() on its own internal director, 227 // or trying to acquire a write lock on the workspace. 228 // Meanwhile, this thread will hold a lock on this 229 // outside director, which may prevent the other 230 // threads from releasing their write lock! 231 wrapup(); 232 } catch (IllegalActionException e) { 233 thrownWhenWrapup = e; 234 } finally { 235 // Let the director know that this thread stopped. 236 // This must occur after the call to wrapup above. 237 synchronized (_director) { 238 _director.removeThread(this); 239 } 240 if (_debugging) { 241 _debug("-- Thread stopped."); 242 } 243 244 boolean rethrow = false; 245 246 if (thrownWhenIterate instanceof TerminateProcessException) { 247 // Process was terminated. 248 if (_debugging) { 249 _debug("-- Blocked Receiver call " 250 + "threw TerminateProcessException."); 251 } 252 } else if (thrownWhenIterate instanceof InterruptedException) { 253 // Process was terminated by call to stop(); 254 if (_debugging) { 255 _debug("-- Thread was interrupted: " 256 + thrownWhenIterate); 257 } 258 } else if (thrownWhenIterate instanceof InterruptedIOException 259 || thrownWhenIterate != null && thrownWhenIterate 260 .getCause() instanceof InterruptedIOException) { 261 // PSDF has problems here when run with JavaScope 262 if (_debugging) { 263 _debug("-- IO was interrupted: " + thrownWhenIterate); 264 } 265 } else if (thrownWhenIterate instanceof IllegalActionException) { 266 if (_debugging) { 267 _debug("-- Exception: " + thrownWhenIterate); 268 } 269 _manager.notifyListenersOfException( 270 (IllegalActionException) thrownWhenIterate); 271 } else if (thrownWhenIterate != null) { 272 rethrow = true; 273 } 274 275 if (thrownWhenWrapup instanceof IllegalActionException) { 276 if (_debugging) { 277 _debug("-- Exception: " + thrownWhenWrapup); 278 } 279 _manager.notifyListenersOfException( 280 (IllegalActionException) thrownWhenWrapup); 281 } else if (thrownWhenWrapup != null) { 282 // Must be a runtime exception. 283 // Call notifyListenerOfThrowable() here so that 284 // the stacktrace appears in the UI and not in stderr. 285 _manager.notifyListenersOfThrowable(thrownWhenWrapup); 286 } else if (rethrow) { 287 _manager.notifyListenersOfThrowable(thrownWhenIterate); 288 } 289 } 290 } 291 } 292 293 /** End the execution of the actor under the control of this 294 * thread. Subclasses are encouraged to override this method 295 * as necessary for domain specific functionality. 296 * @exception IllegalActionException If an error occurs while 297 * ending execution of the actor under the control of this 298 * thread. 299 */ 300 public void wrapup() throws IllegalActionException { 301 if (_debugging) { 302 _debug("-- Thread wrapup() called."); 303 } 304 _actor.wrapup(); 305 } 306 307 /////////////////////////////////////////////////////////////////// 308 //// protected methods //// 309 310 /** Notify that the actor has been initialized. This base class 311 * does nothing. 312 */ 313 protected void _actorInitialized() { 314 } 315 316 /** Iterate the actor associate with this thread. 317 * @return True if either prefire() returns false 318 * or postfire returns true. 319 * @exception IllegalActionException If the actor throws it. 320 */ 321 protected boolean _iterateActor() throws IllegalActionException { 322 FiringsRecordable firingsRecordable = null; 323 // FIXME: See SysMLSequentialDIrector.iterateActorOnce() for very similar code. 324 if (_actor instanceof FiringsRecordable) { 325 firingsRecordable = (FiringsRecordable) _actor; 326 } 327 328 if (firingsRecordable != null) { 329 firingsRecordable.recordFiring(FiringEvent.BEFORE_PREFIRE); 330 } 331 boolean result = true; 332 if (_actor.prefire()) { 333 334 if (firingsRecordable != null) { 335 firingsRecordable.recordFiring(FiringEvent.AFTER_PREFIRE); 336 firingsRecordable.recordFiring(FiringEvent.BEFORE_FIRE); 337 } 338 339 _actor.fire(); 340 341 if (firingsRecordable != null) { 342 firingsRecordable.recordFiring(FiringEvent.AFTER_FIRE); 343 firingsRecordable.recordFiring(FiringEvent.BEFORE_POSTFIRE); 344 } 345 346 result = _actor.postfire(); 347 348 if (firingsRecordable != null) { 349 firingsRecordable.recordFiring(FiringEvent.AFTER_POSTFIRE); 350 } 351 } else { 352 if (firingsRecordable != null) { 353 firingsRecordable.recordFiring(FiringEvent.AFTER_PREFIRE); 354 } 355 } 356 return result; 357 } 358 359 /////////////////////////////////////////////////////////////////// 360 //// protected variables //// 361 362 /** The actor that to be executed. */ 363 protected Actor _actor; 364 365 /** The director responsible for the execution of the actor. */ 366 protected ProcessDirector _director; 367 368 /** The Manager of the actor. */ 369 protected Manager _manager; 370 371 /////////////////////////////////////////////////////////////////// 372 //// private variables //// 373 374 private String _name; 375}