From: Andreas Rottmann <mail@r0tty.org>
To: "Ludovic Courtès" <ludo@gnu.org>
Cc: 39610@debbugs.gnu.org
Subject: bug#39610: R6RS `flush-output-port` not playing along with `transcoded-port`
Date: Sun, 29 Mar 2020 23:15:49 +0200 [thread overview]
Message-ID: <87bloe981m.fsf@r0tty.org> (raw)
In-Reply-To: <874kufs9xa.fsf@gnu.org>
Ludovic Courtès writes:
> Hi,
>
> Andreas Rottmann <mail@r0tty.org> skribis:
>
>>> Andreas Rottmann <mail@r0tty.org> skribis:
>>>
>>>> Andreas Rottmann <mail@r0tty.org> writes:
>>>>
>>>>> [...] I isolated the cause; the following snippet hangs on Guile 2.2
>>>>> and 3.0, while it worked as expected on 2.0:
>>>>>
>>>>> [...]
>>>>>
>>>>> 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.
>>>>>
>>>> [...]
>>>
>>> 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.
>
> Port types don’t have a “flush” operation, only “write”. Thus, it’s
> impossible to define a port type that would propagate flushes.
> There are pros and cons I guess, but it seems like a reasonable choice
> to me.
>
> When implementing a “proxying” port type like ‘transcoded-port’ that
> does its own buffering, it’s probably OK to say that it’s the proxy’s
> responsibility to ensure there’s no double-buffering taking place.
>
In my understanding, the "proxy type" is the R6RS transcoded port in
this case, which has no control over the underlying port, but provides a
flush operation (`flush-output-port`), which R6RS specifies as:
Flushes any buffered output from the buffer of output-port to the
underlying file, device, or object. The flush-output-port procedure
returns unspecified values.
So if I obtain a transcoded port from a pipe port, and call
`flush-output-port` on the transcoded port, I'd expect the bytes to end
up at _least_ at the pipe port. That probably happens currently;
however, the thing is that R6RS also says about `transcoded-port`:
As a side effect, however, transcoded-port closes binary-port in a
special way that allows the new textual port to continue to use the
byte source or sink represented by binary-port, even though
binary-port itself is closed and cannot be used by the input and
output operations described in this chapter.
So, I conclude: when you use `transcoded-port` with any underlying Guile
port, and you care about buffering behavior, you _need_ to set the
underlying port's buffer mode to 'none`, _before_ constructing the
transcoded port. I have not tried if Guile enforces the "specially
closed mode", but I am thinking in the context of an abstraction over
`pipe` and `primitive-fork`, intended to provide a basis for "pure" R6RS
code [1], so the client code cannot just call Guile's `setvbuf`, without
losing portability.
[1] https://github.com/rotty/spells/blob/master/spells/process/compat.guile.sls
Do you agree with that conclusion?
[ After writing the above, I realize that might be what you meant, after
all: do you propose that, as a fix, `transcoded-port` sets the buffer
mode of the underlying port to `none`? ]
I must admit that I am confused -- how can a port type have no flush
operation (which is evidently true from looking at scm_t_port_type), and
Guile's `force-output` procedure, generic over port types, still exist?
>> 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.
>
> Maybe we should not document this specific combination but rather the
> more general issue? I’m not sure how to do that. Thoughts?
>
I now realized I need to wrap my head around the changed port
implementation, and how it relates to R6RS in general, and
`transcoded-port` specifically, before starting to think about
documentation.
I think I have identified another related issue, this time for reading
from `trancoded-port`, but I'd rather make sure we have a shared
understanding of the expected flushing and buffering behavior, before
bringing that up.
Regards, Rotty
next prev parent reply other threads:[~2020-03-29 21:15 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-02-15 0:08 bug#39610: R6RS `flush-output-port` not playing along with `transcoded-port` Andreas Rottmann
2020-02-15 10:27 ` Andreas Rottmann
2020-03-21 17:55 ` Ludovic Courtès
2020-03-22 22:50 ` Andreas Rottmann
2020-03-23 9:22 ` Ludovic Courtès
2020-03-29 21:15 ` Andreas Rottmann [this message]
2020-02-15 13:37 ` Andreas Rottmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/guile/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87bloe981m.fsf@r0tty.org \
--to=mail@r0tty.org \
--cc=39610@debbugs.gnu.org \
--cc=ludo@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).