[comp.unix.questions] BSD vs. SVR4 typehead flush after tty mode change

dce@smsc.sony.com (David Elliott) (10/05/90)

I execute the following command line:

	sleep 5 ; cat /etc/passwd | more > /dev/null

While the sleep is still running, I type "date" (followed
by RETURN) 3 times.

Under BSD, I get 3 date commands run.  Under RISC/OS on a MIPS M2000,
the same happens.  Under our SVR4 system, I get nothing -- the input
has disappeared.

Is there an stty setting that will fix this?  Is it just a difference
between the operating systems, or is it a problem with 'more' changing
the tty mode when it shouldn't?

I should also mention that similar things happen when I am getting
out of vi.  It's annoying to lose typeahead, and I generally
think a few seconds ahead of myself.  I guess I need faster
computers ;-)

jrh@mustang.dell.com (James Howard) (10/05/90)

In article <1990Oct4.213623.27362@smsc.sony.com>, dce@smsc.sony.com
(David Elliott) writes:
> I execute the following command line:
> 
> 	sleep 5 ; cat /etc/passwd | more > /dev/null
> 
> While the sleep is still running, I type "date" (followed
> by RETURN) 3 times.
> 
> Under BSD, I get 3 date commands run.  Under RISC/OS on a MIPS M2000,
> the same happens.  Under our SVR4 system, I get nothing -- the input
> has disappeared.
> 

I just tried this on my V.4 system, and I get three date commands run, as 
you would expect.  I think you must have something wrong on your particular
version of V.4, or maybe the shell you're running.

James Howard        Dell Computer Corp.        !'s:uunet!dell!mustang!jrh
(512) 343-3480      9505 Arboretum Blvd        @'s:jrh@mustang.dell.com
                    Austin, TX 78759-7299   

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (10/05/90)

In article <1990Oct4.213623.27362@smsc.sony.com> dce@smsc.sony.com (David Elliott) writes:
  [ cat /etc/passwd | more > /dev/null flushes tty input on SVR4 ]
> Is there an stty setting that will fix this?

Under BSD, if your tty is normally in cbreak -echo mode (as some shells
prefer), this sort of problem may go away. Smart programs won't change
the mode; even for those that do, the tty driver might not flush input
for a noop. So I wonder what happens if you use ksh in an editing mode.

> Is it just a difference
> between the operating systems, or is it a problem with 'more' changing
> the tty mode when it shouldn't?

Almost certainly the latter, since more shouldn't be talking to the tty
at all.

> I should also mention that similar things happen when I am getting
> out of vi.  It's annoying to lose typeahead, and I generally
> think a few seconds ahead of myself.

I agree. One strategy to fix this, on BSD systems, is to change TIOCSETP
to TIOCSETN. On this system the only difference between the calls is
between a 32-bit 9 and a 32-bit 10, so it should be easy to find out
where to patch the binary.

---Dan

gwyn@smoke.BRL.MIL (Doug Gwyn) (10/05/90)

In article <10704@uudell.dell.com> jrh@mustang.dell.com (James Howard) writes:
>I think you must have something wrong on your particular
>version of V.4, or maybe the shell you're running.

My bet would be that "more" was improperly ported,
and that a "flushing" tty ioctl was used in the port.

ag@cbmvax.commodore.com (Keith Gabryelski) (10/10/90)

In article <14028@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
>In article <10704@uudell.dell.com> jrh@mustang.dell.com (James Howard) writes:
>>I think you must have something wrong on your particular
>>version of V.4, or maybe the shell you're running.
>
>My bet would be that "more" was improperly ported,
>and that a "flushing" tty ioctl was used in the port.

