Xref: utzoo comp.unix.questions:23994 comp.unix.wizards:23035 comp.unix.xenix:12518 comp.unix.i386:7146 Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!know!zaphod.mps.ohio-state.edu!sdd.hp.com!decwrl!uunet!comtst!mdv From: mdv@comtst.UUCP (Mike Verstegen) Newsgroups: comp.unix.questions,comp.unix.wizards,comp.unix.xenix,comp.unix.i386 Subject: Re: TTY line discipline Message-ID: <139@comtst.UUCP> Date: 23 Jul 90 15:40:52 GMT References: <2026@beam.UUCP> Followup-To: poster Organization: Domain Systems Inc., WPB, FL Lines: 156 In article <2026@beam.UUCP>, lucio@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@domain.com