Mailing Lists: Apple Mailing Lists
Image of Mac OS face in stamp
Re: Java subprocess output buffered until process exit
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Java subprocess output buffered until process exit



Timothy Wall <email@hidden> wrote:

>The API for readLine in BufferedReader says it's supposed to treat all of
>CR, LF,
>or CRLF as end of line, so if Apple's version doesn't, that's a bug.

It's not WHETHER BufferedReader treats CR, LF, or CRLF as line-endings,
it's HOW it does so. The problem is that BufferedReader does read-ahead
when it encounters a CR, and then does a pushback if it's not a LF. On a
file, read-ahead is safe because the bytes are there (or an EOF is). On a
socket input-stream or a pipe, there may not be any bytes available for the
read-ahead, so the reading side blocks until something is available. But
if the writer of the bytes is expecting a response, then you get deadlock.

The real problem is that read-ahead OF ANY KIND is an unsafe practice in
certain situations. The fact is that it just happens to occur quite easily
in a BufferedReader reading CR-only line-endings. Consider it a pervasive
and unaddressed design defect in BufferedReader, DataInputStream, etc.

Since you're exec'ing the processes on a single Mac OS X machine, I find it
quite unlikely that line-endings will be a problem. On Mac OS X the Java
line-ending is LF-only. So there won't be any CR's in the stream unless
the C++ programs put them there. Even if there were, BufferedReader's
line-ending read-ahead would at most be one line behind what the C++
program was producing. Obviously, you're seeing a much larger gap than
that. It really sounds to me like there's another Buffered something in
the I/O pipeline (could be a BufferedInputStream) that insists on filling
its buffer before returning anything.

If you want to do a test, you can make a type of FilterInputStream that
walks back along the pipeline and tells you what the classes are that are
leading up to your filter-point. It has to be a FilterInputStream because
the upstream InputStream instance variable is protected (its name is 'in').
Here's some code off the top of my head (untried):

public class TattleInputStream
extends FilterInputStream
{
public
TattleInputStream( InputStream input )
{ super( input ); }

public Vector // ..of String elements
tattle()
{
Vector chain = new Vector();
InputStream upstream = this.in;
while ( upstream != null )
{
chain.addElement( upstream.getClass().getName() );
if ( upstream instanceof FilterInputStream )
upstream = ((FilterInputStream)upstream).in;
else
upstream = null;
}
return ( chain );
}
}


>Anyway, I wrap the Process stdout/stderr streams in a BufferedInputStream,
>then do
>repeated read calls on that, i.e.

You might want to see what happens if you don't buffer the inputs. A 1.3
BufferedInputStream is supposed to return when it sees no bytes available()
upstream (a 1.1 BufferedInputStream is not so clever). But there could be
a bug somewhere upstream that causes BufferedInputStream to block
unnecessarily.

In any case, it should be informative to find out what the upstream classes
are.

-- GG




Visit the Apple Store online or at retail locations.
1-800-MY-APPLE

Contact Apple | Terms of Use | Privacy Policy

Copyright © 2011 Apple Inc. All rights reserved.