BSD vs. SVR4 typehead flush after tty mode change

Guy Harris guy at auspex.auspex.com
Sun Oct 14 07:34:37 AEST 1990


>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.



More information about the Comp.unix.questions mailing list