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

I have been experimenting with Process and ProcessBuilder and come with this SSCCE.
import java.io.IOException;
public class TestProcess {
public static void main(String[] args) {
Process process = null;
ProcessBuilder pb = new ProcessBuilder("notepad.exe");
try {
process = pb.start();
} catch (IOException e) {e.printStackTrace();}
//have some time to close notepad
try {
Thread.sleep(10*1000);
} catch (InterruptedException ignored) {}
try {
System.out.println(process.exitValue());
} catch (IllegalThreadStateException e) {
System.out.println(e);
}
if (process != null)
process.destroy();
/*try {
Thread.sleep(0, 1);
} catch (InterruptedException ignored) {}*/
System.out.println(process.exitValue());
}
}
If I run this code and close notepad before 10s timeout. destroy() call does not show any problem on attempt to stop already terminated process. Why?
If run this code and don't close notepad at all (with commented second sleep)
It seems that destroy is asynchronous call (just sending a signal?) which results in exception in second exitValue()
java.lang.IllegalThreadStateException: process has not exited
Exception in thread "main" java.lang.IllegalThreadStateException: process has not exited
at java.lang.ProcessImpl.exitValue(ProcessImpl.java:246)
at TestProcess.main(TestProcess.java:30)
If I run this code and don't close notepad at all (with uncommented second sleep) then second exitValue never throws Exception, even though sleep value is just 1ms. Is it because of sleep() overhead itself?
Second exitValue would return 1.
PS. I run it from Windows 7 and Eclipse.

ProcessImpl.java on destroy method call native function terminateProcess:
public void destroy() { terminateProcess(handle); }
private static native void terminateProcess(long handle);
terminateProcess is platform dependent and for Windows you can find sources here. It's just call Windows TerminateProcess function (link to this function was in previously answer or you can google it) with uExitCode=1 - thats why exit code of destroyed process is 1.
In linux looks like is used something similar to this. And as proof next code return 143 in ubuntu, that correspond to SIGTERM (https://stackoverflow.com/a/4192488/3181901):
public static void main(final String[] args) throws IOException, InterruptedException {
final Process process = Runtime.getRuntime().exec(args[0]);
process.destroy();
Thread.sleep(1000);
System.out.println(process.exitValue());
}

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.
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.
Possible, indeed, that it's because it takes time to invoke Thread.sleep(). Try increasing the timeout value.

I'm expecting that the destroy() method is calling the native windows function TerminateProcess.
Looking at MSDN, I found this:
TerminateProcess is asynchronous; it initiates termination and returns immediately. If you need to be sure the process has terminated, call the WaitForSingleObject function with a handle to the process.
So I think it explain that destroy is indeed asynchronous.
Another extract from the same source:
The TerminateProcess function is used to unconditionally cause a process to exit.
I guess that "unconditionnally" can explain why the call of destroy() on a terminate process don't fail.
Hope this help. (really interesting question !)

Related

Detect Ctrl+C in Java Console

I have a Console-Java game. The score from the game will be saved in a JSON file if Ctrl+C is pressed. The process to save the score in a JSON file works. But I don't know, how to detect Ctrl+C from the console and if this happens, I will save the score (just a method call).
With KeyListener it doesn't work on the console (only with JFrame as far as I know).
I couldn't find a solution to my problem on the internet.
Do I have to do it with Runtime? I have tried it, but it didn't work...
Runtime.getRuntime().addShutdownHook(new Thread()
{
public void run()
{
Test.mainThread.interrupt();
}
});
There are similar questions on Stackoverflow, but not for use on the console Catching Ctrl+C in Java
Adding a shutdown hook is the right way to do it, but Test.mainThread.interrupt(); probably will not work. The JVM is already shutting down. Your mainThread is unlikely to have time to respond to an interrupt; once all shutdown hooks finish, Java terminates.
Just have your shutdown hook explicitly perform whatever actions you need taken:
Runtime.getRuntime().addShutdownHook(new Thread()
{
#Override
public void run()
{
try
{
Test.saveScore();
}
catch (IOException e)
{
System.err.println("Couldn't save score before terminating.");
e.printStackTrace();
}
}
});
We know that CTRL-C closes the application and shuts down the JVM. And since it is a normal shutdown, it runs the shutdown hooks. So creating a shutdown hook is a correct approach:
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
// Do something to save the score
}));
Note that we're passing a Runnable here as the shutdown task. So we can pass an object that has the required functionality:
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
gameScores.save(); // assuming we have a gameScores object in this scope
}));
Your initial attempt by interrupting the thread can be viewed as a variant of this approach. Instead of passing the business object - gameScores - we can pass the thread to interrupt it later. But it's better to operate on the business level.

