ant-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bugzi...@apache.org
Subject DO NOT REPLY [Bug 28565] - org.apache.tools.ant.taskdefs.Execute
Date Mon, 26 Apr 2004 20:40:56 GMT
DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG 
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://issues.apache.org/bugzilla/show_bug.cgi?id=28565>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND 
INSERTED IN THE BUG DATABASE.

http://issues.apache.org/bugzilla/show_bug.cgi?id=28565

org.apache.tools.ant.taskdefs.Execute

gus_goose@canada.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|RESOLVED                    |REOPENED
         Resolution|INVALID                     |



------- Additional Comments From gus_goose@canada.com  2004-04-26 20:40 -------
Hi Matt, others.

Having re-visited the code, and been even more diligent with my study, I
maintain that there IS a problem with Input/Output streams not being closed. Let
me show by example:

Take the core class org.apache.tools.ant.taskdefs.AbstractCvsTask (base for 4
CVS related tasks. It's execute() method calls the runCommand() method (multiple
times). The runCommand() method creates an org.apache.tools.ant.taskdefs.Execute
instance using a PumpStreamHandler. After setting the environment, workingdir,
etc, it calls the execute() method of the Execute instance.

This is where it gets important.

The execute() method calls the launch() method which returns a java.lang.Process
instance. This is the important instance (variable name is "process"). The
following code runs:
            streamHandler.setProcessInputStream(process.getOutputStream());
            streamHandler.setProcessOutputStream(process.getInputStream());
            streamHandler.setProcessErrorStream(process.getErrorStream());

The Important three streams to follow are:
process.getOutputStream() (I'll call it NB_A)
process.getInputStream() NB_B,
process.getErrorStream() NB_C

Each of these three streams represents a FileDescriptor on Unix OS's.
execute() starts the ExecuteStreamHandler(in our example, a PumpStreamHandler)
execute() waits for the process to complete, and then stop() the PumpStreamHandler.

It returns the exit code of the java.lang.Process instance.

Now, NB_A, NB_B, and NB_C are never close()'d in the execute(). If you inspect
the PumpStreamHandler, you will note that it only (optionally) close()'s the
streams to which it pumps the data to, it does not close() the actual streams
provided by the Process (NB_A,NB_B, and NB_C).

Thus, the only time the NB_A, NB_B, and NB_C streams are close()'d are when the
ExecuteStreamHandler given to the Execute class explicitly does it. By far the
majority of times the Execute class is used, it is used with either the
PumpStreamHandler, or LogStreamHandler. Neither of these classes close the
Process input/output streams. Thus, the vast majority of executions (including
ExtarnalJavac, CVS, VSS, and other Ant tasks leave open file descriptors long
after they are discarded in the code (but not yet Garbage Collected).

In all instances where I have inspected the use of Execute class (19 instances
so far), I have found that it would be safe to close the three streams NB_A,
NB_B, and NB_C after calling the stop() method of the ExecuteStreamHandler.

Attached is a small build file (good for Unix environment - correct the location
for ksh, and lsof) that shows the problem:

<project name="ShowBug" default="bug">

  <property name="ksh" value="/usr/bin/ksh" />
  <property name="lsof" value="/usr/local/bin/lsof" />

  <target name="pid">
    <echo file="getpid" >
      echo PPID=$PPID
    </echo>
    <exec executable="${ksh}" output="pidout" >
      <arg line="getpid " />
    </exec>
    <property file="pidout" />
    <echo message="I am process ${PPID}" />
  </target>

  <target name="lsofa" depends="pid" >
    <exec executable="${lsof}" >
      <arg line=" -p ${PPID}" />
    </exec>
  </target>

  <target name="lsofb" >
    <exec executable="${lsof}" >
      <arg line=" -p ${PPID}" />
    </exec>
  </target>

  <target name="reproduce" >
    <exec executable="/bin/true" />
    <exec executable="/bin/true" />
    <exec executable="/bin/true" />
    <exec executable="/bin/true" />
    <exec executable="/bin/true" />
    <exec executable="/bin/true" />
    <exec executable="/bin/true" />
    <exec executable="/bin/true" />
    <exec executable="/bin/true" />
    <exec executable="/bin/true" />
  </target>

  <target name="bug" depends="lsofa,reproduce,lsofb">
  </target>
</project>


gus

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org


Mime
View raw message