Browse Source

Only register ProcessDestroyer when needed (and unregister it when no

longer needed).

PR: 17216
Submitted by:	James Allers <jallers at advancedreality dot com>


git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274187 13f79535-47bb-0310-9956-ffa450edef68
master
Stefan Bodewig 22 years ago
parent
commit
198cca7aa6
2 changed files with 125 additions and 18 deletions
  1. +2
    -0
      build.xml
  2. +123
    -18
      src/main/org/apache/tools/ant/taskdefs/ProcessDestroyer.java

+ 2
- 0
build.xml View File

@@ -1608,6 +1608,8 @@
unless="tests.and.ant.share.classloader"/>
<exclude name="${optional.package}/metamata/MAuditParserTest.java"
unless="tests.and.ant.share.classloader"/>
<exclude name="${ant.package}/taskdefs/ProcessDestroyerTest.java"
unless="tests.and.ant.share.classloader"/>

<!-- can only run if cvs is installed on your machine
enable by setting the property have.cvs


+ 123
- 18
src/main/org/apache/tools/ant/taskdefs/ProcessDestroyer.java View File

@@ -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;
}
}

/**


Loading…
Cancel
Save