Submitted On 16-JAN-2003
metskem
I'm experiencing the same problem, I have a Java program
running for weeks on Linux (Sun JDK 1.4) and a "ps -u
myuser" command shows processes active still performing the
exec("command") while the proc.waitFor() has already ended.
The only clumsy workaround is to kill these processes by hand.
Submitted On 16-JAN-2003
metskem
Harry Metske
h.metske@rf.rabobank.nl
Submitted On 04-FEB-2003
aneth
Workaround is to always launch the process with "java xxx"
and pass the environment into Runtime.exec. To get the
environment requires doing a Runtime.exec("cmd /C set");
Submitted On 18-MAR-2003
sisutcliffe
I'm having a similar Problem on Windows XP, all that
Process.destroy() seems to do is to Pause the process while
the JVM is still running. As soon as the JVM exits the
Process resumes until it has terminated, normally or otherwise.
[Also don't understand what aneth means in the reply for a
workaround.]
Submitted On 24-MAR-2003
sisutcliffe
should also have indicated that I'm using j2sdk1.4.1_02 or
j2re1.4.1_02 on Windows 98 thru XP
Submitted On 28-APR-2003
rajatroy
I work on a product in Cisco, and it is not causing all the child
processes to exit.
Submitted On 29-MAY-2003
s_narra
I am experiencing the same problem with process.destroy().
The child sub-processes must be killed, instead, it is still
running. Is there a differnet way to successfully kill the
child processes?
Submitted On 11-JUL-2003
hiwa
Should that really be called bug? Practically you launch two
processes in the poor method which can only return one
process. Also, apparently these two process, shell+batch
file and JVM, do not have parent/child relationship. Could
you claim that it is the correct canonical use of the
Runtime.exec() method? I can't think so, though I think
current behavior of the method is erroneously too generous!
Submitted On 15-JUL-2003
boylard1980
I'll also post my suggested work-around... which is really
nasty and specific to the version of ps installed on our
Linux machine, but it could be adapted:
The StreamGobbler class is another small Thread that gathers
up un-needed output from a process...
class ProcessKiller extends Thread {
// this provides info on all running processes, with all
a user's
// processes grouped together in the output. Need to
filter the
// output to only 'slave' owned accounts that are not
java processes and
// have been running for more than 60 seconds.
// The columns displayed are process id, running time,
owner and the
// command used to start the process. Therefore, the
owner is the third
// word on a line, while the command is everything after
that, if words
// are counted as characters with spaces between them.
private static String[] ps = {"ps", "x", "-eo", "\"%p %t
%U %a\"",
"--sort", "user"};
// forms the start of the kill command, process ids are
added on the end
private static String kill = "kill";
private Runtime rt;
private boolean shouldRun = false;
/**
* Initialises the killer
*/
public ProcessKiller(){
// set Priority to somewhere between the background
and normal
// in the javadoc MIN_PRIORITY is 1 while
NORM_PRIORITY is 5
setPriority(Thread.MIN_PRIORITY+2);
setDaemon(true);
rt = Runtime.getRuntime();
String osName = System.getProperty("os.name");
if(!(osName == null || osName.equals("")) &&
osName.equals("Linux"))
shouldRun = true;
}
/**
* Only starts execution if being called on a Linux OS,
sleeps for 30
* seconds between checks on running processes.
*/
public void run(){
if(!shouldRun)
return;
while(true){
checkRunningProcesses();
// sleep for 30 seconds between checks
try{
sleep(30000);
}catch(InterruptedException e){}
}
}
/**
* Checks non-java slave-owned processes to see there
running time.
* Because of the way the server is configured, there not
should be any
* of these processes left running 30 seconds after they
start
*/
private void checkRunningProcesses(){
try{
// run ps, consuming the outputs
Process psProc = rt.exec(ps);
StreamGobbler errorGobbler = new
StreamGobbler(psProc.getErrorStream(), "ERROR");
errorGobbler.start();
InputStream in = psProc.getInputStream();
BufferedReader br = new BufferedReader(
new InputStreamReader(in));
StringWriter psOutput = new StringWriter();
readFromBuffer(br, psOutput);
// wait for process to finish
try{
psProc.waitFor();
} catch( InterruptedException ie ){}
br.close();
// tokeniser converts string into tokens
consisting of lines
StringTokenizer tok = new
StringTokenizer(psOutput.toString(),
"\n\r\f");
int currentPos = 0;
StringBuffer temp = new StringBuffer();
while(tok.hasMoreElements()){
String newTok = tok.nextToken();
// only keep lines with no occurence of java and
an occurence of slave
if(newTok.indexOf("java") == -1 &&
newTok.indexOf("slave") != -1)
temp.append(newTok+"\n");
}
Submitted On 15-JUL-2003
boylard1980
The example here is perhaps a poor one, what about the case
where someone calls a shell script that has been submitted
for some test. This script could be anything, say a student
submission for an assignment which will then have
lecturer-defined tests run on it. In such a case it is
sometimes necessary to forcibly terminate a process if it
has gone on so long that it has failed the test. There needs
to be some way to access information about processes spawned
by the original process and have them destroyed as well,
even if this is not included as part of the functionality of
destroy().
Perhaps a method that returns a Process[] of spawned
processes? Or a destoryThisAndItsFilthySpawn() method?
Submitted On 15-JUL-2003
boylard1980
String fromGrep = temp.toString();
// the lines left contain the execution times of
processes,
// remove lines with less than 30 seconds of
execution
tok = new StringTokenizer(fromGrep);
Vector pids = new Vector();
String prevTok = "", newTok = null;
while(tok.hasMoreElements()){
if(newTok != null)
prevTok = newTok;
newTok = tok.nextToken(" \t\n\r\f");
// first occurence of ':' on a line means
this token is the time
// as process ids don't contain ':'.
if(newTok.indexOf(':') != -1){
int numberOfSecs = parseSecs(newTok);
// previous token is the process id
if(numberOfSecs > 30 &&
tok.nextToken().indexOf("slave") != -1)
pids.add(prevTok);
// move tokeniser to end of line
tok.nextToken("\n\r\f");
}
}
// pids vector contains the process id's of all
processes owned by
// slave but not java and running for more than
30 seconds
if(pids.size() == 0)
return;
String[] killCmd = new String[pids.size()+1];
killCmd[0] = kill;
for(int i = 0; i<pids.size(); i++){
killCmd[i+1] = (String) pids.get(i);
}
// run the kill command
Process killProc = rt.exec(killCmd);
StreamGobbler err = new
StreamGobbler(killProc.getErrorStream(),
"ERROR");
StreamGobbler outGob = new
StreamGobbler(killProc.getInputStream(),
"OUTPUT");
err.start();
outGob.start();
} catch(IOException ioe){
System.err.println(ioe.getMessage());
}
}
private void readFromBuffer(final BufferedReader br,
final StringWriter retBuff){
Runnable r = new Runnable(){
public void run(){
String line = null;
try{
while((line = br.readLine()) != null){
retBuff.write(line.replaceAll("\"",
"")+"\n");
}
}catch(IOException ioe){
System.err.println(ioe.getMessage());
}
}
};
Thread reader = new Thread(r);
reader.start();
}
private int parseSecs(String time){
// input is in form dd-hh:mm:ss, where days and
hours are optional
StringTokenizer tok = new StringTokenizer(time, ":-");
int numToks = 0;
try{
numToks = tok.countTokens();
int days = 0, hours = 0, minutes = 0, seconds = 0;
if(numToks == 4)
days = Integer.parseInt(tok.nextToken());
if(numToks > 2)
hours = Integer.parseInt(tok.nextToken());
minutes = Integer.parseInt(tok.nextToken());
seconds = Integer.parseInt(tok.nextToken());
return seconds + (minutes*60) + (hours*60*60) +
(days*24*60*60);
}catch(NoSuchElementException nsee){
return 0;
}
}
Submitted On 10-DEC-2003
digizard
I am eagerly waiting for the resolution of this bug, as it
is really stopping me from using external processes
correctly.
Submitted On 21-MAY-2004
wishfordynamism
The key is not so much that sub-child processes are killed explicitly by java but that the termination handler of the exec()ed process is being by-passed.
Java should provide the means for being able to cause an exec()ed processes termination handler to be invoked.
Submitted On 08-JUN-2004
aedwards66
I would really enjoy a destroyWithChildren method on the Runtime class.
It would also be very, very useful if the Runtime class had a getPid method? Why doesn't it?
Submitted On 25-OCT-2004
Doron.Rajwan
As it is defined today, the destroy() method is not related to waitFor() and to inputStream.read() methods. The semantics must be coherent: call on destroy() from one thread must unlock any other thread waiting on waitFor() and/or waiting on inputStream.read() methods.
Also, it would be nice to add methods that waitFor() / destroy() a process tree. Currently, it seems that destroy() working on the process itself, while waitFor() waits for the process tree.
Also, add methods to get java.nio.Channel, not input stream, so it will be possible to have non-blocking implementation as well. Again, everything must be coherent.
Also, add support to run external process and set its input/output to null device. This is needed for tasks that I do not want to read their output, but I do not want them to hang as well.
Also, make ProcessBuilder a serializable class. It is just a container for parameters.
Thanks,
Doron Rajwan.
Submitted On 26-SEP-2005
mthornton
The fundamental problem here is that, unlike Unix, Windows does that maintain parent-child relationships between processes. A process can kill its own immediate children, but unless you make other arrangements to obtain the information, can't kill any 'grand-children' because it has no way of finding them. Ctrl-C types at a command prompt is just a character that the command processor interprets and not a signal sent from outside. When you 'destroy' a child command script, that process does not get the opportunity to terminate any child processes it may know about.
Recent versions of WIndows (2000 or later) do provide a "Job" concept which acts as a container for processes. Killing a Job does terminate all processes associated with that job. However Jobs do not contain other jobs, so fully emulating the Unix behaviour is probably impossible.
Submitted On 26-SEP-2005
mthornton
The fundamental problem here is that, unlike Unix, Windows does that maintain parent-child relationships between processes. A process can kill its own immediate children, but unless you make other arrangements to obtain the information, can't kill any 'grand-children' because it has no way of finding them. Ctrl-C types at a command prompt is just a character that the command processor interprets and not a signal sent from outside. When you 'destroy' a child command script, that process does not get the opportunity to terminate any child processes it may know about.
Recent versions of WIndows (2000 or later) do provide a "Job" concept which acts as a container for processes. Killing a Job does terminate all processes associated with that job. However Jobs do not contain other jobs, so fully emulating the Unix behaviour is probably impossible.
Submitted On 19-NOV-2007
PatIC
What are the arguments against providing reliable killing of processes on Windows by using the Job API behind the scenes on platforms where this is possible?
Something like:
if(OS == Win2000 OR higher)
createJobObject()
Submitted On 27-FEB-2009
Rodney_Beede
It would seem that Windows does have a way of obtaining all the children and descendants of a process. It involves forming a tree of all running processes and looking at the parent pid of each.
Of note is that some processes lose their parent and thus point to an invalid id. However since Windows may reuse this parent id it seems that a child process could point to something that really isn't its parent.
This pitfall can be worked around by looking at the creation timestamp of the process and the supposed parent process. If the parent was created later than the child then it isn't the real parent. The process has no parent at that point. It is an orphan.
One example tool I found written in C++ is at http://www.scheibli.com/projects/getpids/index.html that demonstrates how to look for all processes and the parents.
I've only tested on Windows XP and Vista so I'm not sure earlier versions of Windows may work. It's better than nothing though.
Submitted On 27-FEB-2009
Rodney_Beede
My above post would not require using the Jobs api.
PLEASE NOTE: JDK6 is formerly known as Project Mustang
|