Subject: Re: DEC vt320 terminal problem
To: Shannon Hendrix <shannon@widomaker.com>
From: Greg A. Woods <woods@weird.com>
List: netbsd-users
Date: 06/19/2001 15:33:23
[ On Tuesday, June 19, 2001 at 11:51:43 (-0400), Shannon Hendrix wrote: ]
> Subject: Re: DEC vt320 terminal problem
>
> I would have expected hardware flow control to allow full-speed output
> to the terminal without xon/xoff. It doesn't. That's why I don't think
> it really is working. For example, displaying a really large directory
> with rtscts enabled still gives me garbage after the first couple of
> pages. xon/xoff fixes this. Hardware flow control alone should be
> sufficient.

Only if hardware flow control actually works in the terminal.  Fred's
reply suggests it only work on VT5xx terminals.  All I know is that my
DECserver terminal servers can do either hardware flow control, *or*
modem control.  :-)

> I was watching traces of tcsh, and it sends the following string 
> out for each prompt:
> 
>   8076 tcsh     GIO   fd 17 wrote 42 bytes
>          "\^[[79C  \rescape:/home/shannon\^[[59C  \r204 % "
> 
> I see the the ioctl() call before each prompt and external execution.

That's more or less what I exected you'd see (modulo the single ioctl()
vs. two of them, one before the prompt, and one after the <CR> is read.)

> Anyway, I think the problem is in that prompt string.  The first escape
> code means cursor right 79 times.  Then two spaces and carriage return.
> After printing the first prompt it does cursor right 59 times, two spaces
> and carriage return.

The prompt string is not the problem.  The ioctl() is.  The prompt
string is merely long enough to trigger the problem by causing the
terminal to need to do some kind of flow control.  Proof of this below.

> I personally think it would work better if it just issued a carriage
> return and linefeed.  I know what you said about some applications
> being paranoid about how that is handled, but I think this is worse.

If you try my example with /bin/sh and set PS1 to something equivalently
long but containing no special characters you'll be able to reproduce
the problem with "set -o emacs" and see that it goes away when you turn
off all command-line editing and thus stop the shell from doing a pair
of ioctl()s for every prompt it prints.

> I know in the past I found that some terminals were not fast enough to
> handle wrapping on single character output and then doing _anything_
> else for a few milliseconds.

The old fashioned way to handle this without flow control is to make
sure to send non-printing characters to eat up the time the terminal
takes to do its thing....

> I'm now not entirely sure it's the hammering, mainly because I don't
> see two ioctl() calls per prompt being all that hard on the driver or
> the hardware. It could just be a matter of the iotcl() happening near
> the same time as the linefeed, and the terminal handles that badly for
> whatever reason.

It's not "hard" on the driver per se -- it's simply that there's a bit
of a race condition where the ioctl() might happen at exactly the same
time the terminal sends a flow control character.

> > I'm fairly certain the problem does not occur with plain /bin/sh because
> > I don't think it is twiddling the stty settings with every prompt.
> 
> It uses the same TIOCSETAW ioctl() calls, in much the same manner, as
> tcsh does.

Huh?  I see no ioctl() calls in plain /bin/sh when command-line editing
is turned off.  Here's a complete trace of all calls spanning the
reading of two <CR> charactrs and printing of the two resulting prompts:

  2107 sh       CALL  read(0,0x80aff40,0x3ff)
  2107 sh       GIO   fd 0 read 1 bytes
       "
       "
  2107 sh       RET   read 1
  2107 sh       CALL  wait4(0xffffffff,0xbfbfce34,0x3,0)
  2107 sh       RET   wait4 -1 errno 10 No child processes
  2107 sh       CALL  __stat13(0x80b0424,0xbfbfce38)
  2107 sh       NAMI  "/var/mail/woods"
  2107 sh       RET   __stat13 0
  2107 sh       CALL  write(0x2,0x80b4000,0x2)
  2107 sh       GIO   fd 2 wrote 2 bytes
       "$ "
  2107 sh       RET   write 2
  2107 sh       CALL  read(0,0x80aff40,0x3ff)
  2107 sh       GIO   fd 0 read 1 bytes
       "
       "
  2107 sh       RET   read 1
  2107 sh       CALL  wait4(0xffffffff,0xbfbfce34,0x3,0)
  2107 sh       RET   wait4 -1 errno 10 No child processes
  2107 sh       CALL  __stat13(0x80b0424,0xbfbfce38)
  2107 sh       NAMI  "/var/mail/woods"
  2107 sh       RET   __stat13 0
  2107 sh       CALL  write(0x2,0x80b4000,0x2)
  2107 sh       GIO   fd 2 wrote 2 bytes
       "$ "
  2107 sh       RET   write 2