No.  There is a bug in SysVr4 streams tty module `ldterm' that flushes
the stream if ICANON is turned on.

This effectively disables typeahead in shells that turn on ICANON when
leaving edit mode (ie ksh in emacs mode).

The fix:

*** ldterm.c-	Wed Oct 10 12:39:58 1990
--- ldterm.c	Wed Aug 15 17:30:29 1990
***************
*** 3162,3168 ****
--- 3162,3170 ----
  		 */
  		if (tp->t_modes.c_lflag & ICANON) {
  			DEBUG4 (("CHANGING TO CANON MODE\n"));
+ #ifdef FLUSH_IF_ICANON_TWEAKED
  			(void) putctl1(q->q_next, M_FLUSH, FLUSHR);
+ #endif
  			optbuf.so_flags = SO_READOPT|SO_MREADOFF;
  			optbuf.so_readopt = RMSGN;
  

dce@smsc.sony.com (David Elliott) (10/12/90)

>In article <14028@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
>>In article <10704@uudell.dell.com> jrh@mustang.dell.com (James Howard) writes:
>>My bet would be that "more" was improperly ported,
>>and that a "flushing" tty ioctl was used in the port.
>
>No.  There is a bug in SysVr4 streams tty module `ldterm' that flushes
>the stream if ICANON is turned on.

While this may be true, the problem with more in this case was that
it was using TCSETAF, which does flush the tty.  I don't know whether
or not this is "improper".  It doesn't work nicely for me, but it
may be the right thing to do for shl.

It also turned out that SVR4 more resets the tty even if it never
changed it in the first place.

I changed both (TCSETAF becomes TCSETA, and the mode is only reset
if it was changed).  Programs shouldn't mess around with my typeahead.

guy@auspex.auspex.com (Guy Harris) (10/14/90)

>The fix:

OK, now *after* you've applied the fix, try the following:

	Fire up the (S5R4) C shell.

	Turn on filename completion ("set filec").

	Do:

		stty -icanon min 1 time 0; sleep 10;
		    stty icanon eof <whatever> eol <whatever>

	and type "cat /etc/m" after hitting <RETURN> after the preceding
	command line

If you get bizarre behavior from the C shell - for example, a listing of
all files in "/etc" whose names begin with "m", or worse - you have just
discovered why I put that flush into the SunOS 4.0 "tty_ldterm.c" (which
is why it's in the S5R4 "ldterm.c", it being derived from the SunOS
"tty_ldterm.c").

If you don't, I suspect "ldterm" has been changed to 1) request M_READ
notification and 2) *NOT* to send anything upstream until it's asked for
by an M_READ.  If so, this raises the question of how "poll()" can
figure out there's stuff to be read if it's not at the stream head....

The problem is that, in non-canonical mode, input is sent upstream in
streams messages in such a fashion that the boundaries between messages
aren't relevant, so that stuff gets upstream without waiting for an NL. 
The stream head is running in "byte stream" mode, so the stream head
doesn't care about the boundaries between messages in any case.

In *canonical* mode, there is one line per stream head (where a "line"
is terminated by an NL, or by the EOF character, or by either of the two
"alternate end-of-line" characters), and the stream head is in
message-nondiscard mode.  This is necessary in order to implement
standard UNIX cooked-mode tty semantics, i.e. in order to have a
"read()" return at most one line.

Unfortunately, if, say, the tty were in non-canonical mode (with, say,
MIN 1 and TIME 0), and you typed "cat /etc/m", this would probably get sent
upstream as several streams messages, one with "c", one with "a", one
with "t", etc..  When the tty is switched to canonical mode, and thus the
stream head is switched to message-nondiscard mode, some process doing a
"read()" will then have the "read()" succeed, returning one character -
the "c".

This looks to that program as if the user had typed "a" followed by the
EOF character.  The C shell, with filename completion set, will, at the
appropriate time, respond appropriately to this - i.e., it'll give a
listing of the possible completions of the string.

Now, as indicated, one possible fix would be to have "ldterm" never send
anything upstream until it knows (or, at least, has a good guess about)
whether what it's sending upstream is to be read in canonical or
non-canonical mode.

