Reputation: 850
I'm currently building an application in JAVA where there can be only one execution. So I'm currently using a lock file in which I write the PID of the current execution.
So whenever this application will start, it will open the file (if it exists) and try to detect if the PID written in the file is actually running.
This prevent the problem where my app crash before unlocking the file.
I need this to work both on windows (XP,7 or 8) and linux (all the users are on debian based distros).
Here's some code to give you a better picture of what I want to do :
//get the PID from the file
int pidValue = new FileReader(file).read();
//get the OS type
String os = System.getProperty("os.name").toLowerCase();
//Check PID depending of OS type
if( os.contains("nux") || os.contains("nix") ){
/*
* Check PID on Linux/Unix
*/
} else if ( os.contains("win") ) {
/*
* Check PID on Windows
*/
}
I have tried to find documentation on the subject, but I didn't manage to find anything useful yet.
Thank you very much.
Upvotes: 6
Views: 11562
Reputation: 7045
This is platform-independent.
ProcessHandle.of(pid).orElseThrow(() -> new
IllegalArgumentException("Given pid is not found"))
.onExit();
This will
-throw an IllegalArgumentException
if the pid is not running, so you are safe to start this new Java Application instance
-return a Future<ProcessHandle>
so that you can wait until it finished with future.get()
or just check with future.isDone()
to log something or just System.exit(1)
Upvotes: 1
Reputation: 19
i know it has been a long time since the question has been asked but i struggled a bit to check if a specific pid is alive or not using java so here is my solution:
private boolean isServiceRunnign(String servicePid) throws IOException {
try {
System.out.println("-- checking for services --");
System.out.println("--" + System.currentTimeMillis() + "--");
Process p = Runtime.getRuntime().exec("ps -p " + servicePid);
System.out.println("Command : "+ "ps -p " + servicePid);
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String s = "";
while ((s = br.readLine()) != null) {
System.out.println("Bash outputs : " + s);
}
br.close();
p.waitFor();
// printing out exitValue for debug purposes.
System.out.println("Exit: " + p.exitValue());
if (p.exitValue() == 0) {
System.out.println("-- " + servicePid + " found --");
return true;
}
p.destroy();
System.out.println("-- " + servicePid + " not found --");
return false;
} catch (Exception e) {
System.out.println("-- " + servicePid + " not found --");
System.out.println("Exception : " + e.toString());
return false;
}
}
*note that this will only work on linux.
it basically runs the:
ps -p <pid>
command and checks the exit value.
Upvotes: 0
Reputation: 569
Please see below ready to copy/paste example.
Boolean method isStillAllive(...) will get as a parameter the process id number(pid). Method call is quite generic and is meant to wrap device dependent logic to solve same problem on windows/linux/unix like operating systems.
public boolean isStillAllive(String pidStr) {
String OS = System.getProperty("os.name").toLowerCase();
String command = null;
if (OS.indexOf("win") >= 0) {
log.debug("Check alive Windows mode. Pid: [{}]", pidStr);
command = "cmd /c tasklist /FI \"PID eq " + pidStr + "\"";
} else if (OS.indexOf("nix") >= 0 || OS.indexOf("nux") >= 0) {
log.debug("Check alive Linux/Unix mode. Pid: [{}]", pidStr);
command = "ps -p " + pidStr;
} else {
log.warn("Unsuported OS: Check alive for Pid: [{}] return false", pidStr);
return false;
}
return isProcessIdRunning(pidStr, command); // call generic implementation
}
Actual call to system is delegated to isProcessIdRunning(). This method will invoke preformed system dependent command in generic way and result obtained from system is consumed and parsed line by line. If at least one of response lines contains pid than we interpret this as success.
private boolean isProcessIdRunning(String pid, String command) {
log.debug("Command [{}]",command );
try {
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec(command);
InputStreamReader isReader = new InputStreamReader(pr.getInputStream());
BufferedReader bReader = new BufferedReader(isReader);
String strLine = null;
while ((strLine= bReader.readLine()) != null) {
if (strLine.contains(" " + pid + " ")) {
return true;
}
}
return false;
} catch (Exception ex) {
log.warn("Got exception using system command [{}].", command, ex);
return true;
}
}
Upvotes: 3
Reputation: 1598
The following code determines if a process with the specified pid is running. It was tested on Windows 7 and Ubuntu 13. On Windows it uses apache commons-exec to run tasklist and determines if they found the specified pid based on their exit code. It overcomes the fact that tasklist always returns 0 by piping the result to findstr. On linux it uses ps to do the same thing. It also suppresses stdout logging of the child process.
public static boolean isProcessRunning(int pid, int timeout, TimeUnit timeunit) throws java.io.IOException {
String line;
if (OS.isFamilyWindows()) {
//tasklist exit code is always 0. Parse output
//findstr exit code 0 if found pid, 1 if it doesn't
line = "cmd /c \"tasklist /FI \"PID eq " + pid + "\" | findstr " + pid + "\"";
}
else {
//ps exit code 0 if process exists, 1 if it doesn't
line = "ps -p " + pid;
//`-p` is POSIX/BSD-compliant, `--pid` isn't<ref>https://github.com/apache/storm/pull/296#discussion_r20535744</ref>
}
CommandLine cmdLine = CommandLine.parse(line);
DefaultExecutor executor = new DefaultExecutor();
// disable logging of stdout/strderr
executor.setStreamHandler(new PumpStreamHandler(null, null, null));
// disable exception for valid exit values
executor.setExitValues(new int[]{0, 1});
// set timer for zombie process
ExecuteWatchdog timeoutWatchdog = new ExecuteWatchdog(timeunit.toMillis(timeout));
executor.setWatchdog(timeoutWatchdog);
int exitValue = executor.execute(cmdLine);
// 0 is the default exit code which means the process exists
return exitValue == 0;
}
Upvotes: 4
Reputation: 27552
On posix systems the typical way to query if a pid is running is to send it a null signal e.g. kill(pid, 0)
. If the call succeeds the process exists; if it returns ESRCH
it does not. This is naturally subject to unavoidable race conditions which amount to much less in reality than they do in theory. Less uniform ways are to read the /proc file system (if the OS has one) which is more work, amounts to the same thing, and is still subject to the same race conditions.
Note that pid lockfile technique can be two-tiered. That is, the running process creates the file, locks it, and writes its pid. It holds the lock for the duration of its run and thus this pretty much does away with the above need to query whether the process is running because if the process crashes the file lock will be automatically released even though the file still exists. The logic goes like this:
if file exists
if can get lock
prev instance died unnaturally
continue with this new process
else
instance already running
else
good to go, continue with new process
This technique also has race conditions.
I don't remember enough Java to say whether it has wrappers for kill
or file locking syscalls like flock
, lockf
and fcntl
required to implement this scheme.
Upvotes: 3