0

I have this code

private static void restartTor() throws IOException, InterruptedException {

    String killTor = "killall tor";
    String startTor = "/opt/local/bin/tor -f /dev/torrc";
    Runtime run = Runtime.getRuntime();
    Process pr = run.exec(killTor);
    pr.waitFor();
    BufferedReader buf = new BufferedReader(new InputStreamReader(pr.getInputStream()));
    String line = "";
    while ((line=buf.readLine())!=null) {
        System.out.println(line);
    }
    pr = run.exec(startTor);
    pr.waitFor();
    buf = new BufferedReader(new InputStreamReader(pr.getInputStream()));
    line = "";
    while ((line=buf.readLine())!=null) {
        System.out.println(line);
    }
}

When I run this on computer A it executes as expected but when I run it on my second computer, B, it gets stuck at the second pr.waitFor();.

I have read a bunch of questions here on SE, such as process.waitFor() never returns and Java process.waitFor() does not return and the main issue there seems to be that you don't read the buffer but I do that (don't I?).

A and B are similar, but not identical (Macs, running 10.15, A has 32 GB RAM, B has 16 GB RAM).

I use the same version of tor and the torrc:s are identical on A and B.

I am stumped. What is the problem here?


Edit: On B, If I manually, from a regular terminal, kill the process, it returns and everything continues as expected.

Edit 2: Now it fails on computer A as well. I had run it dozens of times there, without problems before but now it fails constantly.

2 Answers2

1

I don't know if this this is the ultimate cause of your problem, but you should call waitFor after reading the output (and errors) from the external process. If a process writes more to its standard output and error streams than the OS is prepared to buffer, then your code could deadlock:

  • The external process is blocked while trying to write output
  • Your Java code is blocked waiting for the external process to exit.
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
0

You need to consume both streams at same time if you are experiencing the stream deadlock issue on waitFor(). You can do this with background threads on pr.getErrorStream(), or set up STDERR handling before calling waitFor().

To do this replace use of Runtime.exec with ProcessBuilder.

ProcessBuilder pb = new ProcessBuilder(startTor);

This is easier with either sending error log to a file:

File stderr = new File("stderr.log");
pb.redirectError(stderr));
        

... or just redirect error to merge it with stdout:

pb.redirectErrorStream(true);

then

pr = pb.start();
pr.waitFor();
DuncG
  • 12,137
  • 2
  • 21
  • 33