lucio@beam.UUCP (Lucio de Re) (07/16/90)
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. Unfortunately for us, we require both unprocessed input and timeouts; we could compromise and use alarm calls to provide the timeout, but the cost in system resources seems prohibitive (and is a kludge). I had occasion to discuss this personally with a gentleman from SCO, who was at the time guest at an exhibition, and he felt that this behaviour should not be the case. We subsequently tested the behaviour on a machine running Intel Unix System V Version 3.2.2 (albeit an early BellTech release) and found the same effect. A number of possibilities arise: (a) a fix to the existing line discipline may have removed the problem in kernels more recent than the ones we are using; (b) what we find problematic may be intentional and we may have to resort to a different line discipline to cater for our needs; (c) what we want may be impossible for reasons that we have overlooked. To the NET I ask: (i) is the behaviour I described intentional or erroneous? (ii) Whether or not it is intentional, is it possible to add line disciplines to an existing device driver without requiring the source for the device driver (said SCO gentleman feels it has been done)? (iii) where can one find guidelines or alternative device drivers for the kernels we use that will make it possible for our requirements to be met? (iv) if it should be imperative that we use alarm calls to satisfy our requirements, what would be the underlying cost in terms of kernel and other resources? (To expand here, we would have to issue an alarm call whenever one or more characters are input; a later alarm call would cancel the previous one, nevertheless we could land up with a ridiculous amount of overheads.) Thanks very much to all who can provide us with some direction on these points. Lucio de Re (lucio@proxima.UUCP).
guy@auspex.auspex.com (Guy Harris) (07/22/90)
>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 */ Yes, but so does turning ICANON and ISIG off; you can leave VINTR and VQUIT alone if you turn ISIG off, and leave VERASE and VKIL alone if you turn ICANON off. Also, "seem to" is the relevant part. In the vanilla S5R[123] driver, setting a control character to 255 sets it to 255, rather than disabling it. If the characters coming in are 7-bit characters (e.g., if ISTRIP is set, or if the character size is 7 bits), it does, in effect, disable it; however, 255 is the code in ISO Latin Alphabet #1 for the "y with a diaresis" character, and if the characters coming in are 8-bit ISO Latin 1 characters, somebody might type that character.... (In S5R4, I think you set the character to 0 to disable it, and that *really* disables it - i.e., a NUL coming in doesn't get treated as a special character.) > 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. Those settings shouldn't cause "null characters", if by that you mean NUL characters, i.e. a character with the code value 0, to do anything different from any other characters (well, not counting ^S and ^Q, which you haven't disabled). >As a result, the null is swallowed by the line discipline >and cannot be received. That's a bug, for sure. If it's intentional, the bug is that the person whose intent it was (i.e., the person who introduced that bug into the tty driver) doesn't understnand the "termio" interface....
mdv@comtst.UUCP (Mike Verstegen) (07/23/90)
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
guy@auspex.auspex.com (Guy Harris) (07/25/90)
>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! All correct, except that if MIN is 0, TIME *is* a timeout for the initial character. However, the problem he's having is that his system does *not* appear to be completely correctly implementing the above semantics! Instead, it appears to be swallowing NUL characters for some reason.