Subject: Re: bug#39610: R6RS `flush-output-port` not playing along with `transcoded-port`

From: Andreas Rottmann <[email-masked]>
Date: Sun, 22 Mar 2020 23:50:47 +0100

Ludovic Courtès writes:

> Hi Andreas,
> And welcome back!  :-)
Thanks -- and thanks in return for looking into this!

> Andreas Rottmann <[email-masked]> skribis:
>
>> Andreas Rottmann <[email-masked]> writes:
>>
>>> [...] I isolated the cause; the following snippet hangs on Guile 2.2
>>> and 3.0, while it worked as expected on 2.0:
>>>
>>> ;; ------------------
>>> (import (rnrs))
>>>
>>> (let* ((p (pipe))
>>>        (in (car p))
>>>        (out (transcoded-port (cdr p) (make-transcoder (utf-8-codec)))))
>>>   (put-datum out "foo")
>>>   (flush-output-port out)
>>>   (display "Should have written to pipe by now, attempting reading a byte\n")
>>>   (display "Got")
>>>   (display (get-u8 in))
>>>   (newline))
>>> ;; -------------------
>>>
>>> It seems the underlying port is no longer flushed to the OS, so the
>>> `get-u8` now hangs waiting for input, starting with Guile 2.2.
>>>
>> I'd like to add that this is indeed not passing data to the OS, as
>> verified by strace. Also, I have now figured out the commit introducing
>> the regression, namely 8399e7af5 ("Generic port facility provides
>> buffering uniformly"); the commit before (e8eeeeb1d) still runs the
>> above code to completion.
>
> Actually I think the code above behaves as expected.  ‘pipe’ returns
> buffered ports by default.  When flushing the transcoded port,
> ‘transcoded_port_write’ is called, but then bytes written to the pipe
> are buffered.
>
> The fix is to add:
>
>   (setvbuf (cdr p) 'none)
>
> Does that make sense?
>
It makes sense, and I can confirm that it makes the boiled-down example
I posted work.

However, I'm not sure it is the expected behavior. Regardless of
buffering modes used, I would expect a `flush-output-port` in a "port
stack" (as produced by `transcoded-output-port`) to propagate all the
way to the OS. It seems that was the case in Guile 2.0, as I'm pretty
sure I observed the "breaking" behavior change with 8399e7af5 applied,
and not with the commit preceding it.

If the current behavior is indeed the intended one, we should make sure
the docs somehow reflect this caveat, as I imagine it may surprise
future Guile users which happen to use its R6RS support and pipes in
combination.

Regards, Rotty