Need to kill a Java program started by Runtime.getRuntime().exec() - java

In a Java program I am running another Java program using the following command:
Process p = Runtime.getRuntime().exec("echo.bat | java -Xms64M -Xmx1G -cp "+execFilePath+" "+inputFileName+" "+inputParam);
The invocation is working fine, but if due to bad coding the executed Java file (inputFileName) is hanging, say, due to some infinite loop, a new process which got started, is not ending. Now, I need to kill that process in my code.
I am able to detect if the Java program is hanging by using TimeOut. But, I don't know how to get the process id of this executed Java program and kill it once TimeOut happens.
Any help is appreciated!

Generally, you can call destroy on your Process instance. See here
I notice however that you are starting one process and pipe its output to another. The simple approach will most probabely only kill the former (your echo.bat process).
Therefore, you need a more complex scenario. Do the following:
Start a process calling echo.bat only
Wait until it is finished
Read all of its output through its output stream (Process.getOutputStream())
Start another process, calling the java program only.
Write the read data to its input (write to Process.getInputStream())
This second process instance will be your java process
As fge mentioned above, take a look at ProcessBuilder, as it simplyfies some of the steps. Especially setting up the input stream can be accomplished before actually starting the program

Related

java not waiting for unix binary to complete execution

Im creating a javafx application to run a unix binary application, which limits the percent of cpu a process can use, herein i already have a cputhrottle unix binary which receives PID and CPU percentage as argument, my application just acts as a GUI for this unix binary.
When I run this cputhrottle from terminal it keeps on running, until i press - CTRL+C (this is the normal behavior).
But the problem is, when I run this unix binary with my java code, it seems, as if the program is almost immediately terminated (whereas it should be running, until I press the stop button), and because its not running & being terminated, My program cannot control the percentage of CPU a process gets.
Here's my code : http://pastebin.com/rbG3ctfH
so, is there a way to tell java to keep running the cputhrottle binary file, instead of closing it.
I've tried replacing the 56th line, and instead wrote code to execute a script, which would create a file, with some text content, & when executed he program, it did created a file, so its working, but when i add e1.printStackTrace in the catch block, it stops working for some reason.
And also, if I add sleep in the shell script, then its not executed Properly, more over no Exception is being Generated.
The command you are trying to run ("echo dkkdk|sudo....) is a shell command. You need to tell runtime.exec() to run 'bash -c echo dkkdk|sudo..'
Also be aware that runtime.exec is asynchronous and could/might/likely will return to your program before the child process completes.
Also, I could not pipe the superuser password to sudo like you are trying to do. Not saying it doesn't work for you just that I couldn't get my system to take it.

DataInputStream java - program doesn't end once dis.close() is called then system.exit(0). Only happens on .exe

There is a couple anomalies I have found here.
Program info:
The program is a parser. It takes in data through a data input stream. Then when the data input stream is closed I call system.exit(0).
dis.close();
System.exit(0);
I have created a jar and exe. When I use the jar it seems to run fine. and everything is as expected. The console looks like this
/the/path/that/im/currently/in
$ <I type:> java -jar myprogram.jar commandLineArg *enter
Program output
Program output
Program output
<program ends and goes back to>
/the/path/that/im/currently/in
$
When I use the exe. The console looks like this, and you can see how it kind of bounces.
/the/path/that/im/currently/in
$ <I type:> ./myprogram commandLineArg *enter
/the/path/that/im/currently/in
$ Program output
Program output
Program output
<now stuck hanging until I hit enter or ctrl+c> *enter
/the/path/that/im/currently/in
$ <now i'm back where I should be>
This sounds like a problem with the tool you used to make the .exe file, it may no longer use a Java Virtual Machine to execute your code, or use one which is inappropriately implemented in that the System.exit(0) call is not recognised as a command to also exit the wrapper process, and as stated by the Javadocs for System.exit(int status):
public static void exit(int status)
Terminates the currently running Java Virtual Machine. The argument
serves as a status code; by convention, a nonzero status code
indicates abnormal termination.
This method calls the exit method in class Runtime. This method never
returns normally.
The call System.exit(n) is effectively equivalent to the call:
Runtime.getRuntime().exit(n)
As such, it may be worth trying another wrapper tool.
System.exit() is a drastic call -- it forces exit of all running threads, rather than allowing them to run to completion. It can be appropriate in cases where you need to communicate an exit code to the OS, or when there are threads you know should be killed. But it is not generally necessary, there are better ways to termnate your program.
We can't tell about yours, of course, unless we know more about the program. But I suspect a hack/quick fix would be to put a Thread.sleep(3000) right before the call to exit().

Runtime.exec getting killed by System.exit?

I have a java program that is supposed to run a bat file, and then exit with a success code 0.
The code essentially looks like this
Runtime.exec(....);
System.exit(0);
99.8% of the time, this works perfectly. But very sporadically the bat file won't get run.
My theory is that on certain systems, the Runtime.exec can't finish its spawning before the System.exit runs. Is this likely/possible?
I looked at the source of Runtime.exec but it drops into native code to do the interesting stuff.
EDIT
Based on the answers so far, I should state that the .bat file executes another java process using javaw. I can confirm that the 1st java process ending does NOT kill the 2nd one run in the bat file.
Is it possible that when the problem happens the bat file hadn't spawned the 2nd java process before the System.exit occurred? Perhaps it is not a Runtime.exec problem after all?
EDIT2
I cannot wait for the 2nd process to end, it could run indefinitely and my 1st process must exit.
Try to change to ProcessBuilder. Maybe it works better.
You are creating a child process that will terminate with its parent. You must use Process.waitFor in Java to ensure that Java process waits for the bat process to finish.
System.exit(0) kills jvm instance. All process will be terminated. If you want to really execute System.exit(0), make sure exec process is done before calling System.exit.
Use Process.waitFor(), the return type of this method is int which gives you the return code as per your current solution using Runtime.
waitFor() causes the current thread to wait, if necessary, until the process represented by this Process object has terminated.
Change it to
Runtime.getRuntime().exec(....).waitFor();
System.exit(0);
But then this will wait for batch file to complete execution and in your case completion of javaw instance.

External program blocks when run by Runtime exec

I'm attempting to launch an instance of the VideoLAN program from within a java application. One of the ways I've tried to do this is shown here:
Process p = Runtime.getRuntime().exec("\"C:\\Program Files\\VideoLAN\\VLC\\vlc.exe\" \"http://www.dr.dk/Forms/Published/PlaylistGen.aspx?qid=1316859&odp=true\" :sout=#std{access=udp,mux=ts,dst=127.0.0.1:63928}");
If I execute the above command the vlc program will be launched, and will start a streaming operation (it goes through connect, buffering and then streaming phases).
When the command is executed by Runtime exec (or ProcessBuilder start), the vlc program will hang when it reached the end of the buffering phase. If all threads in the java program are terminated/run to an end, the vlc program will progress to the streaming phase. The java process will not terminate until the vlc process is closed, so this behavior is obviously the result of some sort of coupling between the processes.
Have tried to execute the command indirectly by writing it to a .cmd file and then executing it, but results in the same behavior.
Any ideas for how I can avoid the external process hanging?
Hmm, my guess would be that VLC filled your STDOUT buffer and is hung in a printf statement because STDOUT is waiting for that buffer to empty.
You need to get the stream for the process's output and read it (even if you discard it).
I recommend you read this article
On the 4th page is a good example of how to read the streams in threads so your child process won't block.
This site is fantastic :). For some reason an approach I thought had already been tried suddenly started working.
The problem is that vlc writes to its stdErrOut (which is not visible when executed in a prompt). It then blocks once some output buffer is full. A solution is to have a stdErr redirected to stdOut and then have a thread empty the input stream of the process object.
It is however not an optimal solution, since I need a fair amount of external processes, and you can't do non-blocking I/O on their input streams. Will experiment a bit with having a timer service drive empty-reading for a number of processes. Other suggestions for how to de-couple the processes to avoid this problem are very welcome.