How to detect an external process crash in Java?

I am working on an application that needs to launch a process and wait for its output. Sometimes the process crashes (very often,) but is not really an issue since I have mitigation tasks. The problem is that Windows detects the process crashed and prompts for user input, to either check for a solution online, or just close the program.
I tried to solve this by waiting for the process to complete in a Runnable submitted to an ExecutorService and using the Future returned to specify a timeout. Speed is not really a concern for the application, and the external process is supposed to run for just a couple of seconds.
This is the code I am using:
final Process process = ...
final ExecutorService service = Executors.newSingleThreadExecutor();
try {
final Future<?> future = service.submit(new Runnable() {
#Override
public void run() {
try {
process.waitFor();
} catch (InterruptedException e) { /* error handling */}
}
});
future.get(10, TimeUnit.SECONDS);
} catch (final TimeoutException e) {
// The process may have crashed
process.destroy();
} catch (final Exception e) {
// error handling
} finally {
service.shutdown();
}
The code above worked well, but the crash dialog still pops up and it doesn't go away without user interaction.
This question presents a similar problem but from a .Net perspective and
proposes to suppress the pop up through the Windows registry, which I cannot do, given that its effect is global to all process in the machine.
Is there a way to prevent the dialog from being displayed at all?
or
Is there a way to detect the application crash and handle it directly
from Java without needing user interaction?
Additional details:
I don't have the source of the external process.
The external process is a console based application (i.e. no GUI.)
Preferably I'm looking for a pure Java based solution (no JNI.)
Thank you.
As already suggested you should use SetErrorMode win32 call. It won't change for the whole system but only for your process and it's children (which is what you want apparently).
The correct call seems to be :
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
See also the MSDN documentation :
http://msdn.microsoft.com/en-us/library/windows/desktop/ms680621%28v=vs.85%29.aspx
Regards.

Force JVM to finish code block before terminate

