conor 2003/07/25 04:02:53 Modified: . WHATSNEW docs/manual/CoreTasks parallel.html src/main/org/apache/tools/ant/taskdefs Parallel.java Log: Add <daemons> element to <parallel> to start <daemon> threads which continue to run after the <parallel> task has completed. Revision Changes Path 1.468 +10 -2 ant/WHATSNEW Index: WHATSNEW =================================================================== RCS file: /home/cvs/ant/WHATSNEW,v retrieving revision 1.467 retrieving revision 1.468 diff -u -w -u -r1.467 -r1.468 --- WHATSNEW 25 Jul 2003 10:06:31 -0000 1.467 +++ WHATSNEW 25 Jul 2003 11:02:52 -0000 1.468 @@ -515,6 +515,14 @@ * <exec> will now work on OpenVMS (please read the notes in <exec>'s manual page). Bugzilla Report 21877. + +* <parallel> now supports a timeout which can be used to recover + from deadlocks, etc in the parallel threads. <parallel> also + now supports a <daemons> nested element. This can be used to + run tasks in daemon threads which the parallel task will not + wait for before completing. A new attribute failonany will cause + <parallel> to throw an exception if any thread fails without + waiting for all other threads to complete. Changes from Ant 1.5.2 to Ant 1.5.3 =================================== 1.12 +19 -0 ant/docs/manual/CoreTasks/parallel.html Index: parallel.html =================================================================== RCS file: /home/cvs/ant/docs/manual/CoreTasks/parallel.html,v retrieving revision 1.11 retrieving revision 1.12 diff -u -w -u -r1.11 -r1.12 --- parallel.html 24 Jul 2003 14:24:07 -0000 1.11 +++ parallel.html 25 Jul 2003 11:02:53 -0000 1.12 @@ -99,6 +99,25 @@ would occur. This is not a repalcement for Java Language level thread semantics and is best used for "embarassingly parallel" tasks.</p> + +<h3>Parameters specified as nested elements</h3> + +<h4>daemons</h4> +<p> +The parallel task supports a <daemons> nested element. This is a list of tasks +which are to be run in parallel daemon threads. The parallel task will not wait for +these tasks to complete. Being daemon threads, however, they will not prevent Ant from +completing, whereupon the threads are terminated. Failures in daemon threads which +occur before the parallel task itself finishes will be reported and can cause +parallel to throw an exception. Failures which occur after parallel has completed are not +reported. +</p> + +<p>Daemon tasks can be used, for example, to start test servers which might not be easily +terminated from Ant. By using <daemons> such servers do not halt the build. +</p> + + <h3>Examples</h3> <pre> <parallel> 1.23 +116 -54 ant/src/main/org/apache/tools/ant/taskdefs/Parallel.java Index: Parallel.java =================================================================== RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/Parallel.java,v retrieving revision 1.22 retrieving revision 1.23 diff -u -w -u -r1.22 -r1.23 --- Parallel.java 25 Jul 2003 08:59:39 -0000 1.22 +++ Parallel.java 25 Jul 2003 11:02:53 -0000 1.23 @@ -56,6 +56,8 @@ import java.lang.reflect.Method; import java.util.Enumeration; import java.util.Vector; +import java.util.List; +import java.util.ArrayList; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Location; import org.apache.tools.ant.Task; @@ -86,6 +88,21 @@ public class Parallel extends Task implements TaskContainer { + /** Class which holds a list of tasks to execute */ + public static class TaskList implements TaskContainer { + /** Collection holding the nested tasks */ + private List tasks = new ArrayList(); + + /** + * Add a nested task to execute parallel (asynchron). + * <p> + * @param nestedTask Nested task to be executed in parallel + */ + public void addTask(Task nestedTask) throws BuildException { + tasks.add(nestedTask); + } + } + /** Collection holding the nested tasks */ private Vector nestedTasks = new Vector(); @@ -98,12 +115,13 @@ /** Total number of threads per processor to run. */ private int numThreadsPerProcessor = 0; + /** The timeout period in milliseconds */ private long timeout; /** Indicates threads are still running and new threads can be issued */ private volatile boolean stillRunning; - /** INdicates that the execution timedout */ + /** Indicates that the execution timedout */ private boolean timedOut; /** @@ -112,6 +130,31 @@ */ private boolean failOnAny; + /** The dameon task list if any */ + private TaskList daemonTasks; + + /** Accumulation of exceptions messages from all nested tasks */ + private StringBuffer exceptionMessage; + + /** Number of exceptions from nested tasks */ + private int numExceptions = 0; + + /** The first exception encountered */ + private Throwable firstException; + + /** The location of the first exception */ + private Location firstLocation; + + /** + * Add a group of daemon threads + */ + public void addDaemons(TaskList daemonTasks) { + if (this.daemonTasks != null) { + throw new BuildException("Only one daemon group is supported"); + } + this.daemonTasks = daemonTasks; + } + /** * Interval to poll for completed threads when threadCount or * threadsPerProcessor is specified. Integer in milliseconds.; optional @@ -211,6 +254,27 @@ } } + private void processExceptions(TaskRunnable[] runnables) { + if (runnables == null) { + return; + } + for (int i = 0; i < runnables.length; ++i) { + Throwable t = runnables[i].getException(); + if (t != null) { + numExceptions++; + if (firstException == null) { + firstException = t; + } + if (t instanceof BuildException + && firstLocation == Location.UNKNOWN_LOCATION) { + firstLocation = ((BuildException) t).getLocation(); + } + exceptionMessage.append(StringUtils.LINE_SEP); + exceptionMessage.append(t.getMessage()); + } + } + } + /** * Spin up required threads with a maximum number active at any given time. * @@ -227,7 +291,7 @@ threadNumber++) { Task nestedTask = (Task) e.nextElement(); runnables[threadNumber] - = new TaskRunnable(threadNumber, nestedTask); + = new TaskRunnable(nestedTask); } final int maxRunning = numTasks < numThreads ? numTasks : numThreads; @@ -236,7 +300,23 @@ threadNumber = 0; ThreadGroup group = new ThreadGroup("parallel"); - // now run them in limited numbers... + TaskRunnable[] daemons = null; + if (daemonTasks != null && daemonTasks.tasks.size() != 0) { + daemons = new TaskRunnable[daemonTasks.tasks.size()]; + } + + synchronized (semaphore) { + // start any daemon threads + if (daemons != null) { + for (int i = 0; i < daemons.length; ++i) { + daemons[i] = new TaskRunnable((Task) daemonTasks.tasks.get(i)); + Thread daemonThread = new Thread(group, daemons[i]); + daemonThread.setDaemon(true); + daemonThread.start(); + } + } + + // now run main threads in limited numbers... // start initial batch of threads for (int i = 0; i < maxRunning; ++i) { running[i] = runnables[threadNumber++]; @@ -266,7 +346,6 @@ // now find available running slots for the remaining threads outer: while (threadNumber < numTasks && stillRunning) { - synchronized (semaphore) { for (int i = 0; i < maxRunning; i++) { if (running[i] == null || running[i].finished) { running[i] = runnables[threadNumber++]; @@ -288,9 +367,7 @@ // sheesh! } } - } - synchronized (semaphore) { // are all threads finished outer2: while (stillRunning) { @@ -315,25 +392,12 @@ } // now did any of the threads throw an exception - StringBuffer exceptionMessage = new StringBuffer(); - int numExceptions = 0; - Throwable firstException = null; - Location firstLocation = Location.UNKNOWN_LOCATION; - for (int i = 0; i < numTasks; ++i) { - Throwable t = runnables[i].getException(); - if (t != null) { - numExceptions++; - if (firstException == null) { - firstException = t; - } - if (t instanceof BuildException - && firstLocation == Location.UNKNOWN_LOCATION) { - firstLocation = ((BuildException) t).getLocation(); - } - exceptionMessage.append(StringUtils.LINE_SEP); - exceptionMessage.append(t.getMessage()); - } - } + exceptionMessage = new StringBuffer(); + numExceptions = 0; + firstException = null; + firstLocation = Location.UNKNOWN_LOCATION; + processExceptions(daemons); + processExceptions(runnables); if (numExceptions == 1) { if (firstException instanceof BuildException) { @@ -373,7 +437,6 @@ private class TaskRunnable implements Runnable { private Throwable exception; private Task task; - private int taskNumber; boolean finished; /** @@ -381,9 +444,8 @@ * * @param task the Task to be executed in a seperate thread */ - TaskRunnable(int taskNumber, Task task) { + TaskRunnable(Task task) { this.task = task; - this.taskNumber = taskNumber; } /**
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]