/**
* Copyright (C) 2008 Progress Software, Inc. All rights reserved.
* http://fusesource.com
*
* The software in this package is published under the terms of the AGPL license
* a copy of which has been included with this distribution in the license.txt file.
*/
package org.fusesource.cloudmix.agent;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import org.fusesource.cloudmix.agent.unix.Posix;
import org.fusesource.cloudmix.agent.win32.Kernel32;
public final class PidUtils {
private static final String[] UNIX_COMMAND = {
"sh", "-c", "echo $PPID"
};
private static final int PID = getPidInternal();
private PidUtils() { /* static utility class */
}
public static int getPid() {
return PID;
}
/**
* @param pid
* @return true if the provided pid is running.
* @throws IOException
*/
public static boolean isPidRunning(int pid) throws IOException {
Kernel32 kernel32 = Kernel32.Factory.get();
if (kernel32 != null) {
Pointer process = kernel32.OpenProcess(Kernel32.SYNCHRONIZE, 0, pid);
if (process != null) {
int x = kernel32.WaitForSingleObject(process, 0);
return x != Kernel32.WAIT_OBJECT_0;
}
return false;
}
Posix posix = Posix.Factory.get();
if (posix != null) {
return posix.kill(pid, 0) == 0;
}
throw new UnsupportedOperationException("isPidRunning is not yet supported"
+ " on this operating system.");
}
/**
* Kills a running PID. If your on a Unix system, it kills it with the given signal, but if your on
* Windows, you terminate the process with the provided exitCode.
*
* @param pid
* @param signal
* @param exitCode
* @throws IOException
*/
public static void killPid(int pid, int signal, int exitCode) throws IOException {
Kernel32 kernel32 = Kernel32.Factory.get();
if (kernel32 != null) {
Pointer process = kernel32.OpenProcess(Kernel32.PROCESS_TERMINATE, 0, pid);
if (process == null) {
throw new IOException("Could not open process pid " + pid + ": "
+ Kernel32.Factory.getLastErrorAsString());
}
try {
if (kernel32.TerminateProcess(process, exitCode) == 0) {
throw new IOException("Could not terminate process pid " + pid + ": "
+ Kernel32.Factory.getLastErrorAsString());
}
return;
} finally {
kernel32.CloseHandle(process);
}
}
Posix posix = Posix.Factory.get();
if (posix != null) {
if (posix.kill(pid, signal) != 0) {
throw new IOException("Could not kill process pid " + pid + ": "
+ posix.strerror(Native.getLastError()));
}
return;
}
throw new UnsupportedOperationException("killPid is not yet supported on this operating system.");
}
private static int getPidInternal() {
// Try to do a native system call call...
Kernel32 kernel32 = Kernel32.Factory.get();
if (kernel32 != null) {
return kernel32.GetCurrentProcessId();
}
// Try to do a native system call call...
Posix posix = Posix.Factory.get();
if (posix != null) {
return posix.getpid();
}
// Fall back to some JVM hacks..
int id = getMXBeanPid();
if (id != -1) {
return id;
}
// Fall back to using some shell hacks..
// on other platforms, try this
return getPidFromShell();
}
private static int getMXBeanPid() {
try {
String name = ManagementFactory.getRuntimeMXBean().getName().trim();
Pattern pattern = Pattern.compile("^(\\d*).*");
Matcher matcher = pattern.matcher(name);
if (matcher.matches()) {
name = matcher.group(1);
return Integer.parseInt(name);
} else {
return -1;
}
} catch (Throwable th) {
return -1;
}
}
private static int getPidFromShell() {
try {
Process p = Runtime.getRuntime().exec(UNIX_COMMAND);
byte[] bytes = new byte[100];
p.getInputStream().read(bytes);
int value = Integer.parseInt(new String(bytes));
if (value == 0) {
value = -1;
}
return value;
} catch (Throwable th) {
return -1;
}
}
}