1 /*********************************************************************
2 Copyright 2012, Ralph Ronnquist.
4 This file is part of GORITE.
6 GORITE is free software: you can redistribute it and/or modify it
7 under the terms of the Lesser GNU General Public License as published
8 by the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 GORITE is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the Lesser GNU General Public
17 License along with GORITE. If not, see <http://www.gnu.org/licenses/>.
18 **********************************************************************/
20 package com.intendico.gorite;
22 import java.util.Vector;
23 import java.util.Iterator;
24 import com.intendico.data.Ref;
27 * The Executor class implements functions for managing goal execution
28 * for a collection of performers. More precisely, it implements the
29 * dispatch thread control to the {@link Performer.TodoGroup} goal
32 * <p> System execution may be controlled by invoking the {@link
33 * Performer#performGoal} method for the top level team. This will
34 * lead the execution thread into the Executor for progressing all
35 * {@link Performer.TodoGroup} executions.
37 * <p> The Executor class also includes a control loop, the {@link
38 * #run} method, for using a separate thread to run performers. This
39 * is an alternative execution principle to the use of {@link
40 * Performer#performGoal}. It's not a good idea to use both.
42 * <p> Ordinarily the use of the Executor class is transparent to an
43 * application developer. A single Executor object is created so as to
44 * provide thread control dispatch to all performers, and the top
45 * level {@link Performer#performGoal} utilizes this as needed.
47 * <p> An application may split the performers amongst several
48 * executors, and create background threads for {@link
49 * Performer.TodoGroup} executions. In that case, the developer must
50 * take precaution against multi-threading interferences, and in
51 * particular refrain from using {@link Performer#performGoal}.
53 * <p> The transfer of control between goal executions uses the {@link
54 * #steps} variable, which tells how many goal steps an execution may
55 * advance before being stopped to allow the thread to pursue another
58 public class Executor implements Runnable {
61 * This is a callback interface for monitoring the executor.
63 public interface Listener {
65 * This method is invoked when the Executor is going idle.
67 public void goingIdle(Executor e);
69 * This method is invoked when the Executor is waking up.
71 public void wakingUp(Executor e);
76 * Holds the current default executor that performers add
77 * themselves to by default. Initially <em>null</em>, but one is
78 * set up on demand if needed by {@link #getDefaultExecutor()}.
80 public static Executor default_executor = null;
83 * Returns the default executor, and creates one if needed.
85 public static Executor getDefaultExecutor() {
86 if ( default_executor == null )
87 default_executor = new Executor( "[gorite]" );
88 return default_executor;
92 * A name for the executor. This is also used as thread name for
93 * the executor's dedicated thread.
98 * Configuration value for how many {@link #changeFocus()}
99 * invocations to count between it returning <em>true</em>.
101 public int steps = 40;
104 * Dynamic counter of how many {@link #changeFocus()} invocations
105 * remain until it will return <em>true</em>.
107 public int count = steps;
110 * The {@link Performer} objects managed by this executor.
112 public Vector/*<Performer>*/ performers = new Vector/*<Performer>*/();
115 * A dynamic state variable.
117 public boolean running = true;
120 * A dynamic state variable. Used by the {link #stop} method for
121 * telling the {@link #run} method to stop and exit when
122 * convenient. Value 1 is a "hard stop", that takes effect even
123 * while performers have things to do, and value 2 is a "soft
124 * stop" that takes effect when all performers are blocking.
126 public int stopping = 0;
129 * A dynamic state variable. Index of the performer to re-run
132 public int index = 0;
135 * The collection of listeners, which get notify about the
136 * thread going to sleep and waking up.
138 public Vector/*<Listener>*/ listeners = new Vector/*<Listener>*/();
141 * Utility method to notify all listeners
143 public void notifyGoingIdle() {
144 Vector/*<Listener>*/ handlers = new Vector/*<Listener>*/();
145 synchronized ( this ) {
146 handlers.addAll( listeners );
148 for ( Iterator/*<Listener>*/ i = handlers.iterator();
150 Listener x = (Listener) i.next();
156 * Utility method to notify all listeners
158 public void notifyWakingUp() {
159 Vector/*<Listener>*/ handlers = new Vector/*<Listener>*/();
160 synchronized ( this ) {
161 handlers.addAll( listeners );
163 for ( Iterator/*<Listener>*/ i = handlers.iterator();
165 Listener x = (Listener) i.next();
171 * Adds a listener to the Executor to be notified when the
172 * Executor goes idle and wakes up from idle
175 synchronized public void addListener(Listener listener) {
176 listeners.add( listener );
180 * Removes a listener from the executor.
183 synchronized public void removeListener(Listener listener) {
184 listeners.remove( listener );
188 * Constructor. The given name is also used as thread name for the
189 * thread that is started.
191 public Executor(String n) {
196 * Returns the executor's name.
198 public String toString() {
203 * Tells whether it is time to change focus or not. This is used
204 * by the {@link Goal.Instance#perform} method to possibly stop
205 * the current computation in order to let the executor shift
206 * focus to another computation. Whenever the {@link #count}
207 * arrives at 0, then it it is time to shift focus, and to reset
208 * the count from {@link #steps}. Though, if the latter is 0 or
209 * negative, then a change of focus will never be signalled from
212 public boolean changeFocus() {
217 if ( Goal.isTracing() )
218 System.err.println( "CHANGE FOCUS" );
224 * Utility method to "preempt" current intention by forcing {@link
225 * #count} to zero. This only has effect if {@link #steps} is
226 * non-zero, i.e., when using intention interleaving.
228 public void preempt() {
233 * Utility method to add a {@link Performer} to be managed by this
234 * executor. If the performer already belongs to an executor, it
235 * is first removed from that one.
237 synchronized public void addPerformer(Performer performer) {
238 if ( performer.executor != null ) {
239 // The performer already belongs to an executor
240 if ( performer.executor != this )
241 performer.executor.removePerformer( performer );
243 if ( ! performers.contains( performer ) )
244 performers.add( performer );
245 performer.executor = this;
249 * Utility method to remove a {@link Performer} from the
250 * collection of performers managed by this executor. This does
251 * not interrupt an ongoing computation, but means that the
252 * executor will not re-run the performer.
254 synchronized public void removePerformer(Performer performer) {
255 if ( performer.executor == this ) {
256 performers.remove( performer );
257 performer.executor = null;
262 * Utility method to localize the first {@link Performer} by its
265 synchronized public Performer findPerformer(String name)
267 for ( Iterator/*<Performer>*/ i =
268 performers.iterator(); i.hasNext(); ) {
269 Performer performer = (Performer) i.next();
270 if ( performer.name.equals( name ) )
277 * Utility method to "tickle" the executor with, just in case it
280 synchronized public void signal() {
286 * A utility method for obtaining the next performer to re-run, or
287 * <em>null</em>, in between having told about them all.
289 synchronized public Performer getNext() {
290 if ( index < performers.size() )
291 return (Performer) performers.get( index++ );
297 * A utility method for going idle when there doesn't seem to be
300 public void waitRunning() {
301 boolean idle = false;
302 synchronized ( this ) {
303 if ( ! running && stopping == 0 )
308 synchronized ( this ) {
310 while ( ! running && stopping == 0 ) {
311 if ( Goal.isTracing() )
313 "** executor " + this + " idle..." );
316 } catch (InterruptedException e) {
323 if ( Goal.isTracing() )
324 System.err.println( "** executor " + this + " active..." );
330 * Utility method to run all {@link Performer Performers} once,
331 * and then report if they all reported blocking or not.
333 public Goal.States runPerformersOnce() {
334 if ( Goal.isTracing() )
335 System.err.println( "** runPerformersOnce" );
336 boolean stopped = false;
337 Performer performer = getNext();
338 while ( performer != null ) {
339 if ( performer.runPerformer() != Goal.States.BLOCKED )
341 performer = getNext();
343 if ( Goal.isTracing() )
344 System.err.println( "** runPerformersOnce stopped " + stopped );
345 return stopped? Goal.States.STOPPED : Goal.States.BLOCKED ;
349 * Utility method to keep running {@link Performer Performers}
350 * while not all are blocking. This method invokes {@link
351 * #runPerformersOnce} repeatedly until it reports that all
352 * performers are blocked.
354 public boolean runPerformersBlocked() {
355 if ( Goal.isTracing() )
356 System.err.println( "** runPerformersBlocked" );
357 boolean done_something = false;
358 while ( runPerformersOnce() != Goal.States.BLOCKED ) {
359 done_something = true;
363 if ( Goal.isTracing() )
365 "** runPerformersBlocked done something " + done_something );
366 return done_something;
370 * This is the main execution loop of the executor. It keeps
371 * running its performers until they are all blocked, in which
372 * case it waits for a signal to re-run them.
375 if ( Goal.isTracing() )
376 System.err.println( "** starting executor " + this );
380 if (runPerformersBlocked()) {
396 } catch (Throwable t) {
398 System.err.println( "** terminating executor " + this );
404 * Tell the {@link #run} method to stop.
406 public void stop(boolean hard) {
407 stopping = hard? 1 : 2;
412 * Service interface to request a goal to be performed by a named
413 * performer, with thread synchronisation on this Executor.
415 synchronized public boolean performGoal(
416 String performer,Goal goal,String head,Data d) {
417 return findPerformer( performer ).performGoal( goal, head, d );
421 * Service interface to request a goal to be performed by a named
422 * performer, with thread synchronisation on this Executor.
424 synchronized public boolean performGoal(
425 String performer,Goal goal,String head,
426 Vector/*<Ref>*/ ins,Vector/*<Ref>*/ outs) {
427 return findPerformer( performer ).performGoal( goal, head, ins, outs );
431 * Service interface to request a goal to be performed by a named
434 public boolean performGoal(
435 String performer,String goal,String head,
436 Vector/*<Ref>*/ ins,Vector/*<Ref>*/ outs) {
437 return findPerformer( performer ).performGoal( goal, head, ins, outs );