TTY line discipline
Mike Verstegen
mdv at comtst.UUCP
Tue Jul 24 01:40:52 AEST 1990
In article <2026 at beam.UUCP>, lucio at beam.UUCP (Lucio de Re) writes:
>
> We first encountered this problem in Xenix (System V, Version 2.3.2), but
> experimentation showed that it occurs in Intel Unix System V, Release 3.2.2
> as well.
>
> The symptoms are as follows: using the standard (and only?) line
> discipline, the following termio settings had a strange side effect:
>
> n_ctrl.c_iflag &= ~(INLCR | IGNCR | ICRNL | IUCLC );
> n_ctrl.c_iflag |= IXOFF;
> n_ctrl.c_lflag &= ~(ICANON | ISIG);
> n_ctrl.c_cc[VINTR] = 255; /* these seem to disable ... */
> n_ctrl.c_cc[VQUIT] = 255; /* ... */
> n_ctrl.c_cc[VERASE] = 255; /* ... */
> n_ctrl.c_cc[VKILL] = 255; /* ... the relevant function */
> n_ctrl.c_cc[VMIN] = 1; /* character count */
> n_ctrl.c_cc[VTIME] = 50; /* time limit */
>
> that is, a null character on input would trigger the timeout
> condition. As a result, the null is swallowed by the line discipline
> and cannot be received. If the timeout is set to zero, the problem
> does not arise, and nulls are accepted as normal characters.
>
[ Remainder of post deleted ]
We have been using a set up similar to this for quite a while (7 years) and
have learned a few things about using async line to do what it appears that
you are trying to do.
DISCLAIMER:
I've never read the source to any kernel code and the following
come only from public doucmentataion and a lot of experience with different
combinations. Corrections from more knowledgable sources welcome.
Once signal processing is turned off with ~SIG, the input characters
are not checked for the INTR, SWITCH, and QUIT characters. Similarly,
when cannonical is turned off with ~ICANON, no checks are made for the
ERASE and KILL characters. the input characters are now unchecked and
reads will be satified directly from the input buffer subject to the
limitation that no read will be satisfied until
1) At least MIN characters have been received AND
2) The timeout value TIME has expired ***BETWEEN CHARACTERS***
Note that there is no timeout for the initial character. This is important!
For our application, we have written a module that uses some internal buffering
and signals, in conjuntion with VMIN and VTIME settings to provide efficient
communications. A code fragment follows which implements this strategy:
/*****************************************************************************/
/* eread_time -- efficient reading mechanism for single characters from a
tty port. This function is intended to be a replacement for the current
read_time which does a read call for each individual character.
This function uses an internal buffer and reads a block of characters
which are buffered (internally to the module) and returned with each
successive call. This approach significantly decreases the number of
read calls made, and the corresponding overhead associated with kernel
calls is therefore minimized.
Input: fd file descriptor of a currently opened file (see Note)
timeout the time (in seconds) to wait for the character
c pointer to the location of the read character
Return: SUCCESS if a character was available and c is set to that char
FAILURE if a character was not available and c is undefined
Note: Prior to the first call to eread_time, an ioctl call must be
made to turn off the cannonical processor, set VMIN to 10 (this
value may require tuning) and VMIN to BUFSIZE.
History:Mike Verstegen 10/26/87 -- rewritten from scratch
*/
#define BUFSIZE 64
eread_time(fd, timeout, c)
int fd;
int timeout;
char *c;
{
static
char buf[BUFSIZE];
static
char *bufend = buf; /* point to the last valid char in the buffer */
static
char *outptr = buf + 1; /* points to the next char to return */
/* this initialization force a read first time
through */
unsigned leftover; /* time leftover on the timer */
int ret; /* return value from read call */
sig_t (*save_sig)(); /* temporary variable for saving current signal
handler */
sig_t null_fn(); /* declaration for null function defined below*/
if (outptr <= bufend) /* can current request be satisfied from bufr?*/
{
*c = *outptr++;
return(SUCCESS);
}
else /* empty buffer, do a real read */
{
save_sig = signal (SIGALRM, null_fn); /* save current signal handler*/
leftover = alarm ((unsigned) timeout); /* and timer */
ret = read(fd, buf, (unsigned)BUFSIZE); /* get the characters */
(void)signal(SIGALRM, save_sig); /* restore signal handler */
(void)alarm(leftover); /* and timer */
if (ret < 0) /* did the read succeed ? */
{
if (errno != EINTR) /* if not an interrupt call...*/
perror("eread_time"); /* we've got a problem */
return (FAILURE); /* otherwise, just a timeout */
}
else
{
outptr = buf; /* at beginning of buffer */
bufend = buf + ret - 1; /* end offset by how many read*/
*c = *outptr++; /* the first char is returned */
}
}
return (SUCCESS);
}
sig_t /* null functiof for signal */
null_fn() {}
#ifdef TEST
/*****************************************************************************/
/* a short test section to read from the standard input. To work successfully,
the user must type "stty -icanon eol ^c eof ^c" to get in to cbreak mode.
*/
main ()
{
char c;
while (1)
{
if (eread_time(0, 2, &c) == FAILURE)
printf ("FAIL\n");
else
printf ("OK -- '%c'\n", c);
}
exit (1);
}
#endif
------------------------- End of code fragment ---------------------------
I hope this is helpful. You should also refer to termio(7) of you Unix manuals
for a more detailed discussion of tty flags usage.
--
Mike Verstegen
..!uunet!comtst!mdv
mdv at domain.com
More information about the Comp.unix.wizards
mailing list