Solved

Killing a java.lang.Process and its children

Posted on 2004-03-22
18
4,155 Views
Last Modified: 2007-12-19
This is a general question about java.lang.Process and the semantics of java.lang.Process.destroy( ) - particularly under *nix (Solaris + Linux). Windows-related knowledge is also welcome but I am primarily concerned about the signals sent to the process when destroy( ) is called.

I have done a relatively quick google on the matter but could not find what the signal sent to the process is -- so I assume it's SIGTERM (and not SIGKILL). Is there a way to specify a signal that I want, or is this not in the standard Java distribution because this is platform-dependent? Anyone who could point answer this and point me to an "official" resource where this is described stands a good chance of getting the points :-)

However, for complete glory, I would also like to know how to kill (i.e. the equivalent of "kill -9" -- sending SIGKILL) a process spawned from a Java program _and_ all of its children. I am not sure whether sending SIGKILL also ensures that all the child processes will die too. I would like to avoid having to shell out to a script that would ps or pstree the situation, perform some awking and then kill -9 the children. Is there a way to kill the children, do I need to do it or does this happen automatically?

Cheers.
0
Comment
Question by:tikiliainen
  • 10
  • 5
  • 3
18 Comments
 
LVL 30

Expert Comment

by:mayankeagle
ID: 10648003
As far as I know, what Process.destroy() actually does is highly dependant on the OS, the VM and its implementation of the abstract 'Process' class returned from Runtime.exec ().
0
 
LVL 30

Expert Comment

by:mayankeagle
ID: 10648068
>> so I assume it's SIGTERM

I guess that's correct.

>> there a way to specify a signal that I want, or is this not in the standard Java distribution because this is platform-dependent?

You might not be able to specify the signal. The VM's implementation will decide what command to send, depending upon the platform you're working on, because every platform will have its own signals and the VM (which will be for the specific platform) will make use of them.

Perhaps this is also why the destroy () method in the Process class is abstract. Based on the process you invoke from Runtime.exec (), an appropriate instance is made by the VM (depending on the OS) and returned.

0
 
LVL 30

Expert Comment

by:mayankeagle
ID: 10648083
Calling process.destroy () however, might not kill all child processes. Maybe that if you do a Ctrl-C, it will kill the process and all sub-processes, but I don't know how to simulate that in the program. Will try to look for something on killing sub-processes as well.
0
 
LVL 30

Expert Comment

by:mayankeagle
ID: 10648088
As an alternative, perhaps you could use waitFor () and make every process wait till its sub-processes end?
0
 
LVL 30

Expert Comment

by:mayankeagle
ID: 10648097
Irrespective of what platform you are on, I guess there is no standard API to extract the native OS process identifier to implement your own clean-up.

Examing the implementation of Runtime.exec()/Process shows that all of the important functions are in native methods, for which the source is not provided so it's difficult to work out what the implementations actually do, or attempt to do.

If the child processes are not dying, then it might be necessary to implement your own (native) Runtime.exec()/ Process replacement to perform the relevant process killing.
0
 

Author Comment

by:tikiliainen
ID: 10648103
Pressing Ctrl-C is equivalent to sending a SIGTERM. As far as waitFor() goes, I use it to wait for :-) the process I spawned to end -- I think waiting for the children to end is implicit, but I might be wrong. In fact, I do not think it is possible to actually get any reference to the children at all. I suppose the question really is "does the SIG(TERM|KILL) get sent to all the children too?"
0
 
LVL 30

Expert Comment

by:mayankeagle
ID: 10648128
>> I suppose the question really is "does the SIG(TERM|KILL) get sent to all the children too?"

Perhaps not, if your children processes are not getting killed. It might depend on the platform as well. Maybe that in some cases, it does get sent to the child processes as well. But if it does not, then you might have to put your own native implementation for Runtime.exec ()/ Process, depending on the platform.
0
 
LVL 2

Expert Comment

by:timbauer
ID: 10659156
I am fairly certain it is a SIGKILL.

This may be a job for JNI. I battled this type of problem for awhile.
The semantics are highly OS dependent.

One idea to test this is to write a program (not necessarly Java) that installs a handler to catch SIGTERM and print a message in that handler and exit. Spawn the process, call destroy() on the Process object, and view the signal output.
If you see your message from the handler, you know SIGTERM was called.
If you do not see your message from the SIGTERM handler, then SIGKILL was called.

If you want to be certain of the semantics of the child process here is a dirty trick.
The unix subclass java.lang.Process is "java.lang.UNIXProcess"
There is a private field called,
   private int pid;
Using native code or reflection you can circumvent the "private" access modifier.
and fetch the pid field. Once you have the pid you could call into JNI and use the kill() system call, sending a signal of your choice to that process.

