/** Report that the manager state has changed. This is called by the manager. */ public void managerStateChanged(Manager manager) { Manager.State newState = manager.getState(); if (newState != _previousState) { report(manager.getState().getDescription()); _previousState = newState; } }
/** * Put a token on the queue contained in this receiver. If the queue is full, then suspend the * calling thread (blocking write) and inform the director of the same. Resume the process on * detecting room in the queue. If a termination is requested, then initiate the termination of * the calling process by throwing a TerminateProcessException. On detecting a room in the queue, * put a token in the queue. Check whether any process is blocked on a read from this receiver. If * a process is indeed blocked, then unblock the process, and inform the director of the same. * * @param token The token to be put in the receiver, or null to not put anything. * @exception NoRoomException If during initialization, capacity cannot be increased enough to * accommodate initial tokens. */ public void put(Token token) throws NoRoomException { IOPort port = getContainer(); if (port == null || token == null) { return; // Nothing to do. } Workspace workspace = port.workspace(); while (!_terminate) { int depth = 0; try { // NOTE: Avoid acquiring read access on the workspace // while holding the lock on the director because if // some other process is trying to acquire write access, // the request for read access will be deferred. Nameable container = getContainer().getContainer(); Manager manager = ((Actor) container).getManager(); // NOTE: This used to synchronize on this, but since it calls // director methods that are synchronized on the director, // this can cause deadlock. synchronized (_director) { // Need to check this again after acquiring the lock. // Otherwise, could end up calling wait() below _after_ // notification has occurred. if (_terminate) { break; } // If we are in the initialization phase, then we may have // to increase the queue capacity before proceeding. This // may be needed to support PublisherPorts that produce // initial tokens (or, I suppose, any actor that produces // initial tokens during initialize()?). if (!super.hasRoom()) { if (container instanceof Actor) { if (manager.getState().equals(Manager.INITIALIZING)) { try { _queue.setCapacity(_queue.getCapacity() + 1); } catch (IllegalActionException e) { throw new NoRoomException( getContainer(), "Failed to increase queue capacity enough to accommodate initial tokens"); } } } } // Try to write. if (super.hasRoom()) { super.put(token); // If any thread is blocked on a get(), then it will become // unblocked. Notify the director now so that there isn't a // spurious deadlock detection. if (_readPending != null) { _director.threadUnblocked(_readPending, this, PNDirector.READ_BLOCKED); _readPending = null; } // Normally, the _writePending reference will have // been cleared by the read that unblocked this write. // However, it might be that the director increased the // buffer size, which would also have the affect of unblocking // this write. Hence, we clear it here if it is set. if (_writePending != null) { _director.threadUnblocked(_writePending, this, PNDirector.WRITE_BLOCKED); _writePending = null; } break; } // Wait to try again. _writePending = Thread.currentThread(); _director.threadBlocked(_writePending, this, PNDirector.WRITE_BLOCKED); // NOTE: We cannot use workspace.wait(Object) here without // introducing a race condition, because we have to release // the lock on the _director before calling workspace.wait(_director). depth = workspace.releaseReadPermission(); _director.wait(); } // release lock on _director before reacquiring read permissions. } catch (InterruptedException e) { _terminate = true; } finally { if (depth > 0) { workspace.reacquireReadPermission(depth); } } } if (_terminate) { throw new TerminateProcessException("Process terminated."); } }
/** * Report in debugging statements that the manager state has changed. This method is called if the * referenced model is executed in another thread and the manager changes state. * * @param manager The manager controlling the execution. * @see Manager#getState() */ public void managerStateChanged(Manager manager) { if (_debugging) { _debug("Referenced model manager state: " + manager.getState()); } }