Java - Process.Destroy() Source Code for Linux

Java - Process.destroy() source code for Linux

Process management and all the like operations are done by the OS. Therefore, the JVM has to call the appropriate system call in order to destroy a process. This will, obviously, vary between operating systems.

On Linux, we have the kill syscall to do that - or exit if we want to terminate the currently running process. The native methods in the JDK sources are, of course, separated according to the operating system the JVM is going to run on. As noted previously, Process has a public void destroy() method. In the case of Linux, this method is implemented by UNIXProcess. The destroy() method is implemented pretty much like this:

private static native void destroyProcess(int pid);
public void destroy() {
destroyProcess(pid);
}

The native method destroyProcess(), in turn, is defined in UNIXProcess_md.c and looks like this:

JNIEXPORT void JNICALL
Java_java_lang_UNIXProcess_destroyProcess(JNIEnv *env, jobject junk, jint pid)
{
kill(pid, SIGTERM);
}

Where kill is the Linux syscall, whose source is available in the Linux kernel, more precisely in the file kernel/signal.c. It is declared as SYSCALL_DEFINE2(kill, pid_t, pid, int, sig).

Happy reading! :)

Killing a process using Java

If you start the process from with in your Java application (ex. by calling Runtime.exec() or ProcessBuilder.start()) then you have a valid Process reference to it, and you can invoke the destroy() method in Process class to kill that particular process.

But be aware that if the process that you invoke creates new sub-processes, those may not be terminated (see https://bugs.openjdk.org/browse/JDK-4770092).

On the other hand, if you want to kill external processes (which you did not spawn from your Java app), then one thing you can do is to call O/S utilities which allow you to do that. For example, you can try a Runtime.exec() on kill command under Unix / Linux and check for return values to ensure that the application was killed or not (0 means success, -1 means error). But that of course will make your application platform dependent.

how can I kill a Linux process in java with SIGKILL Process.destroy() does SIGTERM

Not using pure Java.

Your simplest alternative is to use Runtime.exec() to run a kill -9 <pid> command as an external process.

Unfortunately, it is not that simple to get hold of the PID. You will either need to use reflection black-magic to access the private int pid field, or mess around with the output from the ps command.

UPDATE - actually, there is another way. Create a little utility (C program, shell script, whatever) that will run the real external application. Code the utility so that it remembers the PID of the child process, and sets up a signal handler for SIGTERM that will SIGKILL the child process.

The right way to kill a process in Java

If the process you want to kill has been started by your application

Then you probably have a reference to it (ProcessBuilder.start() or Runtime.exec() both return a reference). In this case, you can simply call p.destroy(). I think this is the cleanest way (but be careful: sub-processes started by p may stay alive, check Process.destroy does not kill multiple child processes for more info).

The destroyForcibly should only be used if destroy() failed after a certain timeout. In a nutshell

  1. terminate process with destroy()
  2. allow process to exit gracefully with reasonable timeout
  3. kill it with destroyForcibly() if process is still alive


If the process you want to kill is external

Then you don't have much choice: you need to pass through the OS API (Runtime.exec). On Windows, the program to call will be taskkill.exe, while on Mac and Linux you can try kill.


Have a look at Support for Process.destroyForcibly() and .isAlive() from Java 8 and Killing a process using Java and Code a Simple Java App to Kill Any Process After a Specified Time for more info.

Killing a Java Process object

The solution in my case, since I was writing both the parent and the child processes, was to add a ShutdownHook which halted the JVM (a simple System.exit(1) was not sufficient):

Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
Runtime.getRuntime().halt(5);
}
});

After this, when a SIGTERM was received the process would terminate, as though it had been sent SIGKILL by the parent process.

Java tool/method to force-kill a child process

There is a leaner way to do this using Java JNA.

This works definitely for Windows and Linux, i assume that you can do the same for other platforms too.

The biggest problem of Java process handling is the lack of a method to get the process id of the process started with untime.getRuntime().exec().

Assuming you got the pid of a process, you always can start a kill -9 command in linux, or use similar ways to kill a process in windows.

Here is a way to get the process id natively for linux (borrowed from the selenium framework, :) ), and with the help of JNA this also can be done for windows (using native Windows API calls).

For this to work (for Windows) you first have to get the JNA Library at JAVA NATIVE ACCESS (JNA): Downloads or get it from maven

Look at the following code, which will get the pid of a (in this example windows) program (most of the code is actually debris to get a working java program going):

import com.sun.jna.*;
import java.lang.reflect.Field;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Main {

static interface Kernel32 extends Library {

public static Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);

public int GetProcessId(Long hProcess);
}

public static void main(String[] args) {
try {
Process p;

if (Platform.isWindows())
p = Runtime.getRuntime().exec("cmd /C ping msn.de");
else if (Platform.isLinux())
p = Runtime.getRuntime().exec("cmd /C ping msn.de");

System.out.println("The PID: " + getPid(p));

int x = p.waitFor();
System.out.println("Exit with exitcode: " + x);

} catch (Exception ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}

public static int getPid(Process p) {
Field f;

if (Platform.isWindows()) {
try {
f = p.getClass().getDeclaredField("handle");
f.setAccessible(true);
int pid = Kernel32.INSTANCE.GetProcessId((Long) f.get(p));
return pid;
} catch (Exception ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
} else if (Platform.isLinux()) {
try {
f = p.getClass().getDeclaredField("pid");
f.setAccessible(true);
int pid = (Integer) f.get(p);
return pid;
} catch (Exception ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
else{}
return 0;
}
}

Hope this helps, ;)...

Process.exitValue() and Process.destroy() features

  1. Why would it show a problem? You're trying to destroy a process that was already destroyed. The specification of Process.destroy() doesn't say what happens if there was nothing to destroy, so it is logical (I suppose) to assume that if there's nothing to destroy, then there's nothing to complain about. Compare with Thread.join(), which doesn't just die if the thread has already ended.

  2. The only way to kill a process is to send it a signal. On some OS's, there are other, more "violent" ways (on some platforms, for example, it is possible to simply remove the process from the OS's list of running processes. Results are undefined and it usually ends ugly), but at least with platforms that I know of, it's really all about sending signals.

  3. Possible, indeed, that it's because it takes time to invoke Thread.sleep(). Try increasing the timeout value.

Java - Object runs an external process: how to stop it?

This:

new ProcessBuilder(command).start();

returns a Process object, and if you hold a reference to it, you can call Process.destroy() at a later time (this SO answer details the destroy() implementation)



Related Topics



Leave a reply



Submit