From f1e7b4baf59161757ad5d81e6d7938b827ba36b0 Mon Sep 17 00:00:00 2001 From: Jacobus Martinus Kruithof Date: Sun, 16 Sep 2007 21:08:08 +0000 Subject: [PATCH] Improved InterruptException handling, especially from Parallel task. Should also solve Pr 42924. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@576176 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/tools/ant/taskdefs/Parallel.java | 98 +++++++++++++------ .../apache/tools/ant/taskdefs/Redirector.java | 6 +- .../apache/tools/ant/taskdefs/WaitFor.java | 27 ++--- .../org/apache/tools/ant/util/Watchdog.java | 11 ++- 4 files changed, 91 insertions(+), 51 deletions(-) diff --git a/src/main/org/apache/tools/ant/taskdefs/Parallel.java b/src/main/org/apache/tools/ant/taskdefs/Parallel.java index 8425a6973..d3aedcecc 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Parallel.java +++ b/src/main/org/apache/tools/ant/taskdefs/Parallel.java @@ -248,6 +248,7 @@ public class Parallel extends Task TaskRunnable[] runnables = new TaskRunnable[numTasks]; stillRunning = true; timedOut = false; + boolean interrupted = false; int threadNumber = 0; for (Enumeration e = nestedTasks.elements(); e.hasMoreElements(); @@ -314,50 +315,48 @@ public class Parallel extends Task timeoutThread.start(); } - // now find available running slots for the remaining threads - outer: - while (threadNumber < numTasks && stillRunning) { - for (int i = 0; i < maxRunning; i++) { - if (running[i] == null || running[i].isFinished()) { - running[i] = runnables[threadNumber++]; - Thread thread = new Thread(group, running[i]); - thread.start(); - // continue on outer while loop to get another - // available slot - continue outer; + try { + // now find available running slots for the remaining threads + outer: while (threadNumber < numTasks && stillRunning) { + for (int i = 0; i < maxRunning; i++) { + if (running[i] == null || running[i].isFinished()) { + running[i] = runnables[threadNumber++]; + Thread thread = new Thread(group, running[i]); + thread.start(); + // continue on outer while loop to get another + // available slot + continue outer; + } } - } - // if we got here all slots in use, so sleep until - // something happens - try { + // if we got here all slots in use, so sleep until + // something happens semaphore.wait(); - } catch (InterruptedException ie) { - // doesn't java know interruptions are rude? - // just pretend it didn't happen and go about out business. - // sheesh! } - } - // are all threads finished - outer2: - while (stillRunning) { - for (int i = 0; i < maxRunning; ++i) { - if (running[i] != null && !running[i].isFinished()) { - //System.out.println("Thread " + i + " is still alive "); - // still running - wait for it - try { + // are all threads finished + outer2: while (stillRunning) { + for (int i = 0; i < maxRunning; ++i) { + if (running[i] != null && !running[i].isFinished()) { + // System.out.println("Thread " + i + " is still + // alive "); + // still running - wait for it semaphore.wait(); - } catch (InterruptedException ie) { - // who would interrupt me at a time like this? + continue outer2; } - continue outer2; } + stillRunning = false; } - stillRunning = false; + } catch (InterruptedException ie) { + interrupted = true; } + + killAll(running); } + if (interrupted){ + throw new BuildException("Parallel execution interrupted."); + } if (timedOut) { throw new BuildException("Parallel execution timed out"); } @@ -382,6 +381,34 @@ public class Parallel extends Task } } + /** + * Doesn't do anything if all threads where already gone, + * else it tries to kill the threads 3 times. + * @param running The list of tasks that may currently be running. + */ + private void killAll(TaskRunnable[] running) { + boolean oneAlive; + int tries = 0; + do + { + oneAlive = false; + for (int i = 0; i < running.length; i++) + { + if (running[i] != null && ! running[i].isFinished()) + { + running[i].interrupt(); + Thread.yield(); + oneAlive = true; + } + } + if (oneAlive) + { + tries++; + Thread.yield(); + } + } while (oneAlive && tries < 100); + } + /** * Determine the number of processors. Only effective on later VMs * @@ -409,6 +436,7 @@ public class Parallel extends Task private Throwable exception; private Task task; private boolean finished; + private volatile Thread thread; /** * Construct a new TaskRunnable.

@@ -425,6 +453,7 @@ public class Parallel extends Task */ public void run() { try { + thread = Thread.currentThread(); task.perform(); } catch (Throwable t) { exception = t; @@ -454,6 +483,11 @@ public class Parallel extends Task boolean isFinished() { return finished; } + + void interrupt() + { + thread.interrupt(); + } } } diff --git a/src/main/org/apache/tools/ant/taskdefs/Redirector.java b/src/main/org/apache/tools/ant/taskdefs/Redirector.java index ff6ec4812..359f1609a 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Redirector.java +++ b/src/main/org/apache/tools/ant/taskdefs/Redirector.java @@ -781,7 +781,11 @@ public class Redirector { } wait(1000); } catch (InterruptedException eyeEx) { - // Ignore exception + Thread[] thread = new Thread[threadGroup.activeCount()]; + threadGroup.enumerate(thread); + for (int i = 0; i < thread.length && thread[i] != null; i++) { + thread[i].interrupt(); + } } } diff --git a/src/main/org/apache/tools/ant/taskdefs/WaitFor.java b/src/main/org/apache/tools/ant/taskdefs/WaitFor.java index 2a85dd0c8..222f1281e 100644 --- a/src/main/org/apache/tools/ant/taskdefs/WaitFor.java +++ b/src/main/org/apache/tools/ant/taskdefs/WaitFor.java @@ -135,21 +135,22 @@ public class WaitFor extends ConditionBase { long savedMaxWaitMillis = maxWaitMillis; long savedCheckEveryMillis = checkEveryMillis; try { - maxWaitMillis *= maxWaitMultiplier; - checkEveryMillis *= checkEveryMultiplier; - long start = System.currentTimeMillis(); - long end = start + maxWaitMillis; - - while (System.currentTimeMillis() < end) { - if (c.eval()) { - processSuccess(); - return; - } - try { + try { + maxWaitMillis *= maxWaitMultiplier; + checkEveryMillis *= checkEveryMultiplier; + long start = System.currentTimeMillis(); + long end = start + maxWaitMillis; + + while (System.currentTimeMillis() < end) { + if (c.eval()) { + processSuccess(); + return; + } Thread.sleep(checkEveryMillis); - } catch (InterruptedException e) { - // ignore } + } catch (InterruptedException e) { + log("Task " + getTaskName() + + " interrupted, treating as timed out."); } processTimeout(); } finally { diff --git a/src/main/org/apache/tools/ant/util/Watchdog.java b/src/main/org/apache/tools/ant/util/Watchdog.java index 826a8fd75..a6bcd7260 100644 --- a/src/main/org/apache/tools/ant/util/Watchdog.java +++ b/src/main/org/apache/tools/ant/util/Watchdog.java @@ -110,13 +110,14 @@ public class Watchdog implements Runnable { */ public synchronized void run() { final long until = System.currentTimeMillis() + timeout; - long now; - while (!stopped && until > (now = System.currentTimeMillis())) { - try { + long now = until - 1; + try { + while (!stopped && until > now) { + now = System.currentTimeMillis(); wait(until - now); - } catch (InterruptedException e) { - // Ignore exception } + } catch (InterruptedException e) { + // Ignore exception } if (!stopped) { fireTimeoutOccured();