Now, what I just suggested is a very naughty and unclean solution. I acknowledge that and
hope I don't hurt anyone's feelings with it. The code is VERY unportable and unstable since it depends on information that it shouldn't (a private field on a hidden class). It might not even work on Java 1.5 and certainly only works on Linux/Unix machines.

Happy hacking,
- Tim
0
 

Author Comment

by:tikiliainen
ID: 10659441
Thanks Tim,

This is very close to what I needed to know. I am amused very much by the idea you suggest for getting the PID. I am however, unable to find any refernce to java.lang.UNIXProcess anywhere, apart from a very 1.1-like API page. I assume UNIXProcess was deprecated and removed.

How did you find the code for it?
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 30

Assisted Solution

by:mayankeagle
mayankeagle earned 40 total points
ID: 10664374
>> I assume UNIXProcess was deprecated and removed.

Correct. It is not there anymore.

>> I am amused very much by the idea you suggest for getting the PID

You can access private members through reflection. It is the cleanest way to do so. In fact, previously, there were also some illegal methods followed for that. A lot of people had posted questions for doing that in EE, and we have strictly told them not to do so. What they did was - they got Sun's sources, modified the sources to make the private field as public, then compiled their .java file into a .class file and replaced it in rt.jar. Then they compiled the program which accessed the private variable, and it compiled because the variable was declared as public in their file. Then they replaced the .class file back with the original one. Now, they were able to access the private members because the private-public accessibility check is done only at compile-time and not at run-time. However, I would call it illegal, which is why we discouraged it. But I guess because of this reason, some later versions of the JDK throw an IllegalAccessError while executing the program, if you attempt to access a private variable during runtime.

Try reflection. It would help. Have a look here:

http://www.javaalmanac.com/egs/java.lang.reflect/pkg.html
0
 
LVL 2

Accepted Solution

by:
timbauer earned 260 total points
ID: 10666590
>> I assume UNIXProcess was deprecated and removed
No, it is there as of:
java version "1.4.1_02"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_02-b06)
Java HotSpot(TM) Client VM (build 1.4.1_02-b06, mixed mode)

This is part of the problem though. That class is virtual machine dependent.
The java.lang.Process has abstract methods. When you call
<Runtime>.exec(...);
The native "exec" code finds the concrete implementation (java.lang.UnixProcess on
the linux box I tested this with) and returns it.
To you and I, we just see a "Process". The way I found out about it is by executing
the code.

Process p = Runtime.getRuntime().exec("ls");
System.out.println("The real class is: "+ p.getClass() ); //prints "java.lang.UNIXProcess"

Once you have the name of the real subclass call
javap -p java.lang.UNIXProcess
 ("-p" means include private fields).


The code to get the pid field would look something like.

Process child = ...
Field field = child.getClass().getField("pid");
field.setAccessible(true); //supress the private modifier.
int pid = field.getInt( child ); //fetch the "pid" field's value from "child"


Another danger is that we don't know when that field is actually set.
I see no logical reason why it should not be set in the constructor.

If you get the source code for the java classes (included when you install the VM on a Unix machine) it should have those additional classes.

If you are interested in java signal handler implementations etc.
Here is a good article from IBM that points out some secret
classes and such for internal singal handling.
http://www-106.ibm.com/developerworks/ibm/library/i-signalhandling/

Hope this helps. VM system'ish stuff is quite fun!
- Tim
0
 

Author Comment

by:tikiliainen
ID: 10666847
Thanks a lot, Tim. I am very puzzled though, why Unix process would not be documented *anywhere on the net*. It is not a public class (as javap shows), so I guess this explains why it's not in *any* of the standard Javadocs for recent JDKs.