Unfortunately, as indicated, this makes life more difficult for
"poll()", as it can no longer simply check out the stream head to see
whether a "read()" on a file descriptor will block or not; it has to
send a notification downstream to ask whether anybody below the stream
head is withholding any data pending an M_READ message.

gwyn@smoke.BRL.MIL (Doug Gwyn) (10/14/90)

In article <4187@auspex.auspex.com> guy@auspex.auspex.com (Guy Harris) writes:
>>The fix:
>OK, now *after* you've applied the fix, try the following:
>	Fire up the (S5R4) C shell.

It sems to me that a bug was introduced in the kernel solely in order
to avoid fixing the C shell, which is clearly screwed up in its input
handling.  In interactive command-line editing mode, a shell should
read() only 1 character at a time.

guy@auspex.auspex.com (Guy Harris) (10/16/90)

>It sems to me that a bug was introduced in the kernel solely in order
>to avoid fixing the C shell, which is clearly screwed up in its input
>handling.  In interactive command-line editing mode, a shell should
>read() only 1 character at a time.

I won't defend the unnatural acts the C shell engages in to implement
"filec",

BUT

that's not *the* problem with switching modes, it's just the most
*obvious* one.

Consider a more vanilla shell, one that runs in cooked mode.  You type
some characters while exiting some program that runs in uncooked mode,
those characters being typed while still in uncooked mode.  As such,
they probably went upstream immediately and are sitting at the stream
head.

Let's say you're typing the command "cat /etc/motd", and you, say,
manage to type "cat /ect/" (*sic*) before the driver is switched to
cooked mode.  You realize you got it wrong, and type your kill character
to try to erase the entire line and start again (or, this being S5R4,
type the word-erase character).

Well, the "cat /ect/" has already left "ldterm"s domain, so it *can't*
be erased by ^U (or ^W).  It is, again, just as if you'd typed

	c^Da^Dt^D ^D/^De^Dc^Dt^D/^D

Probably the "best" fix for this problem is to have "ldterm", when in
uncooked mode, *never* send anything upstream unless it's been
requested.  This does, of course, require some way of dealing with the
"poll()" problem, which probably means a message sent downstream when
the "poll()" is done (only if the stream has M_READ notification turned
on), and another message sent upstream in lieu of data to indicate that
a "poll()" waiting for input to succeed.  Unfortunately, that would
require more stuff to be added to the stream head code....

ag@cbmvax.commodore.com (Keith Gabryelski) (10/16/90)

In article <4191@auspex.auspex.com> guy@auspex.auspex.com (Guy Harris) writes:
>>It sems to me that a bug was introduced in the kernel solely in order
>>to avoid fixing the C shell, which is clearly screwed up in its input
>>handling.  In interactive command-line editing mode, a shell should
>>read() only 1 character at a time.
>
>I won't defend the unnatural acts the C shell engages in to implement
>"filec",
>
>BUT
>
>that's not *the* problem with switching modes, it's just the most
>*obvious* one.
>
>Consider a more vanilla shell, one that runs in cooked mode.  You type
>some characters while exiting some program that runs in uncooked mode,
>those characters being typed while still in uncooked mode.  As such,
>they probably went upstream immediately and are sitting at the stream
>head.

If I am not mistaken I remember noting this same problem with
switching from non-canonized processing to canonized processing under
the old (non streams) tty subsystem.  Ie, this is not a new problem.

It also seems to me that flushing the stream when ICANON is turned
on may fix this problem for csh, but breaks typeahead (for programs
that go in an out of ICANON) and breaks termio (flushing on TCSETS).

Try (while in vi).

	:!sleep 10
	:!echo foo
	:!echo bar
	:!echo baz


Pax, Keith

dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) (10/17/90)

UNIX assumes a per-tty state rather than a per-process state, i.e.,
it's the tty driver that's in a certain mode of operation rather than
the process.  This leads to all sorts of problems.  (Though it no doubt
greatly simplifies the system call interface and avoids the QIO fiasco
in VMS.)

