001/* An actor that stops a model executing when it receives a true token.
002
003 Copyright (c) 1997-2014 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION_2
025 COPYRIGHTENDKEY
026
027 */
028package ptolemy.actor.lib;
029
030import ptolemy.data.BooleanToken;
031import ptolemy.data.expr.SingletonParameter;
032import ptolemy.data.type.BaseType;
033import ptolemy.kernel.CompositeEntity;
034import ptolemy.kernel.util.IllegalActionException;
035import ptolemy.kernel.util.NameDuplicationException;
036import ptolemy.kernel.util.Settable;
037
038///////////////////////////////////////////////////////////////////
039//// Stop
040
041/**
042
043 <p>An actor that stops execution of a model when it receives a true
044 token on any input channel. This is accomplished by calling
045 finish() on the director, which requests that the current iteration
046 be completed and then the execution be halted. This actor will
047 also call stopFire() which requests that any actors that are
048 firing concurrently in separate threads conclude their firings.
049 This is necessary to support threaded domains like PN. If the input
050 is not connected to anything, then this actor requests a stop
051 whenever it fires.
052
053 </p><p>
054 When exactly this stops the execution depends on the domain.  For
055 example, in DE, if an event with time stamp <i>T</i> and value
056 <i>true</i> arrives at this actor, then the current iteration will
057 be concluded, and then the model will halt.  Concluding the current
058 iteration means processing all events in the event queue with time
059 stamp <i>T</i>. Thus, it is possible for actors to be invoked after
060 this one is invoked with a <i>true</i> input.
061
062 </p><p>
063 In SDF, if this actor receives <i>true</i>, then the current
064 iteration is concluded and then execution is stopped.  Similarly in
065 SR.
066
067 </p><p>
068 In PN, where each actor has its own thread, there is no
069 well-defined notion of an iteration. The finish() method of the
070 manager calls stopFire() on all actors, which for threaded actors
071 results in halting them upon their next attempt to read an input or
072 write an output. When all actor threads have stopped, the iteration
073 concludes and the model halts. <b>NOTE</b>: <i>This is not the best
074 way to stop a PN model!</i> This mechanism is nondeterministic in
075 the sense that there is no way to control exactly what data is
076 produced or consumed on the connections before the model stops.  To
077 stop a PN model, it is better to design the model so that all
078 actors are starved of data when the model is to stop.  The director
079 will detect this starvation, and halt the model.  Nonetheless, if
080 the nondeterminism is acceptable, this actor can be used.</p>
081
082 @author Edward A. Lee
083 @version $Id$
084 @since Ptolemy II 2.1
085 @Pt.ProposedRating Green (eal)
086 @Pt.AcceptedRating Green (neuendor)
087 */
088public class Stop extends Sink {
089    /** Construct an actor in the specified container with the specified
090     *  name.
091     *  @param container The container.
092     *  @param name The name of this actor within the container.
093     *  @exception IllegalActionException If the actor cannot be contained
094     *   by the proposed container.
095     *  @exception NameDuplicationException If the name coincides with
096     *   an actor already in the container.
097     */
098    public Stop(CompositeEntity container, String name)
099            throws IllegalActionException, NameDuplicationException {
100        super(container, name);
101
102        input.setTypeEquals(BaseType.BOOLEAN);
103
104        // Icon is a stop sign.
105        _attachText("_iconDescription", "<svg>\n"
106                + "<polygon points=\"-8,-19 8,-19 19,-8 19,8 8,19 "
107                + "-8,19 -19,8 -19,-8\" " + "style=\"fill:red\"/>\n"
108                + "<text x=\"-15\" y=\"4\""
109                + "style=\"font-size:11; fill:white; font-family:SansSerif\">"
110                + "STOP</text>\n" + "</svg>\n");
111
112        // Hide the name because the name is in the icon.
113        _hideName = new SingletonParameter(this, "_hideName");
114        _hideName.setToken(BooleanToken.TRUE);
115        _hideName.setVisibility(Settable.EXPERT);
116    }
117
118    ///////////////////////////////////////////////////////////////////
119    ////                     ports and parameters                  ////
120
121    /** The parameter that hides the name of the actor.  The default
122     * value is true.
123     */
124    public SingletonParameter _hideName;
125
126    ///////////////////////////////////////////////////////////////////
127    ////                         public methods                    ////
128
129    /** Read one token from each input channel that has a token,
130     *  and if any token is true, call finish() on the manager.
131     *  If nothing at all is connected to the input port, then
132     *  call finish() unconditionally.
133     *  @exception IllegalActionException If there is no director or
134     *   if there is no manager, or if the container is not a
135     *   CompositeActor.
136     *  @return False if this actor is trying to stop execution if any
137     *  token is true or if the input is not connected.  If this actor
138     *  is not trying to stop execution, then return the value
139     *  returned by super.postfire().
140     */
141    @Override
142    public boolean postfire() throws IllegalActionException {
143        boolean result = false;
144
145        if (!input.isOutsideConnected()) {
146            result = true;
147        }
148
149        // NOTE: We need to consume data on all channels that have data.
150        // If we don't then DE will go into an infinite loop.
151        for (int i = 0; i < input.getWidth(); i++) {
152            if (input.hasToken(i)) {
153                if (((BooleanToken) input.get(i)).booleanValue()) {
154                    result = true;
155                }
156            }
157        }
158
159        if (result) {
160            // NOTE: This used to call stop() on the manager, but that's
161            // not the right thing to do. In particular, this could be
162            // used inside a RunCompositeActor, and it should only
163            // stop the inside execution, not the outside one.
164            // It's also not correct to call stop() on the director,
165            // because stop() requests immediate stopping. To give
166            // determinate stopping, this actor needs to complete
167            // the current iteration.
168            getDirector().finish();
169
170            // To support multithreaded domains, also have to call
171            // stopFire() to request that all actors conclude ongoing firings.
172            getDirector().stopFire();
173
174            //             Nameable container = getContainer();
175
176            //             if (container instanceof CompositeActor) {
177            //                 Manager manager = ((CompositeActor) container).getManager();
178
179            //                 if (manager != null) {
180            //                     manager.finish();
181            //                 } else {
182            //                     throw new IllegalActionException(this,
183            //                             "Cannot stop without a Manager.");
184            //                 }
185            //             } else {
186            //                 throw new IllegalActionException(this,
187            //                         "Cannot stop without a container that is a "
188            //                                 + "CompositeActor.");
189            //             }
190
191        }
192
193        // If this actor is not trying to stop execution, then return
194        // the value returned by super.postfire().
195        boolean superResults = super.postfire();
196        if (!result) {
197            return superResults;
198        }
199
200        return !result;
201    }
202}