001/* A BranchController manages the execution of a set of branch objects by 002 monitoring whether the branches have blocked. 003 004 Copyright (c) 1998-2014 The Regents of the University of California. 005 All rights reserved. 006 Permission is hereby granted, without written agreement and without 007 license or royalty fees, to use, copy, modify, and distribute this 008 software and its documentation for any purpose, provided that the above 009 copyright notice and the following two paragraphs appear in all copies 010 of this software. 011 012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 013 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 014 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 015 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 016 SUCH DAMAGE. 017 018 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 020 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 021 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 022 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 023 ENHANCEMENTS, OR MODIFICATIONS. 024 025 PT_COPYRIGHT_VERSION_2 026 COPYRIGHTENDKEY 027 028 029 */ 030package ptolemy.actor.process; 031 032import java.util.Iterator; 033import java.util.LinkedList; 034 035import ptolemy.actor.CompositeActor; 036import ptolemy.actor.IOPort; 037import ptolemy.actor.Receiver; 038import ptolemy.kernel.util.IllegalActionException; 039import ptolemy.kernel.util.Nameable; 040 041/////////////////////////////////////////////////////////////////// 042//// BranchController 043 044/** 045 A BranchController manages the execution of a set of branch objects by 046 monitoring whether the branches have blocked. A branch blocks when it is 047 either unable to get data from its producer receiver or put data into its 048 consumer receiver. When a branch blocks, it registers the block with its 049 branch controller by passing the specific receiver that is blocked. If all 050 of a branch controllers branches are blocked, then the branch controller 051 informs the director associated with its containing composite actors. 052 <P> 053 Branches are assigned to a branch controller by the director associated 054 with the controller's composite actor via the addBranches() method. This 055 method takes an io port and determines the port's receivers. Branches 056 are then instantiated and assigned to the receivers according to whether 057 the receivers are producer or consumer receivers. 058 059 @author John S. Davis II 060 @version $Id$ 061 @since Ptolemy II 1.0 062 @Pt.ProposedRating Red (davisj) 063 @Pt.AcceptedRating Red (davisj) 064 */ 065public class BranchController implements Runnable { 066 /** Construct a branch controller in the specified composite actor 067 * container. 068 * 069 * @param container The parent actor that contains this object. 070 */ 071 public BranchController(CompositeActor container) { 072 _parentActor = container; 073 //_parentName = ((Nameable) container).getName(); 074 } 075 076 /////////////////////////////////////////////////////////////////// 077 //// public methods //// 078 079 /** Activate the branches that are managed by this branch 080 * controller. This method should be invoked once when 081 * a branch controller first starts the branches it controls. 082 * Invocation of this method will cause the branches to 083 * begin transferring tokens between their assigned producer 084 * and consumer receiver. Each branch executes in its own 085 * thread. 086 */ 087 public void activateBranches() { 088 // Copy the list of branches within a synchronized block, 089 // then activate them. We do not want to hold the lock 090 // on this controller during the run, as this can cause 091 // deadlock. 092 LinkedList branchesCopy; 093 094 synchronized (this) { 095 if (!hasBranches()) { 096 return; 097 } 098 099 setActive(true); 100 branchesCopy = new LinkedList(_branches); 101 } 102 103 Iterator branches = branchesCopy.iterator(); 104 105 while (branches.hasNext()) { 106 Branch branch = (Branch) branches.next(); 107 Thread thread = new Thread(branch); 108 _getDirector().addThread(thread); 109 thread.start(); 110 } 111 } 112 113 /** Add branches corresponding to the channels of the port 114 * argument. The port must be contained by the same actor 115 * that contains this controller. If branches corresponding 116 * to the specified port have already been added to this 117 * controller, then an IllegalActionException will be thrown. 118 * If the input/output polarity of this port does not match that 119 * of ports for whom branches have been previously added 120 * to this controller, then throw an IllegalActionException. 121 * @param port The port for which branches will be added to this 122 * controller. 123 * @exception IllegalActionException If branches for the 124 * port have been previously added to this controller or 125 * if the port input/output polarity does not match that 126 * of ports for whom branches were previously add to this 127 * controller. 128 */ 129 public void addBranches(IOPort port) throws IllegalActionException { 130 if (port.getContainer() != getParent()) { 131 throw new IllegalActionException( 132 "Can not contain " + "a port that is not contained by this " 133 + "BranchController's container."); 134 } 135 136 if (_ports.contains(port)) { 137 throw new IllegalActionException(port, "This port " 138 + "is already controlled by this " + "BranchController"); 139 } 140 141 // Careful; maintain order of following test in case 142 // Java is like C 143 if (_hasInputPorts() && !port.isInput()) { 144 throw new IllegalActionException("BranchControllers " 145 + "must contain only input ports or only output " 146 + "ports; not both"); 147 } 148 149 if (_hasOutputPorts() && !port.isOutput()) { 150 throw new IllegalActionException("BranchControllers " 151 + "must contain only input ports or only output " 152 + "ports; not both"); 153 } 154 155 _ports.add(port); 156 157 Branch branch = null; 158 ProcessReceiver producerReceiver = null; 159 ProcessReceiver consumerReceiver = null; 160 Receiver[][] producerReceivers = null; 161 Receiver[][] consumerReceivers = null; 162 163 for (int i = 0; i < port.getWidth(); i++) { 164 if (port.isInput()) { 165 producerReceivers = port.getReceivers(); 166 consumerReceivers = port.deepGetReceivers(); 167 } else if (port.isOutput()) { 168 producerReceivers = port.getInsideReceivers(); 169 consumerReceivers = port.getRemoteReceivers(); 170 } else { 171 throw new IllegalActionException("Bad news"); 172 } 173 174 // If the port lacks either producer or consumer 175 // receivers, then there is no point in creating a branch. 176 if (producerReceivers.length > i && consumerReceivers.length > i) { 177 try { 178 producerReceiver = (ProcessReceiver) producerReceivers[i][0]; 179 consumerReceiver = (ProcessReceiver) consumerReceivers[i][0]; 180 } catch (ClassCastException ex) { 181 // See [Bug 5] and pn/test/PNInsideDE.xml 182 throw new IllegalActionException(port, ex, 183 "At the current time, process-oriented domains " 184 + "(PN and CSP) cannot be nested inside " 185 + "firing-based domains (SDF, DE, CT, etc.)."); 186 } 187 188 branch = new Branch(producerReceiver, consumerReceiver, this); 189 _branches.add(branch); 190 } 191 } 192 } 193 194 /** Deactivate the branches assigned to this branch controller. 195 */ 196 public synchronized void deactivateBranches() { 197 setActive(false); 198 199 Iterator branches = _branches.iterator(); 200 Branch branch = null; 201 202 while (branches.hasNext()) { 203 branch = (Branch) branches.next(); 204 branch.setActive(false); 205 206 Receiver receiver = branch.getConsumerReceiver(); 207 208 synchronized (receiver) { 209 receiver.notifyAll(); 210 } 211 212 receiver = branch.getProducerReceiver(); 213 214 synchronized (receiver) { 215 receiver.notifyAll(); 216 } 217 } 218 219 notifyAll(); 220 } 221 222 /** Return the list of branches controlled by this controller. 223 * @return The list of branches controlled by this controller. 224 */ 225 public LinkedList getBranchList() { 226 return _branches; 227 } 228 229 /** Return the composite actor that contains this branch 230 * controller. 231 * @return The composite actor that contains this controller. 232 */ 233 public CompositeActor getParent() { 234 return _parentActor; 235 } 236 237 /** Return true if this branch controller controls one or more 238 * branches; return false otherwise. 239 * @return True if this controller controls one or more branches; 240 * return false otherwise. 241 */ 242 public boolean hasBranches() { 243 return _branches.size() > 0; 244 } 245 246 /** Return true if this controller is active; return false 247 * otherwise. 248 * @return True if this controller is active; false otherwise. 249 */ 250 public synchronized boolean isActive() { 251 return _isActive; 252 } 253 254 /** Return true if all of the branches assigned to this branch 255 * controller are blocked or if this branch controller has no 256 * branches; return false otherwise. 257 * @return True if all branches controlled by this branch 258 * controller are blocked or if this branch controller has 259 * no branches; return false otherwise. 260 */ 261 public synchronized boolean isBlocked() { 262 if (!hasBranches()) { 263 return true; 264 } 265 266 if (_branchesBlocked >= _branches.size()) { 267 if (_branchesBlocked > 0) { 268 return true; 269 } 270 } 271 272 return false; 273 } 274 275 /** Begin executing the branches associated with this branch 276 * controller so that they will begin transferring data in 277 * their assigned channels. If all of the branches become 278 * blocked then the director associated with this branch 279 * branch controller is notified. 280 */ 281 @Override 282 public void run() { 283 try { 284 activateBranches(); 285 286 // After starting the runs, acquire a lock 287 // on this object. 288 synchronized (this) { 289 while (isActive()) { 290 while (!isBlocked() && isActive()) { 291 wait(); 292 } 293 294 while (isBlocked() && isActive()) { 295 _getDirector()._controllerBlocked(this); 296 wait(); 297 } 298 299 _getDirector()._controllerUnBlocked(this); 300 } 301 } 302 } catch (InterruptedException e) { 303 // FIXME: Do something 304 } 305 } 306 307 /** Set this branch controller active if the active parameter is 308 * true; set this branch controller to inactive otherwise. 309 * @param active The indicator of whether this branch controller 310 * will be set active or inactive. 311 */ 312 public synchronized void setActive(boolean active) { 313 _isActive = active; 314 } 315 316 /////////////////////////////////////////////////////////////////// 317 //// protected methods //// 318 319 /** Return the director that controls the execution of this 320 * branch controller's containing composite actor. 321 * @return The composite process director that is associated 322 * with this branch controller's container. 323 */ 324 protected CompositeProcessDirector _getDirector() { 325 try { 326 return (CompositeProcessDirector) _parentActor.getDirector(); 327 } catch (NullPointerException ex) { 328 // If a thread has a reference to a receiver with no director it 329 // is an error so terminate the process. 330 String name = ((Nameable) getParent()).getName(); 331 throw new TerminateProcessException("Error: " + name 332 + " contains a branch controller that has a " 333 + "receiver that does not have a director"); 334 } 335 } 336 337 /////////////////////////////////////////////////////////////////// 338 //// private methods //// 339 340 /** Return true if this branch controller has input ports associated 341 * with it; return false otherwise. 342 * @return True if this branch controller has input ports associated 343 * with it. False otherwise. 344 */ 345 private boolean _hasInputPorts() { 346 if (_ports.size() == 0) { 347 return false; 348 } 349 350 Iterator ports = _ports.iterator(); 351 352 while (ports.hasNext()) { 353 IOPort port = (IOPort) ports.next(); 354 return port.isInput(); 355 } 356 357 return false; 358 } 359 360 /** Return true if this branch controller has output ports associated 361 * with it; return false otherwise. 362 * @return True if this branch controller has output ports associated 363 * with it. False otherwise. 364 */ 365 private boolean _hasOutputPorts() { 366 if (_ports.size() == 0) { 367 return false; 368 } 369 370 Iterator ports = _ports.iterator(); 371 372 while (ports.hasNext()) { 373 IOPort port = (IOPort) ports.next(); 374 return port.isOutput(); 375 } 376 377 return false; 378 } 379 380 /////////////////////////////////////////////////////////////////// 381 //// private variables //// 382 // The number of branches that are blocked 383 private int _branchesBlocked = 0; 384 385 // The CompositeActor that owns this controller object. 386 private CompositeActor _parentActor; 387 388 private LinkedList _branches = new LinkedList(); 389 390 private LinkedList _ports = new LinkedList(); 391 392 private boolean _isActive = false; 393 394 //private String _parentName = null; 395}