@SuppressWarnings("unchecked")
public CrossbarMessage waitForMessage(List<MessageChannel<T>> channelsToWaitOn, TimeInstant waitUntil)
throws DelayedInterruptException {
final T current;
String where = "CrossbarMessage waitForMessage(List<MessageChannel<T>> channelsToWaitOn, TimeInstant waitUntil)";
ExternalEvent delayedInterruptEvent;
ExternalEvent processUnblockingEvent = null;
current = (T) currentSimProcess();// get the current SimProcess
// perform all necessary checks
if (!isProcessValid(current, where)) {
return null;
}
if (!isChannelListValid(channelsToWaitOn, where)) {
return null;
}
if (!isWaitUntilValid(waitUntil, where)) {
return null;
}
if (!canProcessWaitAtMessageCrossbar(current, where)) {
return null;
}
// TODO Bitte pr�fen ob hier weitere checks fehlen
// If a wait time limit is set (waitUntil!=null) schedule an delayed
// interrupt of this process, so it can leave the
// crossbar after the specified wait time
// Since blocked processes cannot be interrupted schedule an
// ExternalEvent that unblocks the process just before it is
// interrupted.
if (waitUntil != null) {
skipTraceNote();
delayedInterruptEvent = current.interruptDelayed(waitUntil);
processUnblockingEvent = new ExternalEvent(getModel(), "MessageCrossbarProcessUnblockingEvent", true) {
@Override
public void eventRoutine() {
current.setBlocked(false);
}
};
skipTraceNote();
processUnblockingEvent.scheduleBefore(delayedInterruptEvent);
}
current.setBlocked(true); // block the process
if (current.isScheduled()) {
current.cancel();
}
for (MessageChannel<T> channel : channelsToWaitOn) {
// Let the channels keep track of the processes which are waiting on
// them
channel.addWaitingProcess(current);
}
// let the crossbar track all passivated process
skipTraceNote();
getPassivatedProcessesQueue().insert(current);
if (currentlySendTraceNotes()) {
String messageChannelNames = "";
Iterator<MessageChannel<T>> messageChannelsIterator = channelsToWaitOn.iterator();
while (messageChannelsIterator.hasNext()) {
messageChannelNames += messageChannelsIterator.next().getName();
if (messageChannelsIterator.hasNext()) {
messageChannelNames += ", ";
}
}
sendTraceNote("Waiting for a message at the MessageCrosbar " + getName() + " on the message channels "
+ messageChannelNames + ". Process is passivated.");
}
try {
skipTraceNote(); // dont tell the user that...
current.passivate();// ...the process is passivated here.
} catch (DelayedInterruptException ex) {
// If the process is interrupted by the delayed interupt, remove it
// from the crossbar queue and from all channels it might still be
// waiting on
skipTraceNote();
getPassivatedProcessesQueue().remove(current);
interruptedWaits++; // increment the number of interrupted waits
for (MessageChannel<T> channel : messageChannelsByName.values()) {
channel.abortWaiting(current);
}
// Finally re-throw the DelayedInterruptException so a process using
// the message crossbar can handle the interrupt.
throw ex;
}
// The process has been activated normally. Therefore the delayed
// interrupt and the processUnblockingEvent have to be unscheduled. Of
// course this only applies if a wait time limit has been set and a
// delayed interrupt has been scheduled.
if (waitUntil != null) {
skipTraceNote(2);
current.cancelInterruptDelayed();
processUnblockingEvent.cancel();
}
// Now after the process is active again get the message that activated
// the process and return it. Additionally remove the process from the
// list of passivated processes.