> It doesn't use a cursor right command like tcsh does, but it does nearly
> the same thing by outputting 80 spaces to force a wrap and linefeed.

You must have had command-line editing turned on then.  Indeed as I've
already said the problem appears *only* when command-line editing is
turned on, and thus the only difference is(are) the ioctl(s).

Here's a complete trace as above but with command-line editing turned on
with "set -o emacs".  Note the ioctl(TIOCSETAW) after the <CR> is read,
and the ioctl(TIOCGETA) and ioctl(TIOCSETAW) again just after the prompt
is printed and before the next read() is done.  The two TIOCSETAW's are
the "pair" I was referring to:

  4163 sh       CALL  read(0,0xbfbfce3b,0x1)
  4163 sh       GIO   fd 0 read 1 bytes
       "
       "
  4163 sh       RET   read 1
  4163 sh       CALL  write(0x2,0x80be000,0x2)
  4163 sh       GIO   fd 2 wrote 2 bytes
       "\r
       "
  4163 sh       RET   write 2
  4163 sh       CALL  ioctl(0,TIOCSETAW,0x80b416c)
  4163 sh       RET   ioctl 0
  4163 sh       CALL  wait4(0xffffffff,0xbfbfce24,0x3,0)
  4163 sh       RET   wait4 -1 errno 10 No child processes
  4163 sh       CALL  __stat13(0x80b0424,0xbfbfce28)
  4163 sh       NAMI  "/var/mail/woods"
  4163 sh       RET   __stat13 0
  4163 sh       CALL  write(0x2,0x80be000,0x2)
  4163 sh       GIO   fd 2 wrote 2 bytes
       "$ "
  4163 sh       RET   write 2
  4163 sh       CALL  ioctl(0,TIOCGETA,0x80b41c4)
  4163 sh       RET   ioctl 0
  4163 sh       CALL  ioctl(0,TIOCSETAW,0x80b4198)
  4163 sh       RET   ioctl 0
  4163 sh       CALL  read(0,0xbfbfce3b,0x1)
  4163 sh       GIO   fd 0 read 1 bytes
       "
       "
  4163 sh       RET   read 1
  4163 sh       CALL  write(0x2,0x80be000,0x2)
  4163 sh       GIO   fd 2 wrote 2 bytes
       "\r
       "
  4163 sh       RET   write 2
  4163 sh       CALL  ioctl(0,TIOCSETAW,0x80b416c)
  4163 sh       RET   ioctl 0
  4163 sh       CALL  wait4(0xffffffff,0xbfbfce24,0x3,0)
  4163 sh       RET   wait4 -1 errno 10 No child processes
  4163 sh       CALL  __stat13(0x80b0424,0xbfbfce28)
  4163 sh       NAMI  "/var/mail/woods"
  4163 sh       RET   __stat13 0
  4163 sh       CALL  write(0x2,0x80be000,0x2)
  4163 sh       GIO   fd 2 wrote 2 bytes
       "$ "
  4163 sh       RET   write 2
  4163 sh       CALL  ioctl(0,TIOCGETA,0x80b41c4)
  4163 sh       RET   ioctl 0
  4163 sh       CALL  ioctl(0,TIOCSETAW,0x80b4198)
  4163 sh       RET   ioctl 0


-- 
							Greg A. Woods

+1 416 218-0098      VE3TCP      <gwoods@acm.org>     <woods@robohack.ca>
Planix, Inc. <woods@planix.com>;   Secrets of the Weird <woods@weird.com>