1

Ok, So i am trying to read the output of a c binary from java code and I am unable to figure out whether the communication channel is blocking or non blocking.

The setup is such:

  1. A java class (A.java) is run

  2. A.java runs a c binary (B.o) using Runtime.getRuntime().exec("B.o"). At this point I have the Process object (returned by Runtime.exec)

  3. A.java reads from the input stream of the Process object using a bufferedreader

  4. A.java outputs the data read from the input stream to a file (output.txt)

The B.o binary simply prints random lines using printf function call.

Now, if I run the above setup, I receive all the data sent by B.o flawlessly. Then to test (the blocking / nonblocking thing), I changed the A.java to sleep for 5 milliseconds after every read from the inputstream of the Process object of B.o. As it turned out, now I wasn't receiving the complete data in A.java send by B.o. This indicates that the communication channel being used is non-blocking (as per my weak understanding).

Then just to make sure, I started looking at the source code of java to see if I was right. And I have found the following so far:

Every call to Runtime.getRuntime().exec(...) ends up in forkAndExec() method in ProcessImpl_md.c. In ProcessImpl_md.c the command is executed, a process is created, and PIPES are setup for communication (using the pipe function call in c). I can't find anywhere in the source code where the PIPES are being set to nonblocking mode (as indicated by my code). I am assuming the PIPES are blocking by default.

I know this is a very bad way to check what I want to check. I am way out of my depth here and I am just head-banging uselessly, I think.

Can anyone point me in the right direction or tell me:

  1. Are the PIPES of a process created through java runtime API are blocking or non-blocking?

  2. When I make A.java sleep after reading from the input stream, why all data is not received? (Assumption being that the PIPE is blocking)

  3. Any non-programmatic way (i.e. I don't have to change the source code of java and etc!) to figure out if the PIPES of a process are blocking or non-blocking?

Thank you.

EDIT: (added code)

Following is not the actual (or even compilable) code but it shows what i am trying to do.

Source of "B.o":

#include <stdio.h>
void main(int argc, char*argv[]){
    int a = 0;
    for(; a<9000000; a++){
        printf("%s", argv[1]);
    }
}

Source of "A.java":

<java imports>
public class A{
    public static void main(String[] args) throws Exception{
        Process p = Runtime.getRuntime().exec("./B.o");
        BufferedReader br = new 
            BufferedReader(new InputStreamReader(p.getInputStream()));
        int a = 0;
        while(br.readLine() != null){
            a++;
            Thread.sleep(5);//data missed if this line not commented out
        }
        br.close();
        System.out.println(a);
    }
}

PLEASE CHECK MY ANSWER. USELESS QUESTION BY ME.

Undefined
  • 31
  • 1
  • 7
  • I'd avoid using a *.o extension for executable files (your `B.o`). That extension is typically used for object files. – Tim Čas Feb 10 '15 at 17:33
  • Sleeping should not change the input you get from the InputStream wrapped in a BufferedReader. A "non-blocking" read doesn't mean that you skip over input to get to more recent writes in the pipe. That said, it's not clear why you're observing skipped data. Could you post relevant code? – Andy Thomas Feb 10 '15 at 17:45
  • 1
    Really "random" lines? You'd never know if some go missing. – laune Feb 10 '15 at 17:49
  • @Tim Cas. Thanks. Will keep that in mind. – Undefined Feb 11 '15 at 05:46
  • @Andy Thomas. I think the issue is actually on the write end of the pipe to which the B.o binary is writing to. What do you think? Thanks for the response. – Undefined Feb 11 '15 at 05:49
  • @laune. I just wrote "random" to keep things simple. The sent and the received data can be matched :) – Undefined Feb 11 '15 at 05:50
  • @Undefined: If you're not adding a `'\n'` at the end of your program output, that might be the problem; or you could try using `fflush(stdout);`. See this question: http://stackoverflow.com/questions/7431425/c-stdout-print-without-new-line – Tim Čas Feb 11 '15 at 12:09
  • @Tim Cas. Ok. Thanks. – Undefined Feb 11 '15 at 14:03

