ant-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bode...@apache.org
Subject cvs commit: ant/src/main/org/apache/tools/ant/taskdefs ProcessDestroyer.java
Date Wed, 26 Feb 2003 13:06:06 GMT
bodewig     2003/02/26 05:06:06

  Modified:    .        build.xml
               src/main/org/apache/tools/ant/taskdefs ProcessDestroyer.java
  Log:
  Only register ProcessDestroyer when needed (and unregister it when no
  longer needed).
  
  PR: 17216
  Submitted by:	James Allers <jallers at advancedreality dot com>
  
  Revision  Changes    Path
  1.353     +2 -0      ant/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/ant/build.xml,v
  retrieving revision 1.352
  retrieving revision 1.353
  diff -u -r1.352 -r1.353
  --- build.xml	26 Feb 2003 11:37:20 -0000	1.352
  +++ build.xml	26 Feb 2003 13:06:06 -0000	1.353
  @@ -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
  
  
  
  1.6       +123 -18   ant/src/main/org/apache/tools/ant/taskdefs/ProcessDestroyer.java
  
  Index: ProcessDestroyer.java
  ===================================================================
  RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/ProcessDestroyer.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- ProcessDestroyer.java	10 Feb 2003 14:13:36 -0000	1.5
  +++ ProcessDestroyer.java	26 Feb 2003 13:06:06 -0000	1.6
  @@ -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 @@
    * @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 @@
        *          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;
  +        }
       }
   
       /**
  
  
  

Mime
View raw message