|
|
@@ -1,7 +1,7 @@ |
|
|
|
/* |
|
|
|
* The Apache Software License, Version 1.1 |
|
|
|
* |
|
|
|
* Copyright (c) 2001-2002 The Apache Software Foundation. All rights |
|
|
|
* Copyright (c) 2001-2003 The Apache Software Foundation. All rights |
|
|
|
* reserved. |
|
|
|
* |
|
|
|
* Redistribution and use in source and binary forms, with or without |
|
|
@@ -54,6 +54,7 @@ |
|
|
|
|
|
|
|
package org.apache.tools.ant.taskdefs; |
|
|
|
|
|
|
|
import java.lang.reflect.InvocationTargetException; |
|
|
|
import java.lang.reflect.Method; |
|
|
|
import java.util.Enumeration; |
|
|
|
import java.util.Vector; |
|
|
@@ -65,42 +66,140 @@ import java.util.Vector; |
|
|
|
* @since Ant 1.5 |
|
|
|
*/ |
|
|
|
class ProcessDestroyer |
|
|
|
extends Thread { |
|
|
|
implements Runnable { |
|
|
|
|
|
|
|
private Vector processes = new Vector(); |
|
|
|
|
|
|
|
// methods to register and unregister shutdown hooks |
|
|
|
private Method addShutdownHookMethod; |
|
|
|
private Method removeShutdownHookMethod; |
|
|
|
private ProcessDestroyerImpl destroyProcessThread = null; |
|
|
|
|
|
|
|
// whether or not this ProcessDestroyer has been registered as a |
|
|
|
// shutdown hook |
|
|
|
private boolean added = false; |
|
|
|
|
|
|
|
private class ProcessDestroyerImpl extends Thread{ |
|
|
|
private boolean shouldDestroy = true; |
|
|
|
|
|
|
|
public ProcessDestroyerImpl(){ |
|
|
|
super("ProcessDestroyer Shutdown Hook"); |
|
|
|
} |
|
|
|
public void run(){ |
|
|
|
if(shouldDestroy){ |
|
|
|
ProcessDestroyer.this.run(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public void setShouldDestroy(boolean shouldDestroy){ |
|
|
|
this.shouldDestroy = shouldDestroy; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Constructs a <code>ProcessDestroyer</code> and registers it as |
|
|
|
* a shutdown hook. |
|
|
|
* Constructs a <code>ProcessDestroyer</code> and obtains |
|
|
|
* <code>Runtime.addShutdownHook()</code> and |
|
|
|
* <code>Runtime.removeShutdownHook()</code> through reflection. The |
|
|
|
* ProcessDestroyer manages a list of processes to be destroyed when the |
|
|
|
* VM exits. If a process is added when the list is empty, |
|
|
|
* this <code>ProcessDestroyer</code> is registered as a shutdown hook. If |
|
|
|
* removing a process results in an empty list, the |
|
|
|
* <code>ProcessDestroyer</code> is removed as a shutdown hook. |
|
|
|
*/ |
|
|
|
public ProcessDestroyer() { |
|
|
|
try { |
|
|
|
// check to see if the method exists (support pre-JDK 1.3 VMs) |
|
|
|
// |
|
|
|
// check to see if the shutdown hook methods exists |
|
|
|
// (support pre-JDK 1.3 VMs) |
|
|
|
Class[] paramTypes = {Thread.class}; |
|
|
|
Method addShutdownHook = |
|
|
|
addShutdownHookMethod = |
|
|
|
Runtime.class.getMethod("addShutdownHook", paramTypes); |
|
|
|
|
|
|
|
// add the hook |
|
|
|
// |
|
|
|
Object[] args = {this}; |
|
|
|
addShutdownHook.invoke(Runtime.getRuntime(), args); |
|
|
|
|
|
|
|
removeShutdownHookMethod = |
|
|
|
Runtime.class.getMethod("removeShutdownHook", paramTypes); |
|
|
|
// wait to add shutdown hook as needed |
|
|
|
} catch (Exception e) { |
|
|
|
// it just won't be added as a shutdown hook... :( |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Registers this <code>ProcessDestroyer</code> as a shutdown hook, |
|
|
|
* uses reflection to ensure pre-JDK 1.3 compatibility. |
|
|
|
*/ |
|
|
|
private void addShutdownHook(){ |
|
|
|
if(addShutdownHookMethod != null){ |
|
|
|
destroyProcessThread = new ProcessDestroyerImpl(); |
|
|
|
Object[] args = {destroyProcessThread}; |
|
|
|
try { |
|
|
|
addShutdownHookMethod.invoke(Runtime.getRuntime(),args); |
|
|
|
added = true; |
|
|
|
} catch (IllegalAccessException e) { |
|
|
|
// it just won't be added as a shutdown hook... :( |
|
|
|
} catch (InvocationTargetException e) { |
|
|
|
// it just won't be added as a shutdown hook... :( |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Registers this <code>ProcessDestroyer</code> as a shutdown hook, |
|
|
|
* uses reflection to ensure pre-JDK 1.3 compatibility |
|
|
|
*/ |
|
|
|
private void removeShutdownHook(){ |
|
|
|
if(removeShutdownHookMethod != null && destroyProcessThread != null){ |
|
|
|
Object[] args = {destroyProcessThread}; |
|
|
|
try{ |
|
|
|
Boolean removed = |
|
|
|
(Boolean) removeShutdownHookMethod.invoke( |
|
|
|
Runtime.getRuntime(), |
|
|
|
args); |
|
|
|
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 |
|
|
|
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){ |
|
|
|
}catch(InvocationTargetException e){ |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Returns whether or not the ProcessDestroyer is registered as |
|
|
|
* as shutdown hook |
|
|
|
* @return true if this is currently added as shutdown hook |
|
|
|
*/ |
|
|
|
public boolean isAddedAsShutdownHook(){ |
|
|
|
return added; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Returns <code>true</code> if the specified <code>Process</code> was |
|
|
|
* successfully added to the list of processes to destroy upon VM exit. |
|
|
|
* |
|
|
|
* |
|
|
|
* @param process the process to add |
|
|
|
* @return <code>true</code> if the specified <code>Process</code> was |
|
|
|
* successfully added |
|
|
|
*/ |
|
|
|
public boolean add(Process process) { |
|
|
|
processes.addElement(process); |
|
|
|
return processes.contains(process); |
|
|
|
synchronized(processes){ |
|
|
|
// if this list is empty, register the shutdown hook |
|
|
|
if(processes.size() == 0){ |
|
|
|
addShutdownHook(); |
|
|
|
} |
|
|
|
processes.addElement(process); |
|
|
|
return processes.contains(process); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
@@ -112,7 +211,13 @@ class ProcessDestroyer |
|
|
|
* successfully removed |
|
|
|
*/ |
|
|
|
public boolean remove(Process process) { |
|
|
|
return processes.removeElement(process); |
|
|
|
synchronized(processes){ |
|
|
|
boolean processRemoved = processes.removeElement(process); |
|
|
|
if(processes.size() == 0){ |
|
|
|
removeShutdownHook(); |
|
|
|
} |
|
|
|
return processRemoved; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|