I think the tty stream ("stream", not necessarily "STREAM") should
associate each data byte with a control byte.  The control byte could
tell you when EOF was seen, and also what state the tty was in when the
character was read.  My gut feeling is that this would make all sorts
of tty interfaces (including what BSD does and what SVR4 does) more
powerful.  You could even go so far as putting a "delete previous
character" control byte in the stream, so the next module in the STREAM
("STREAM", not necessarily "stream") could edit the incoming stream of
characters.
--
Rahul Dhesi <dhesi%cirrusl@oliveb.ATC.olivetti.com>
UUCP:  oliveb!cirrusl!dhesi

guy@auspex.auspex.com (Guy Harris) (10/19/90)

 >>Consider a more vanilla shell, one that runs in cooked mode.  You type
 >>some characters while exiting some program that runs in uncooked mode,
 >>those characters being typed while still in uncooked mode.  As such,
 >>they probably went upstream immediately and are sitting at the stream
 >>head.
 >
 >If I am not mistaken I remember noting this same problem with
 >switching from non-canonized processing to canonized processing under
 >the old (non streams) tty subsystem.  Ie, this is not a new problem.

I think you're mistaken.  I've never noted any such problem with either
the old BSD tty subsystem or the old S5 tty subsystem.

The old BSD tty subsystem will, if you switch from CBREAK mode to
non-CBREAK mode, take everything in the raw queue and shove it through
the input-processing machine.  (If you switch from RAW mode to non-RAW
mode, it discards queued input.)

The old S5 tty subsystem leaves stuff in the raw queue until you
actually try to read it, at which point it calls "canon()" and moves
stuff in the raw queue to the canonical queue after doing canonical
processing.

In both cases, characters typed in noncanonical mode are under the
control of the line discipline until they're actually read by a process,
and are in the raw queue, so that they can be erased if canonical mode
is turned on.

>It also seems to me that flushing the stream when ICANON is turned
>on may fix this problem for csh, but breaks typeahead (for programs
>that go in an out of ICANON)

Yes, that's the complaint that started this thread in the first place; I
don't like it, but short of arranging that characters typed in
noncanonical mode remain under the control of "ldterm" until they're
actually read by a process, as is the case in non-streams tty drivers
and as I suggested be the made the case with the streams tty driver, you
have the problem I described.  I don't like having typeahead discarded,
either, but....

In order to arrange that characters typed in noncanonical mode remain
under the control of "ldterm" until they're read, you need:

	1) M_READ: SunOS 4.x doesn't have it, but S5R4 does;

	2) M_POLL - i.e., if a "poll()" for input is done on a stream
	   with no data at the stream head but with M_READ notification
	   turned on, a message is sent downstream; if there is data
	   that would have been send upstream in response to an M_READ,
	   a reply is sent upstream to the M_POLL that causes it to
	   succeed, and if there isn't any data, the fact that a
	   "poll()" is in progress is noted, so that when data *does*
	   come in, the reply can be sent upstream to wake up any
	   "poll()"ing processes.  Neither SunOS 4.x *nor* S5R4 have
	   this, as far as I know.

All that stuff doesn't necessarily help if you have a user-mode
canonicalizer that can get out of the way if canonicalization is turned
off, e.g. a "cmdtool" window or an Andrew Toolkit "tm" window.

The problem there is that the "cmdtool" or "tm" or whatever program
would have to withhold any characters typed at it when canonicalization
is turned off, and listen for M_READ or M_POLL messages sent down the
slave side (the S5R4 pseudo-tty mechanism would let this happen, as long
as the appropriate pseudo-tty streams modules and driver pass it through
to the master side).  If such a message arrived, it would cough up the
requested number of characters (if an M_READ) or a reply (if an M_POLL).

If the program detected that canonicalization is turned on, it would
have to take all the queued-up characters and act as if they'd been
typed at it in canonical mode.

Programs like that get in the way of a number of things (including the
filename completion stuff the C shell does, and which I mentioned
earlier).