Terminate process run with `exec` when program terminates
Asked Answered
E

2

7

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?

Eloquence answered 13/5, 2011 at 7:25 Comment(10)
I'm actually really interested in the answer to this question as well. Although I can't offer it, do you mind sharing why your Java program is crashing?Twocolor
In order for this question to be answerable, you need to provide more information. For example: are you free to modify the sources of either or both of the Java and Python programs?Honeyed
I would have to disagree Vinay (haha same name). I actually am looking it up right now, but I think something along the lines of running that python Process only while the current Java Process ID is running would do the trick. Not sure if I'm on the right path, but this question truly intrigues me.Twocolor
The program crashes because it is under development and I hope that the final version will not crash ;-) However, when I test the program and it crashes I have to kill the subprocess manually, what is quite annoying ;-)Eloquence
Haha that's what I figured. I'll probably be in a similar situation down the road, so I'd really love to figure this out. Try looking up a while(PID) sort of loop in the mean time. It's a race. ;-)Twocolor
@Twocolor Sajip: Yes, I have access to the Python program that is run as a child process. However, I wonder if the is general solution in case where the is no access to the child process source code.Eloquence
@Twocolor H, what are you disagreeing with exactly? If the OP has no access to change either or both programs - e.g. because one or the other was provided by a third party - how can the OP solve the problem?Honeyed
No no haha. I was simply disagreeing with you regarding you saying the question is unanswerable. The actual question seems like something that would be plausible. I agree that, in order to fully finish his program, the OP would have to fix the bug that's actually crashing the program. No offense intended.Twocolor
To be clear, the program that is run as a child process works fine. The source of problem is the mother program that crashes in different, unexpected places. I think I could make the child process a static variable, wrap the entire Java code with try-catch and close the process every time an exception occurs. But this solution is not so good because it requires me to change all local processes to global.Eloquence
I'm sorry man. I've been really thinking about how to tackle this without "try/catch", but I can't think of any way. I'll leave it to some other Java guru. :)Twocolor
H
2

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.

Hardhearted answered 13/5, 2011 at 8:24 Comment(1)
This is not a perfect solution but this pattern is sufficient in my case.Eloquence
I
3

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?

Involuntary answered 13/5, 2011 at 8:25 Comment(1)
"Shutdown hooks should also finish their work quickly. When a program invokes exit the expectation is that the virtual machine will promptly shut down and exit. When the virtual machine is terminated due to user logoff or system shutdown the underlying operating system may only allow a fixed amount of time in which to shut down and exit. It is therefore inadvisable to attempt any user interaction or to perform a long-running computation in a shutdown hook." Killing a Python process doesn't take a long time. Seems like the perfect solution for the OP (and quenching my interest). :)Twocolor
H
2

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.

Hardhearted answered 13/5, 2011 at 8:24 Comment(1)
This is not a perfect solution but this pattern is sufficient in my case.Eloquence

© 2022 - 2024 — McMap. All rights reserved.