From: Dilbert on
On 13 jan, 00:09, "Peter J. Holzer" <hjp-usen...(a)hjp.at> wrote:
> On 2010-01-12 22:48, Jim Gibson <jimsgib...(a)gmail.com> wrote:
>
> > [problem with flushing output to screen before reading input snipped]
>
> > It is likely that it is the tee program that is doing the buffering and
> > needs to be flushed before input is read.
>
> No. tee doesn't buffer (at least not the implementations I'm familiar
> with).

I confirm, if I flush STDOUT in my Perl program, then the output is
ok.

> Dilbert correctly (except that he erroneously calls a pipe a
> "flat file", but that makes no difference in this context) the behaviour
> required for stdio by the C standard. Apparently perlio emulates this
> behaviour.

Under normal circumstances, perlio emulates the behaviour required for
stdio by the C standard correctly. And I understand that this
behaviour is dropped if I re-open STDOUT to another file.

What I would like to achieve is to teach perlio *not* to forget this
behaviour in this particular case when STDOUT is re-opened to a pipe
that tee's back to the terminal.
From: Peter J. Holzer on
On 2010-01-13 09:40, Dilbert <dilbert1999(a)gmail.com> wrote:
> On 13 jan, 00:09, "Peter J. Holzer" <hjp-usen...(a)hjp.at> wrote:
>> Dilbert correctly (except that he erroneously calls a pipe a
>> "flat file", but that makes no difference in this context) the behaviour
>> required for stdio by the C standard. Apparently perlio emulates this
>> behaviour.
>
> Under normal circumstances, perlio emulates the behaviour required for
> stdio by the C standard correctly.

It also emulates the behaviour correctly in this case.

> And I understand that this behaviour is dropped if I re-open STDOUT to
> another file.

AIUI, you didn't reopen STDOUT. Filedescriptor 1 already referred to a
non-terminal when your program was called.


> What I would like to achieve is to teach perlio *not* to forget this
> behaviour in this particular case when STDOUT is re-opened to a pipe
> that tee's back to the terminal.

Yes, I understood that. But the behaviour you want is *not* allowed by
the C standard. Of course the C standard is only marginally relevant to
perl, so perl could implement a more intelligent flushing scheme.
However, it cannot detect what the program on the other end of the pipe
(tee in this case) does, so it either needs to be a better heuristic
(which may be difficult because "better" includes "doesn't break
existing programs") or it needs to be user/programmer-controllable.
Maybe a function "flush that stream before reading from this stream". Or
- even more generic - just a hook which is called for certain ops. So
you could do something like

$in->add_hook(pre_read => sub { $out->flush });

hp
From: Dilbert on
On 13 jan, 13:29, "Peter J. Holzer" <hjp-usen...(a)hjp.at> wrote:
> Yes, I understood that. But the behaviour you want is *not* allowed by
> the C standard. Of course the C standard is only marginally relevant to
> perl, so perl could implement a more intelligent flushing scheme.
> However, it cannot detect what the program on the other end of the pipe
> (tee in this case) does, so it either needs to be a better heuristic
> (which may be difficult because "better" includes "doesn't break
> existing programs")

I agree, detecting what the program on the other end of the pipe does
is difficult.

> or it needs to be user/programmer-controllable.
> Maybe a function "flush that stream before reading from this stream". Or
> - even more generic - just a hook which is called for certain ops.

Adding a hook which is called for certain ops is the way I want to go.

> So you could do something like
>
> $in->add_hook(pre_read => sub { $out->flush });

Can this hook also be added to a simple
my $answer = <STDIN>;

Maybe the following ?
use IO::Handle;
STDIN->add_hook(pre_read => sub { STDOUT->flush });

....but that gave me an error:
Can't locate object method "add_hook" via package "IO::Handle"
From: Peter J. Holzer on
On 2010-01-13 13:41, Dilbert <dilbert1999(a)gmail.com> wrote:
> On 13 jan, 13:29, "Peter J. Holzer" <hjp-usen...(a)hjp.at> wrote:
>> Maybe a function "flush that stream before reading from this stream". Or
>> - even more generic - just a hook which is called for certain ops.
>
> Adding a hook which is called for certain ops is the way I want to go.
>
>> So you could do something like
>>
>> $in->add_hook(pre_read => sub { $out->flush });
>
> Can this hook also be added to a simple
> my $answer = <STDIN>;
>
> Maybe the following ?
> use IO::Handle;
> STDIN->add_hook(pre_read => sub { STDOUT->flush });
>
> ...but that gave me an error:
> Can't locate object method "add_hook" via package "IO::Handle"

This was an idea how such a feature could look like in a future version
of perl. It doesn't currently exist (as far as I know).

I think the simplest solution for you is to just set $|. Since you
you send the output to the screen anyway, this is unlikely to degrade
performance noticeably.

hp

From: Ben Morrow on

Quoth "Peter J. Holzer" <hjp-usenet2(a)hjp.at>:
> On 2010-01-13 09:40, Dilbert <dilbert1999(a)gmail.com> wrote:
>
> > What I would like to achieve is to teach perlio *not* to forget this
> > behaviour in this particular case when STDOUT is re-opened to a pipe
> > that tee's back to the terminal.
>
> Yes, I understood that. But the behaviour you want is *not* allowed by
> the C standard. Of course the C standard is only marginally relevant to
> perl, so perl could implement a more intelligent flushing scheme.
> However, it cannot detect what the program on the other end of the pipe
> (tee in this case) does, so it either needs to be a better heuristic
> (which may be difficult because "better" includes "doesn't break
> existing programs") or it needs to be user/programmer-controllable.
> Maybe a function "flush that stream before reading from this stream". Or
> - even more generic - just a hook which is called for certain ops. So
> you could do something like
>
> $in->add_hook(pre_read => sub { $out->flush });

This is called a 'PerlIO layer'. Writing something like this should be
trivial with PerlIO::via, at least once you've worked out how to pass
the handle that should be flushed (binmode only accepts a string), and
not terribly difficult from XS using the real API.

Ben