[patch, libgfortran] PR47694 [4.3/4.4/4.5/4.6 Regression] Fortran read from named pipe fails

Jerry DeLisle jvdelisle@frontier.com
Sat Feb 19 18:27:00 GMT 2011


On 02/19/2011 09:15 AM, Janne Blomqvist wrote:
> On Sat, Feb 19, 2011 at 04:18, Jerry DeLisle<jvdelisle@frontier.com>  wrote:
>> Hi folks,
>>
>> The problem here is that when a read from a named pipe reads more than one
>> line worth, the formatted IO buffer holds onto the data.  When fbuf_read is
>> subsequently invoked, a sread is dutifully called and it waits for the next
>> read completion.  In the meantime, the next line of data is already in the
>> buffer so the read waits for another "enter".  The reads get out of sync.
>>   The problem does not occur with regular files because there is either
>> always data available from the file to read or an EOF occurs and in both
>> those cases sread returns.
>
> Thanks for the explanation; So I think the fundamental issue is that
> in order to handle pipes (and perhaps other stuff like terminals too?)
> correctly, we need to consume all the bytes in the buffer before
> asking for more via sread.
>
>> The patch fixes this by scanning the buffer under certain conditions looking
>> for an End-of-Line (or EOR). If EOR is found, there is no need to sread
>> again from the pipe.  This patch does add a little overhead from the tight
>> scan loop, but will save some system calls.
>>
>> Regression tested on x86-64.  I would appreciate others testing please. I do
>> not know how to create a specific named pipe test in the test suite. See the
>> PR for the original test.
>>
>> OK for trunk?
>
>     if (oldpos + *len>  oldact)
>       {
> +      /* See if we have a pending EOR in here.  */
> +      if (*len>  oldact)
>
> This second conditional makes no sense. What matters is if the current
> position in the buffer + len goes past the active bytes, which is
> exactly the previous conditional. Thus, does the patch work if you
> remove that conditional and check for EOR unconditionally if oldpos +
> *len>  oldact?

I thought it made no sense either. But without it, fmt_t_2.f90 fails.  It is the 
only regression I found when testing this patch.  I determined that condition by 
experiment.  I looked at the values of oldpos, oldact, *len for various test 
cases to see what was unique about that one in particular. I then tried 
different combinations of conditions until it worked for the piped case and this 
case and no regressions. I suppose we could study that case more explicitly, but 
it is unique. Maybe a bug elsewhere?

>
> Secondly, you check for "\n" or "\r", but I think you need to check
> that a "\r" is followed by a "\n" before you can say that you're at
> EOR.
>

It does not matter because either way the result is we read what is in the 
buffer and sf_read looks for the \r followed by \n. All we are doing here is 
avoiding an sread and I wanted to address the case where there is a \r without a 
\n. Of course I just realized I can artificially test this on my machine here 
and I will do so.

> I wonder, would it perhaps be cleaner to create a new function, say
> something like
>
> static inline uchar *
> fbuf_getptr (gfc_unit * u)
> {
>    return (uchar*) u->fbuf->buf + u->fbuf->pos;
> }
>
> use this in read_sf() to get a pointer to eventually return, then loop
> forwards one character at a time using fbuf_getc() checking for
> EOR/EOF and other conditions/errors along the way.
>
> What do you think?
>

This alternate approach could work, but I think the numerous calls to fbuf_getc 
even if inlined will be less efficient then the approach I have which is a 
fairly tight loop.

Do you want to test and compare? It will take me a little while to modify and 
test it.  Also, how exactly should we test for performance? cat bigfile 
 >tmpfifo? or just read a big file? and time it.

Jerry




More information about the Fortran mailing list