My ultimate aim (as far as this question goes) is to be able to get to all the child processes of the one I spawn. I am guessing this is impossible without going through JNI, which I really do not want to do because that will give me a headache (2 languages + bindings, on 2 OS's).

One thing which is really strange is the following:

mtikilia@machine1[808]:~>javap java.lang.UNIXProcess
Compiled from UNIXProcess.java
class java.lang.UNIXProcess extends java.lang.Process {
    java.lang.UNIXProcess(java.lang.String[],java.lang.String[]) throws java.io.IOException;
    static java.io.FileDescriptor access$0(java.lang.UNIXProcess);
    static java.io.OutputStream access$1(java.lang.UNIXProcess);
    static int access$10(java.lang.UNIXProcess, int);
    static boolean access$11(java.lang.UNIXProcess);
    static void access$12(java.lang.UNIXProcess, boolean);
    static int access$13(java.lang.UNIXProcess);
    static void access$14(java.lang.UNIXProcess, int);
    static void access$2(java.lang.UNIXProcess, java.io.OutputStream);
    static java.io.FileDescriptor access$3(java.lang.UNIXProcess);
    static java.io.InputStream access$4(java.lang.UNIXProcess);
    static void access$5(java.lang.UNIXProcess, java.io.InputStream);
    static java.io.FileDescriptor access$6(java.lang.UNIXProcess);
    static java.io.InputStream access$7(java.lang.UNIXProcess);
    static void access$8(java.lang.UNIXProcess, java.io.InputStream);
    static int access$9(java.lang.UNIXProcess);
    public void destroy();
    public synchronized int exitValue();
    public java.io.InputStream getErrorStream();
    public java.io.InputStream getInputStream();
    public java.io.OutputStream getOutputStream();
    public synchronized int waitFor() throws java.lang.InterruptedException;
}
mtikilia@machine1[809]:~>which java
/usr/bin/java
mtikilia@machine1[810]:~>ls -l /usr/bin/java
lrwxrwxrwx   1 root     other         16 Oct 22  2002 /usr/bin/java -> ../java/bin/java
mtikilia@machine1[811]:~>jar -tf /usr/bin/../java/src.jar | grep Process
src/java/lang/Process.java
mtikilia@machine1[812]:~>

javap clearly shows that the class is compiled from a UNIXProcess.java, but it is nowhere to be found in the src.jar! Mystery! Do you know where it lives?
0
 
LVL 30

Expert Comment

by:mayankeagle
ID: 10666870
Even I didn't find it in the documentation, that's why I said that its probably been removed.

Since its a platform-specific class (does stuff only for the UNIX platform), perhaps its not there in the sources because they contain only the public classes used by all platforms. Also, I guess this one has been given friendly access (and not public) because its more used internally by the JVM and only in the classes of the same package.
0
 

Author Comment

by:tikiliainen
ID: 10666949
>perhaps its not there in the sources because they contain only the public
>classes used by all platforms.

Are you double sure this is true? A quick check seems to agree with you -- i.e. only platform independent classes are present in src.jar, but this clearly does not make sense, as you need the platform specific ones to compile the Java distribution on a specific platform.
0
 
LVL 30

Expert Comment

by:mayankeagle
ID: 10667044
>> Are you double sure this is true?

I'm not sure. That's why I said: 'perhaps'.

>> but this clearly does not make sense

Depends upon Sun. Maybe that they did not want to give you the sources for it. And it was easier to provide the same src.jar for all platforms.
0
 
LVL 2

Expert Comment

by:timbauer
ID: 10707911
The detective work I did to find it was not difficult, but vnot very good at answering our question.

You will see this pattern in Java alot. They give the interface as an abstract class
"java.lang.Process", then do all the implementation dependent stuff in a concrete
OS dependent sublcass.

You will see this pattern in java.awt.Graphics (subclass depends on the graphics environment) too and many other different classes. DirectByteBuffer has man different system dependent version.

A cleaner solution might be to write a simple platform specific class that gives you the functionality you need.
You could even extend Process (although I would not without a better reason).
Good luck,
- T
0
 
LVL 30

Expert Comment

by:mayankeagle
ID: 10711580
>> although I would not without a better reason

But perhaps it is the best way out ;-)
0
 

Author Comment

by:tikiliainen
ID: 10714179
I have also done a little detective work, however, in a different direction: if it is not possible to get to the children, how can we make sure the parent will kill them before dying (you know, Mohammed, mountain).

This also gave a precise answer to exactly what signal gets sent to the process by Process.destroy() on Solaris. The answer is SIGTERM.

I was trying to find out whether there was a way of passing the signal along to the chilren here: http://www.experts-exchange.com/Programming/Programming_Platforms/Unix_Programming/Q_20937086.html
and as you can see, the answer was similar to what was suggested in this thread: write a signal handler for SIGTERM and use that to kill the children.

So, just trying my luck, I wrote a similar script with a child process and a SIGTERM handler and ran it from Java. I then Process.destroy()'d it from Java and the handler fired! To double-check, I changed the signal trapped by the script from SIGTERM to SIGHUP and repeated. When the parent was killed from Java, the handler did not fire, thus confirming that the signal sent to the process by Process.destroy is definitely SIGTERM. This actually makes more sense than sending SIGKILL as the killed process is given a chance to clean up.

So, to draw a line under this: you cannot kill the children from Java without some horrible (and adventurous!) hacking and shelling out or native code calling. However, it is possible to get around this by using signal handlers at script-level (or program level).
0

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

Suggested Solutions

Java had always been an easily readable and understandable language.  Some relatively recent changes in the language seem to be changing this pretty fast, and anyone that had not seen any Java code for the last 5 years will possibly have issues unde…
Introduction This article is the second of three articles that explain why and how the Experts Exchange QA Team does test automation for our web site. This article covers the basic installation and configuration of the test automation tools used by…
This tutorial covers a step-by-step guide to install VisualVM launcher in eclipse.
This tutorial will introduce the viewer to VisualVM for the Java platform application. This video explains an example program and covers the Overview, Monitor, and Heap Dump tabs.

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now