Best Way to Launch External Process from Java Web-Service?

I've inherited a Java web-services code-base (BEA/Oracle Weblogic) and need to start/launch an external background application from a web-service.
I've already tried:
ProcessBuilder pb = new ProcessBuilder(arg);
pb.start();
as well as:
Runtime.exec(cmdString);
But am experiencing strange behaviors when launching applications in this manner (i.e. the launched application stops working even though the process is still active. -- The application works fine when manually run from a normal command line).
Is there a better way to launch an external processes?
EDIT: ----------------------
I have some additional information that may help shed some light on the problem.
The process we are trying to start will require hours to complete so waiting for completion (using waitfor()) in the webservice will not be an ideal scenario.
Yes, the process we are trying to start from the webservice was created by a fellow team member [cue: your eyes roll... now]
I have had success when I use process builder to start a bash script, where the external application is launched as a background process (using "&").
#!/bin/bash
java -jar myApp.jar &
This obviously creates an orphaned process but at least the application does continue to execute.
Simply put: if the launched application writes to SDTOUT/STDIN and you don't flush them frequently (see Process.getErrorStream/Process.getInputStream) then the process will block when the buffer is full (that is really small, 4KB or less).
I recommend you to invoke ProcessBuilder.redirectErrorStream() before starting the process. Then, after that, create a thread with the run() method along the lines of:
public void run() {
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
By "stops working even though the process is still active" I am assuming you might be expecting some output from the application you have launched and not getting anything.
Try using the following:
ProcessBuilder pb = new ProcessBuilder(arg);
Process p = pb.start();
p.waitFor();
waitFor() causes the current thread to wait, if necessary, until the process represented by this Process object has terminated.
http://java.sun.com/javase/6/docs/api/java/lang/Process.html#waitFor()
Firstly, is this happening on Windows or on Linux? Also, what is the launched application supposed to more or less do? (is it a script? is it a binary? is it your binary?)
EDIT
OK, so starting a bash script (using ProcessBuilder) which in turns spawns a new JVM (java -jar myApp.jar) works.
What happens exactly when you try to spawn the new JVM directly using ProcessBuilder? You originally said:
the launched application stops working
By launched application do you mean "java -jar myApp.jar", when invoked directly, not via an intermediate bash script?
What are the exact and complete parameters (and their values) you pass to the various ProcessBuilder methods (and in which order) when you try to launch Java directly and this new JVM stops working? (e.g. provide annotated code)
If you install lsof on your *nix machine, what file is shown to be associated with file descriptor 2 (look at the FD column) when running: lsof -p 1234 (where 1234 is the process ID of the "hung" JVM?) It might be interesting to attach the entire output of the lsof command here.
What is appended to the file you have identified in step 3 above (for file descriptor 2), up to several seconds after you issue the command: kill -QUIT 1234 (where 1234 is the process ID of the "hung" JVM?)
Are you properly handling the standard input and output of the process? If the standard input or output is being processed by your application and you are not properly handling it, then the process you execute will hang waiting for I/O.
A way to test this is to write a script that runs your program, redirecting standard input, output and error to files. Then have your web service app run the script instead of the program. If the program runs to completion this way, then the problem is handling of the output of the process.
I'm guessing that the problem might be the thread that launches the process gets TERMINATED or whatever after the request is over. Try having a single thread in the applicaton that you are sure is kept alive always, you can use this for starting the processes by making calls to it from other threads.

Categories