2 Answers2

3

Whether the communication channels between Java and the external program (there are three, one from Java to native, and two coming back) are operating in blocking or non-blocking mode is not directly relevant to whether all data will be successfully transmitted across each. Likewise, delays between read requests are not directly relevant to whether all data will be successfully transmitted, regardless of blocking vs. non-blocking I/O in your particular implementation of java.lang.Process.

Really, your efforts to probe blocking vs. non-blocking inter-process I/O are futile, because the I/O interface provided to your Java program is based on InputStream and OutputStream, which provide only for blocking I/O. Even if non-blocking I/O were involved at some low level of the implementation, I can't think of any way for your program to detect that.

With respect to your specific questions, however:

Are the PIPES of a process created through java runtime API are blocking or non-blocking?

They could be either, but they are more likely blocking because that better matches the interface presented to the Process user.

When I make A.java sleep after reading from the input stream, why all data is not received? (Assumption being that the PIPE is blocking)

I can only speculate, but the problem is likely in the external program. Possibly it goes to sleep when its output buffer fills, and nothing happens to wake it up. It might help to invoke myProcess.getOutputStream().close() if your Java program is not sending data to the external program. It's in any case a good idea to close that stream once you've written to it everything you're ever going to write.

Any non-programmatic way (i.e. I don't have to change the source code of java and etc!) to figure out if the PIPES of a process are blocking or non-blocking?

Potentially you could run the VM under strace or connect a native debugger to it, and analyze the VM's behavior that way. If you mean to do this from inside Java then the answer is a resounding "NO". Your Java program will see blocking behavior under all circumstances because the contracts of InputStream and OutputStream demand it.

John Bollinger
  • 121,924
  • 8
  • 64
  • 118
  • Thanks for the very detailed response. Can you please let me know further if the write end of the pipe of B.o (c binary) is blocking or non-blocking? Because the only reason I can think of for all data not getting through is that the pipe write buffer (on B.o's end) gets full (since i am making my java code to sleep and thus causing delayed emptying of the buffer). This causes the overflowing data to be dropped. But for this to happen won't the pipe have to be non-blocking? – Undefined Feb 11 '15 at 05:45
  • Blocking vs. non-blocking relates to whether `read()` and `write()` calls will block when they cannot immediately transfer any data. Under no circumstance should you expect a pipe to lose data, regardless of blocking vs non-blocking mode. If you are not receiving all the data you expect from `B.o`, then it is almost surely because `B.o` is buggy. Your data are not going *into* the pipe in the first place. – John Bollinger Feb 11 '15 at 15:09
  • Note, too, that successful `read()` and `write()` syscalls are not guaranteed to transfer the full number of bytes requested, except when exactly one byte is specified and the file descriptor is open in blocking mode. Other than for the one-byte special case, that does not depend on blocking mode. Assuming that those calls will transfer the full number of bytes requested is a common error, but one that you need be concerned about only if you are calling those functions directly. – John Bollinger Feb 11 '15 at 15:20
  • Thanks. You pointed out a lot of subtle things that I was taking for granted. – Undefined Feb 12 '15 at 15:01
0

I was making a big blunder and was completely off base. Posting this answer to clear things up (though I would like to delete the question altogether). I wanted to know if the communication channels between a C binary run from Java code are blocking or non-blocking. And I mentioned that the data was missing when I made my java code sleep after reading from the input stream of the created process (of C code). The data wasn't missing because of that. I had actually put a timer in Java code after which to terminate the process of the C binary. And since the PIPES are blocking, it wasn't able to receive all the data before the timer expired. I was misinterpreting this loss of data to mean that the PIPES were non-blocking. Confirmed this by running STRACE on the created C binary process. There were no EAGAIN errors on the write syscalls. My bad. But thank you very much to all for taking out the time to respond.

Undefined
  • 31
  • 1
  • 7