From: Eric Wong <e@80x24.org>
To: meta@public-inbox.org
Subject: [RFC 3/3] input_pipe: handle noncanonical TTY
Date: Tue, 17 Oct 2023 10:11:06 +0000 [thread overview]
Message-ID: <20231017101106.582556-4-e@80x24.org> (raw)
In-Reply-To: <20231017101106.582556-1-e@80x24.org>
lei could get a TTY in noncanonical mode for stdin, so rely on
VMIN+VTIME to get the desired non-blocking semantics we'd expect
from a pipe or socket. This ought to prevent read(2) (Perl sysread)
from returning zero when we really want to hit EAGAIN.
---
lib/PublicInbox/InputPipe.pm | 33 ++++++++++++++++++++++++++++++++-
1 file changed, 32 insertions(+), 1 deletion(-)
diff --git a/lib/PublicInbox/InputPipe.pm b/lib/PublicInbox/InputPipe.pm
index 39aefab2..8358ddd6 100644
--- a/lib/PublicInbox/InputPipe.pm
+++ b/lib/PublicInbox/InputPipe.pm
@@ -6,6 +6,31 @@ package PublicInbox::InputPipe;
use v5.12;
use parent qw(PublicInbox::DS);
use PublicInbox::Syscall qw(EPOLLIN);
+use POSIX ();
+use Carp qw(croak carp);
+
+# I'm not sure what I'm doing w.r.t terminals.
+# FIXME needs non-interactive tests
+sub unblock_tty ($) {
+ my ($self) = @_;
+ my $fd = fileno($self->{sock});
+ my $t = POSIX::Termios->new;
+ $t->getattr($fd) or croak("tcgetattr($fd): $!");
+ return if $t->getlflag & POSIX::ICANON; # line-oriented, good
+
+ # make noncanonical mode TTYs behave like a O_NONBLOCK pipe.
+ # O_NONBLOCK itself isn't well-defined, here, so rely on VMIN + VTIME
+ my ($vmin, $vtime) = ($t->getcc(POSIX::VMIN), $t->getcc(POSIX::VTIME));
+ return if $vmin == 1 && $vtime == 0;
+
+ $t->setcc(POSIX::VMIN, 1); # 1 byte minimum
+ $t->setcc(POSIX::VTIME, 0); # no timeout
+ $t->setattr($fd, POSIX::TCSANOW) or croak("tcsetattr($fd): $!");
+
+ $t->setcc(POSIX::VMIN, $vmin);
+ $t->setcc(POSIX::VTIME, $vtime);
+ $self->{restore_termios} = $t;
+}
sub consume {
my ($in, $cb, @args) = @_;
@@ -16,11 +41,17 @@ sub consume {
$self->requeue;
} elsif (-p $in || -s _) { # O_NONBLOCK for sockets and pipes
$in->blocking(0);
- } # TODO: tty
+ } elsif (-t $in) { # isatty(3) can't use `_' stat cache
+ unblock_tty($self);
+ }
}
sub close {
my ($self) = @_;
+ if (my $t = delete($self->{restore_termios})) {
+ my $fd = fileno($self->{sock} // return);
+ $t->setattr($fd, POSIX::TCSANOW) or carp("tcsetattr($fd): $!")
+ }
$self->{-need_rq} ? delete($self->{sock}) : $self->SUPER::close
}
prev parent reply other threads:[~2023-10-17 10:11 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-10-17 10:11 [PATCH 0/3] lei: stdin handling improvements Eric Wong
2023-10-17 10:11 ` [PATCH 1/3] lei: consolidate stdin slurp, fix warnings Eric Wong
2023-10-17 10:11 ` [PATCH 2/3] input_pipe: improve error handling Eric Wong
2023-10-17 10:11 ` Eric Wong [this message]
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://public-inbox.org/README
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20231017101106.582556-4-e@80x24.org \
--to=e@80x24.org \
--cc=meta@public-inbox.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).