if (!(getDirector() instanceof RendezvousDirector)) {
throw new IllegalActionException(this,
"Buffer actor can only be used with RendezvousDirector.");
}
final RendezvousDirector director = (RendezvousDirector) getDirector();
_postfireReturns = true;
if (_readThread == null) {
_readThread = new Thread(getFullName() + "_readThread") {
public void run() {
try {
if (_debugging) {
_debug("** Starting read thread.");
}
_exception = null;
while (!_stopRequested) {
// Synchronize on the director since all read/write
// operations do.
synchronized (director) {
// If the buffer is full, then wait until it is no
// longer full.
int capacityValue = ((IntToken) capacity
.getToken()).intValue();
while (_buffer.size() >= capacityValue
&& !_stopRequested) {
if (_debugging) {
_debug("** Waiting because buffer is full.");
}
try {
director.threadBlocked(_readThread,
null);
RendezvousReceiver
.waitForChange(director);
} finally {
director.threadUnblocked(_readThread,
null);
}
}
if (_stopRequested) {
break;
}
if (_debugging) {
_debug("** Waiting for input.");
}
Token token = input.get(0);
_buffer.add(token);
if (_debugging) {
_debug("** Received input. Buffer contents: "
+ _buffer);
}
director.threadUnblocked(writeThread, null);
director.notifyAll();
}
}
} catch (TerminateProcessException ex) {
// OK, just exit.
_postfireReturns = false;
} catch (IllegalActionException ex) {
_exception = ex;
} finally {
director.removeThread(_readThread);
if (_debugging) {
_debug("** Ending read thread.");
}
}
}
};
director.addThread(_readThread);
_readThread.start();
}
// Synchronize on the director since all read/write
// operations do.
synchronized (director) {
if (_exception != null) {
throw _exception;
}
while (_buffer.size() == 0) {
if (_stopRequested || !_postfireReturns) {
_postfireReturns = false;
return;
}
if (_debugging) {
_debug("Buffer is empty. Waiting for it to fill.");
}
try {
director.threadBlocked(writeThread, null);
RendezvousReceiver.waitForChange(director);
} catch (TerminateProcessException ex) {
_postfireReturns = false;
return;
} finally {
director.threadUnblocked(writeThread, null);
}
if (_exception != null) {
throw _exception;
}
}
// There is a token.
Token token = (Token) _buffer.get(0);
if (_debugging) {
_debug("Sending token to output: " + token);
}
if (_exception != null) {
throw _exception;
}
// If this put blocks for any reason, it will block on
// a director.wait(), so the lock will not be held.
try {
output.send(0, token);
} catch (TerminateProcessException e) {
_postfireReturns = false;
return;
}
if (_exception != null) {
throw _exception;
}
_buffer.remove(0);
if (_debugging) {
_debug("Buffer contents: " + _buffer);
}
int capacityValue = ((IntToken) capacity.getToken()).intValue();
if (_buffer.size() == capacityValue - 1 && !_stopRequested) {
director.threadUnblocked(_readThread, null);
director.notifyAll();
}
}
}