[comp.sys.sgi] HELP: Low level terminal I/O

mis@APL.STANFORD.EDU (Misha Pavel) (07/21/89)

I have a problem that probably reflects more my
understanding of the low-level I/O than its inherent difficulty,
but I am not shure how to proceed.

I need to  read a tty line and return  immediately 
even if there is nothing  in the system buffer for that tty.
To do that I set the terminal in raw mode with the folowing
settings:

  term.c_iflag = IGNBRK;
  term.c_oflag = 0;
  term.c_lflag = 0;
  term.c_cflag = B9600 | CS8 | CREAD | PARENB | PARODD;
  term.c_cc[VMIN] = 1;
  term.c_cc[VTIME] = 0;

I was hoping that the term.c_cc[VTIME] = 0 would do the job.
But the system seems to  be still waiting for at least one char.

Is there any way to look at the system buffer and or return
from read() when no input was generated?

(Because of the real-time application I cannot afford to
run a separate terminal process on my IRIS-2400).

Any ideas?

Thanks in advance

Misha Pavel <mis@psych.Stanford.Edu>

moss@BRL.MIL ("Gary S. Moss", VLD/VMB) (07/28/89)

[Misha Pavel <mis@psych.Stanford.Edu> writes]
< Is there any way to look at the system buffer and or return
< from read() when no input was generated?

Probably the better way to go, rather than mucking around with the terminal
settings, is to use fcntl() as follows:

Where fd is a file descriptor returned from creat(), open(), dup(),
	fcntl(), or pipe().

#include <fcntl.h>

	(void) fcntl( fd, F_SETFL, O_NDELAY );

	/* to check the buffer... */
	if( read( fd, bufptr, bytes ) == 0 )
		; /* nothing to read */

To be portable to BSD systems, the following is more correct:

	got = read( fd, bufptr, bytes);

#ifdef BSD
	if( got == -1 && errno == EWOULDBLOCK )
		got = 0; /* act like System V */
#endif
	if( got == 0 )
		; /* nothing to read */

Do a 'man fcntl' for more info.
-moss
	

vjs@rhyolite.wpd.sgi.com (Vernon Schryver) (07/29/89)

In article <8907201857.aa12017@SMOKE.BRL.MIL>, mis@APL.STANFORD.EDU (Misha Pavel) writes:
> ...
> I was hoping that the term.c_cc[VTIME] = 0 would do the job.
> But the system seems to  be still waiting for at least one char.
> 
> Is there any way to look at the system buffer and or return
> from read() when no input was generated?
> ...
> 
> Misha Pavel <mis@psych.Stanford.Edu>

System V has a confusing notion of VTIME/VMIN.  It likes to wait for at
least one character.  I seem to recall that there is a combination which
does not wait, but there is no reason to suffer the pain of reading the
SVID (the only place I know where it is half way documented), or of reading
either SGI's stty_ld.c or the standard SVR3 line discipline code.

You could use the FIONNBIO ioctl(2) on an FD that is a tty or socket.

I would use select(2) instead.  Select(2) has always worked on streams
(tty's) and sockets.  It allows fine grain timeouts and simultaneous
polling of lots of FD's, for reading and/or writing.  It now works on
everything.  Now is 3.2, or maybe some version of 3.1.  It was added to
lboot(1), cdev[], etc. seemingly a long time ago.


Vernon Schryver
Silicon Graphics
vjs@sgi.com

jmb@patton.sgi.com (Jim Barton) (07/31/89)

In article <8907201857.aa12017@SMOKE.BRL.MIL>, mis@APL.STANFORD.EDU (Misha Pavel) writes:
...
> I need to  read a tty line and return  immediately 
> even if there is nothing  in the system buffer for that tty.
> To do that I set the terminal in raw mode with the folowing
> settings:
> 
>   term.c_iflag = IGNBRK;
>   term.c_oflag = 0;
>   term.c_lflag = 0;
>   term.c_cflag = B9600 | CS8 | CREAD | PARENB | PARODD;
>   term.c_cc[VMIN] = 1;
>   term.c_cc[VTIME] = 0;
> 
...
> Misha Pavel <mis@psych.Stanford.Edu>

Several others have posted valid solutions to this problem, but there is one
valid one which is portable (although somewhat ugly) and used by many
programs out there.

You have the VMIN and VTIME settings backwards.  The proper way to do this is
to set:

	term.c_cc[VMIN] = 0;
	term.c_cc[VTIME] = 1;

This tells the terminal driver to return if no characters have arrived in the
last 1/10 second, thus your program would sleep for 1/10 of a second each
time it polled the variable.  The proper way to read a single character is
then to perform the read as:

	if (read(fd, &c, 1) == 1)
		/* got a character */
		...

This style of handling the terminal is oriented towards efficient yet
responsive data passing.  For instance, let's say I write a program which
reads from the tty line and writes to a file (or a pty, for instance).  In
that case, I could set up a small buffer to take either a maximum number
of characters or time out after a certain point:

	term.c_cc[VMIN] = 0;
	term.c_cc[VTIME] = 2;
	...
	while ((count = read(ifd, buf, 10) > 0)
		write(ofd, buf, count);

This makes for high throughput while still insuring that single characters
make it through quickly.  It is useless in real-time applications.  As
Vernon and Mike pointed out, IRIX is fairly rich in ways to do this operation
while still being real-time.

-- Jim Barton
Silicon Graphics Computer Systems    "UNIX: Live Free Or Die!"
jmb@sgi.sgi.com, sgi!jmb@decwrl.dec.com, ...{decwrl,sun}!sgi!jmb

moss@BRL.MIL ("Gary S. Moss", VLD/VMB) (08/01/89)

[Jim Barton writes]
< Several others have posted valid solutions to this problem, but there is one
< valid one which is portable (although somewhat ugly) and used by many
< programs out there.
<
< You have the VMIN and VTIME settings backwards.  The proper way to do
< this is to set:
< 
<	term.c_cc[VMIN] = 0;
< 	term.c_cc[VTIME] = 1;

I don't believe that this is portable, except on System V based machines.
It will work on some BSD-based systems, but not all, especially older
implementations.  For example, here is an excerpt from the termio(4V) manual
page on my Sun (Release 3.2):

"    3.   The MIN and TIME values supported by other implementations
          can be set, but this has no effect on the terminal driver.
          The driver behaves as if MIN were 1 and TIME were 0."

Basic BSD systems use the sgtty structures rather than termio; though later
versions have some compatibility with System V built in, you may not get
the behavior you want.

-moss

jmb@patton.sgi.com (Jim Barton) (08/02/89)

In article <8908011000.aa22873@VMB.BRL.MIL>, moss@BRL.MIL ("Gary S. Moss", VLD/VMB) writes:
> [Jim Barton writes]
...
> I don't believe that this is portable, except on System V based machines.
> It will work on some BSD-based systems, but not all, especially older
> implementations.  For example, here is an excerpt from the termio(4V) manual
> page on my Sun (Release 3.2):
...
> -moss

Sorry, I meant portable to other System V machines.  Of course this is
nonsense on non-conforming implementations.  Bezerkely has better ways
to do this, and IRIX has picked those up.

-- Jim Barton
Silicon Graphics Computer Systems    "UNIX: Live Free Or Die!"
jmb@sgi.sgi.com, sgi!jmb@decwrl.dec.com, ...{decwrl,sun}!sgi!jmb