I have the following code:
public class LogWriter implements Runnable {
private static BlockingQueue<LogRecord> logQueue;
static {
logQueue = new ArrayBlockingQueue<LogRecord>(30);
}
#Override
public void run() {
Integer errorNo = 0;
configureLogger();
while (true) {
try {
LogRecord record = logQueue.take();
consumeLogRecord(record);
System.out.println(++errorNo + " - Logged error in file '" + LoggerConfig.LOG_PATH + "'");
record = null;
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}
}
}
This is part of a logger for a LibreOffice pluggin written in Java. When LibreOffice is closing, it simply kills it's plugins (as I can tell so far, not sure of it), but not before sending a signal to them that it is closing, which I can detect in my code (through the UNO API). After I receive the termination signal from LibreOffice, I want to flush my LogRecord queue to the log file and change that while(true) to false so the method run() can finish appropriately, releasing the resources it have. So my question is, how can I tell the JVM that waiting for this operation is of high priority and it shouldn't terminate before finishing it?
The advice about shutdown hooks must be taken with a large grain of salt. The shutdown hook is a last resort device where you can try to salvage what you couldn't possibly by any other means. You can't rely on any normal assumption, such as that System.out is still open, that your log file is still open, that even the filesystem is available, and so on.
A use case for a shutdown hook is to try to gracefully close acquired resources, with no attempt at further data transfer.
The approach you should take is:
inform yourself exactly what terms LibreOffice gives you: do you have a certain timeout within which to complete your work?
minimize the work pending at any point in time, thereby maximizing your chance to have it completed within the timeout.
You can use.
Runtime.getRuntime().addShutdownHook(Thread);
Shutdown hooks will be the best option to go.

Order a Runtime exec and a ProcessBuilder.start?

I've been confronted to a weird problem while running and killing processes through java.
Basically, I have a method which kills one process using taskkill :
private static void kill() {
try {
Runtime.getRuntime().exec("taskkill /F /IM app.exe");
} catch (IOException e) {
e.printStackTrace();
}
}
I call this method to be sure all the processes are killed before I start a new one :
kill();
ProcessBuilder procBuilder = new ProcessBuilder(args);
try {
Process p = procBuilder.start();
} catch (Exception e) {
e.printStackTrace();
}
The problem is the process started seems to be killed by the taskkil. Without the call to kill, it works perfectly fine; while with the kill, the process starts but the GUI doesn't appear.
Is this a problem of priority between the two calls ? (a runtime.exec would be of lower priority than a ProcessBuilder.start ?).
I've solved that using a waitFor on the return of the Runtime exec but I'm curious about why this problem appeared.
Basically the Runtime.exec starts a new process in the OS asynchronously, and there is no guarantee that it is finished before your new process is started. Theoretically you sould wait for the taskkill to return with a SUCCESS result and start your new job only after that. According to its documentation taskkill will tell you with 0 return code if it has successfully killed its suspect.
The issue is not priority related, since both of them will have the default priority. A possible issue is that Runtime.exec using a String will have to parse the input and then execute the command, while ProcessBuild will execute the given command without the needed parsing logic. Because of this you can see a small delay and you need the waitFor to work as intended. You can eliminate this delay by using the String[] version of the Runtime.exec.
Also note that the threads are scheduled by the system scheduler and the execution order is unpredictable, see Java thread unpredictable.

Terminate process run with `exec` when program terminates

I have a java program that runs another (Python) program as a process.
Process p = Runtime.getRuntime().exec("program.py", envp);
If the java program finish processing, the Python process is finished as well. The finish command sends a signal to the Python process to close it.
In normal situation the process is closed this way:
BufferedWriter output = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
output.write("#EOF\n");
output.flush();
However, when the java program crashes, the process is not closed. The closing command is not send due to the crash. Is it possible to terminate the process automatically every time the program is terminated?
hey #czuk would a ShutdownHook hook be any use? This will deal with the following scenarios
The Java virtual machine shuts down in response to two kinds of events:
The program exits normally, when the last non-daemon thread exits or when the exit (equivalently, System.exit) method is invoked, or
The virtual machine is terminated in response to a user interrupt, such as typing ^C, or a system-wide event, such as user logoff or system shutdown.
When the system unexpectedly crashes this is not so easy to capture.
Perhaps use the Thread.setDefaultUncaughtExceptionHandler method?
Assuming that by crashing you mean that the Java program throws an exception, I would just kill the Python process when that happens. I haven't seen your code but:
class Foo {
Process p;
private void doStuff() throws Exception {
p = Runtime.getRuntime().exec("program.py", envp);
// More code ...
}
private void startStuff() {
try {
doStuff();
} catch (Exception e) {
p.destroy();
}
}
public static void main(String[] args) {
Foo foo = new Foo();
foo.startStuff();
}
}
Something like this should work if only exceptions that cause the program to crash escapes from doStuff().
Even if you don't expect the program to crash in this way when it is finished I think this approach is better than perhaps wrapping it in a shell script that in some way kill the Python process. Handling it in your program is less complex and it might even be a good idea to keep the code once the program is finished, since you might still have bugs that you don't know about.

Categories