blob: 3143163f8974fa19a6875a2863939c42921e25e7 [file] [log] [blame]
/*=========================================================================
* Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
* This product is protected by U.S. and international copyright
* and intellectual property laws. Pivotal products are covered by
* one or more patents listed at http://www.pivotal.io/patents.
*=========================================================================
*/
package com.gemstone.gemfire.internal.process;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import com.gemstone.gemfire.internal.util.IOUtils;
/**
* Utility operations for processes such as identifying the process id (pid).
*
* @author Kirk Lund
* @since 7.0
*/
public final class ProcessUtils {
private static InternalProcessUtils internal = initializeInternalProcessUtils();
private ProcessUtils() {}
/**
* Returns the pid for this process.
*
* @throws PidUnavailableException if parsing the pid from the name of the
* RuntimeMXBean fails
*
* @see java.lang.management.RuntimeMXBean#getName()
*/
public static int identifyPid() throws PidUnavailableException {
return identifyPid(ManagementFactory.getRuntimeMXBean().getName());
}
/**
* Returns the pid for this process using the specified name from
* RuntimeMXBean.
*
* @throws PidUnavailableException if parsing the pid from the RuntimeMXBean
* name fails
*/
public static int identifyPid(final String name) throws PidUnavailableException {
try {
final int index = name.indexOf("@");
if (index < 0) {
throw new PidUnavailableException("Unable to parse pid from " + name);
}
return Integer.valueOf(name.substring(0, index));
} catch (NumberFormatException e) {
throw new PidUnavailableException("Unable to parse pid from " + name, e);
}
}
/**
* Returns true if a process identified by the process id is
* currently running on this host machine.
*
* @param pid process id to check for
* @return true if the pid matches a currently running process
*/
public static boolean isProcessAlive(final int pid) {
return internal.isProcessAlive(pid);
}
/**
* Returns true if a process identified by the specified Process is
* currently running on this host machine.
*
* @param process the Process to check
* @return true if the Process is a currently running process
*/
public static boolean isProcessAlive(final Process process) {
try {
process.exitValue();
return false;
} catch (IllegalThreadStateException e) {
return true;
}
}
/**
* Returns true if a process identified by the process id was
* running on this host machine and has been terminated by this operation.
*
* @param pid process id
* @return true if the process was terminated by this operation
*/
public static boolean killProcess(final int pid) {
return internal.killProcess(pid);
}
public static int readPid(final File pidFile) throws IOException {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(pidFile));
return Integer.parseInt(reader.readLine());
}
finally {
IOUtils.close(reader);
}
}
/**
* Returns true if a fully functional implementation is available. If the
* Attach API or JNA NativeCalls are available then this returns true.
*/
public static boolean isAvailable() {
return internal.isAvailable();
}
private static InternalProcessUtils initializeInternalProcessUtils() {
// 1) prefer Attach because it filters out non-JVM processes
try {
Class.forName("com.sun.tools.attach.VirtualMachine");
Class.forName("com.sun.tools.attach.VirtualMachineDescriptor");
return new AttachProcessUtils();
} catch (ClassNotFoundException e) {
// fall through
} catch (LinkageError e) {
// fall through
}
// 2) try NativeCalls but make sure it doesn't throw UnsupportedOperationException
try {
// TODO: get rid of Class.forName usage if NativeCalls always safely loads
Class.forName("com.gemstone.gemfire.internal.shared.NativeCalls");
NativeProcessUtils inst = new NativeProcessUtils();
boolean result = inst.isProcessAlive(identifyPid());
if (result) {
return inst;
}
} catch (ClassNotFoundException e) {
// fall through
} catch (LinkageError e) {
// fall through
} catch (PidUnavailableException e) {
// fall through TODO:KIRK log warning??
} catch (UnsupportedOperationException e) {
// fall through
}
// 3) TODO: log warning and then proceed with no-op
return new InternalProcessUtils() {
@Override
public boolean isProcessAlive(int pid) {
return false;
}
@Override
public boolean killProcess(int pid) {
return false;
}
@Override
public boolean isAvailable() {
return false;
}
};
}
/**
* Defines the SPI for ProcessUtils
*/
interface InternalProcessUtils {
public boolean isProcessAlive(int pid);
public boolean killProcess(int pid);
public boolean isAvailable();
}
}