// currentPort, which is legal. The container argument
// is always the container of the director, so any port
// that has that container must be connected on the inside.
if (connectedPort.isOutput()
&& (connectedPort.getContainer() != container)) {
throw new NotSchedulableException(currentPort,
connectedPort,
"Output ports drive the same relation. "
+ "This is not legal in SDF.");
} else if (connectedPort.isInput()
&& (connectedPort.getContainer() == container)) {
throw new NotSchedulableException(currentPort,
connectedPort,
"Output port drives the same relation "
+ "as the external input port. "
+ "This is not legal in SDF.");
}
}
}
// Next check to make sure that if this port is an external
// input port, then it does not drive the same relation as some
// other output port or some other external input port.
// This results in a non-deterministic merge and is illegal.
if (currentPort.isInput() && (currentPort.getContainer() == container)) {
Iterator connectedPorts = currentPort.deepInsidePortList()
.iterator();
// Make sure any connected output ports are connected on
// the inside.
while (connectedPorts.hasNext()) {
IOPort connectedPort = (IOPort) connectedPorts.next();
// connectPort might be connected on the inside to the
// currentPort, which is legal. The container argument
// is always the container of the director, so any port
// that has that container must be connected on the inside.
if (connectedPort.isOutput()
&& (connectedPort.getContainer() != container)) {
throw new NotSchedulableException(currentPort,
connectedPort,
"External input port drive the same relation "
+ "as an output port. "
+ "This is not legal in SDF.");
} else if (connectedPort.isInput()
&& (connectedPort.getContainer() == container)) {
throw new NotSchedulableException(currentPort,
connectedPort,
"External input port drives the same relation "
+ "as another external input port. "
+ "This is not legal in SDF.");
}
}
}
Director director = (Director) getContainer();
CompositeActor model = (CompositeActor) director.getContainer();
// Get the rate of this port.
int currentRate;
if (currentActor == model) {
currentRate = 1;
} else {
currentRate = DFUtilities.getRate(currentPort);
}
// Port rates of less than zero are not valid.
if (currentRate < 0) {
throw new NotSchedulableException(currentPort,
"Rate cannot be less than zero. It was: " + currentRate);
}
// Propagate to anything that this port is connected to. For
// external ports, this is anything that is connected on the
// inside. For ports of actors that are being scheduled, this is
// anything that is connected on the outside.
Iterator connectedPorts;
if (currentPort.getContainer() == container) {
// Find all the ports that are deeply connected to
// current port on the inside.
if (_debugging && VERBOSE) {
// Move this inside and avoid FindBugs Dead Local Store
connectedPorts = currentPort.deepInsidePortList().iterator();
_debug("deepInsidePortList of " + currentPort);
while (connectedPorts.hasNext()) {
_debug(connectedPorts.next().toString());
}
}
connectedPorts = currentPort.deepInsidePortList().iterator();
} else {
connectedPorts = currentPort.deepConnectedPortList().iterator();
}
// For every port we are connected to.
while (connectedPorts.hasNext()) {
IOPort connectedPort = (IOPort) connectedPorts.next();
ComponentEntity connectedActor = (ComponentEntity) connectedPort
.getContainer();
if (_debugging && VERBOSE) {
_debug("Propagating " + currentPort + " to "
+ connectedActor.getName());
}
int connectedRate;
if (connectedActor == model) {
connectedRate = 1;
} else {
connectedRate = DFUtilities.getRate(connectedPort);
}
// currentFiring is the firing ratio that we've already
// calculated for currentActor
Fraction currentFiring = (Fraction) entityToFiringsPerIteration
.get(currentActor);
// Compute the firing ratio that we think connected actor
// should have, based on its connection to currentActor
Fraction desiredFiring;
// HDF actors might have zero rates...
if ((currentRate == 0) && (connectedRate > 0)) {
// The current port of the current actor has a rate
// of 0, and the current connected port of the
// connected actor has a positive integer rate.
// therefore, we must set the firing count of
// the connected actor to 0 so that it will
// not appear in the final static schedule.
desiredFiring = Fraction.ZERO;
} else if ((currentRate > 0) && (connectedRate == 0)) {
// The current port of the current actor has a
// positive integer rate, and the current
// connected port of the connected actor has
// rate of 0. therefore, we set the firing
// count of the current actor to 0 so that
// it will not appear in the final static schedule.
currentFiring = Fraction.ZERO;
// Update the entry in the firing table.
entityToFiringsPerIteration.put(currentActor, currentFiring);
// Set the firing count of the connected actor to
// be 1.
desiredFiring = new Fraction(1);
} else if ((currentRate == 0) && (connectedRate == 0)) {
// Give the connected actor the same rate as the
// current actor.
desiredFiring = currentFiring;
} else {
// Both the rates are non zero, so we can just do the
// regular actor propagation.
desiredFiring = currentFiring.multiply(new Fraction(
currentRate, connectedRate));
}
// Now, compare the firing ratio that was computed before
// with what we just determined.
// This should be either
// the firing that we computed previously, or null
// if the port is an external port, or _minusOne if
// we have not computed the firing ratio for this actor yet.
Fraction presentFiring = (Fraction) entityToFiringsPerIteration
.get(connectedActor);
if (_debugging && VERBOSE) {
_debug("presentFiring of connectedActor " + connectedActor
+ " = " + presentFiring);
}
// if (presentFiring == null) {
// Make sure to check for presentFiring == null here so that
// we avoid a NullPointerException if the model is ill formed.
// I had problems here with a bug in Publisher.clone() and
// Subscriber.clone() where presentFiring was null.
// Getting a NullPointerException is bad, we should check
// for null and try to give a better message.
if (connectedActor == model || presentFiring == null) {
// We've gotten out to an external port.
// Temporarily create the entry in the firing table.
// This is possibly rather fragile.
entityToFiringsPerIteration.put(connectedActor, desiredFiring);
// Compute the external rate for this port.
Fraction rate = currentFiring.multiply(new Fraction(
currentRate, 1));
Fraction previousRate = (Fraction) externalRates
.get(connectedPort);
if (previousRate == null) {
// This can happen if we somehow have a link to a port
// within a class definition.
// Give better error message than null pointer exception.
throw new InternalErrorException(
"Invalid connection found between ports: "
+ currentPort.getFullName() + " and "
+ connectedPort.getFullName());
}
//if (previousRate.equals(Fraction.ZERO)) {
if (!clusteredExternalPorts.contains(connectedPort)) {
clusteredExternalPorts.add(connectedPort);
externalRates.put(connectedPort, rate);
_propagatePort(container, connectedPort,
entityToFiringsPerIteration, externalRates,
remainingActors, pendingActors, clusteredActors,
clusteredExternalPorts);
} else if (!rate.equals(previousRate)) {
// The rates don't match.
throw new NotSchedulableException("No solution "
+ "exists for the balance equations.\n"
+ "Graph is not "
+ "consistent under the SDF domain "
+ "detected on external port "
+ connectedPort.getFullName());
}
// _propagatePort(container, connectedPort,
// entityToFiringsPerIteration, externalRates,
// remainingActors, pendingActors, clusteredActors,
// clusteredExternalPorts);
// entityToFiringsPerIteration.remove(connectedActor);
} else if (presentFiring.equals(_minusOne)) {
// So we are propagating here for the first time.
// Create the entry in the firing table.
entityToFiringsPerIteration.put(connectedActor, desiredFiring);
// Remove them from remainingActors.
remainingActors.remove(connectedActor);
clusteredActors.add(connectedActor);
// and add them to the pendingActors.
pendingActors.addLast(connectedActor);
} else if (!presentFiring.equals(desiredFiring)) {
// So we've already propagated here, but the
// firingsPerIteration don't match.
throw new NotSchedulableException(this, "No solution "
+ "exists for the balance equations.\n"
+ "Graph is not " + "consistent under the SDF domain "
+ "detected on external port "
+ connectedPort.getFullName());
}