|
|
@@ -38,6 +38,9 @@ class ProcessDestroyer implements Runnable { |
|
|
|
// whether or not this ProcessDestroyer has been registered as a |
|
|
|
// shutdown hook |
|
|
|
private boolean added = false; |
|
|
|
// whether or not this ProcessDestroyer is currently running as |
|
|
|
// shutdown hook |
|
|
|
private boolean running = false; |
|
|
|
|
|
|
|
private class ProcessDestroyerImpl extends Thread { |
|
|
|
private boolean shouldDestroy = true; |
|
|
@@ -89,7 +92,7 @@ class ProcessDestroyer implements Runnable { |
|
|
|
* uses reflection to ensure pre-JDK 1.3 compatibility. |
|
|
|
*/ |
|
|
|
private void addShutdownHook() { |
|
|
|
if (addShutdownHookMethod != null) { |
|
|
|
if (addShutdownHookMethod != null && !running) { |
|
|
|
destroyProcessThread = new ProcessDestroyerImpl(); |
|
|
|
Object[] args = {destroyProcessThread}; |
|
|
|
try { |
|
|
@@ -98,7 +101,13 @@ class ProcessDestroyer implements Runnable { |
|
|
|
} catch (IllegalAccessException e) { |
|
|
|
e.printStackTrace(); |
|
|
|
} catch (InvocationTargetException e) { |
|
|
|
e.printStackTrace(); |
|
|
|
Throwable t = e.getCause(); |
|
|
|
if (t != null && t.getClass() == IllegalStateException.class) { |
|
|
|
// shutdown already is in progress |
|
|
|
running = true; |
|
|
|
} else { |
|
|
|
e.printStackTrace(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@@ -108,7 +117,7 @@ class ProcessDestroyer implements Runnable { |
|
|
|
* uses reflection to ensure pre-JDK 1.3 compatibility |
|
|
|
*/ |
|
|
|
private void removeShutdownHook() { |
|
|
|
if (removeShutdownHookMethod != null && destroyProcessThread != null) { |
|
|
|
if (removeShutdownHookMethod != null && added && !running) { |
|
|
|
Object[] args = {destroyProcessThread}; |
|
|
|
try { |
|
|
|
Boolean removed = |
|
|
@@ -118,25 +127,31 @@ class ProcessDestroyer implements Runnable { |
|
|
|
if (!removed.booleanValue()) { |
|
|
|
System.err.println("Could not remove shutdown hook"); |
|
|
|
} |
|
|
|
// start the hook thread, a unstarted thread may not be |
|
|
|
// eligible for garbage collection |
|
|
|
// Cf.: http://developer.java.sun.com/developer/bugParade/bugs/4533087.html |
|
|
|
destroyProcessThread.setShouldDestroy(false); |
|
|
|
destroyProcessThread.start(); |
|
|
|
// this should return quickly, since Process.destroy() |
|
|
|
try { |
|
|
|
destroyProcessThread.join(20000); |
|
|
|
} catch (InterruptedException ie) { |
|
|
|
// the thread didn't die in time |
|
|
|
// it should not kill any processes unexpectedly |
|
|
|
} |
|
|
|
destroyProcessThread = null; |
|
|
|
added = false; |
|
|
|
} catch (IllegalAccessException e) { |
|
|
|
e.printStackTrace(); |
|
|
|
} catch (InvocationTargetException e) { |
|
|
|
e.printStackTrace(); |
|
|
|
Throwable t = e.getCause(); |
|
|
|
if (t != null && t.getClass() == IllegalStateException.class) { |
|
|
|
// shutdown already is in progress |
|
|
|
running = true; |
|
|
|
} else { |
|
|
|
e.printStackTrace(); |
|
|
|
} |
|
|
|
} |
|
|
|
// start the hook thread, a unstarted thread may not be |
|
|
|
// eligible for garbage collection |
|
|
|
// Cf.: http://developer.java.sun.com/developer/bugParade/bugs/4533087.html |
|
|
|
destroyProcessThread.setShouldDestroy(false); |
|
|
|
destroyProcessThread.start(); |
|
|
|
// this should return quickly, since it basically is a NO-OP. |
|
|
|
try { |
|
|
|
destroyProcessThread.join(20000); |
|
|
|
} catch (InterruptedException ie) { |
|
|
|
// the thread didn't die in time |
|
|
|
// it should not kill any processes unexpectedly |
|
|
|
} |
|
|
|
destroyProcessThread = null; |
|
|
|
added = false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@@ -179,8 +194,7 @@ class ProcessDestroyer implements Runnable { |
|
|
|
public boolean remove(Process process) { |
|
|
|
synchronized (processes) { |
|
|
|
boolean processRemoved = processes.removeElement(process); |
|
|
|
if (processes.size() == 0) { |
|
|
|
processes.notifyAll(); |
|
|
|
if (processRemoved && processes.size() == 0) { |
|
|
|
removeShutdownHook(); |
|
|
|
} |
|
|
|
return processRemoved; |
|
|
@@ -192,17 +206,11 @@ class ProcessDestroyer implements Runnable { |
|
|
|
*/ |
|
|
|
public void run() { |
|
|
|
synchronized (processes) { |
|
|
|
running = true; |
|
|
|
Enumeration e = processes.elements(); |
|
|
|
while (e.hasMoreElements()) { |
|
|
|
((Process) e.nextElement()).destroy(); |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
// wait for all processes to finish |
|
|
|
processes.wait(); |
|
|
|
} catch (InterruptedException interrupt) { |
|
|
|
// ignore |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |