Re: TTY lockup's (Kernel V2.0.32)

Bill Hawes (whawes@star.net)
Sat, 13 Dec 1997 11:02:39 -0500


This is a multi-part message in MIME format.
--------------C05F606B5616CF1FE14A85D2
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Karl Vogel wrote:
> I would greatly appreciate it if you can find this patch! The lockups are
> occuring way less than before Kernel V2.0.31 but they still occure
> regularly (ie 6-7 locked tty's after a weekend).

Hi Karl,
I've attached a back-ported patch for 2.0.32 n_tty.c that may help your
locked tty problem. The relevant changes are in the handling of the
throttle and unthrottle calls as the input buffer fills.

I've verified that it compiles and boots, but haven't tested beyond
that. Please let me know if it helps reduce the frequency of tty lockups
-- it's possible that there may be other causes, so this might be only a
partial solution.

Regards,
Bill
--------------C05F606B5616CF1FE14A85D2
Content-Type: text/plain; charset=us-ascii; name="ntty_32-patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="ntty_32-patch"

--- drivers/char/n_tty.c.old Thu Aug 7 12:34:37 1997
+++ drivers/char/n_tty.c Sat Dec 13 11:32:05 1997
@@ -52,7 +52,7 @@
* unthrottling the TTY driver. These watermarks are used for
* controlling the space in the read buffer.
*/
-#define TTY_THRESHOLD_THROTTLE (N_TTY_BUF_SIZE - 128)
+#define TTY_THRESHOLD_THROTTLE 128 /* now based on remaining room */
#define TTY_THRESHOLD_UNTHROTTLE 128

static inline void put_tty_queue(unsigned char c, struct tty_struct *tty)
@@ -64,20 +64,41 @@
}
}

+/*
+ * Check whether to call the driver.unthrottle function.
+ * We test the TTY_THROTTLED bit first so that it always
+ * indicates the current state.
+ */
+static void check_unthrottle(struct tty_struct * tty)
+{
+ if (clear_bit(TTY_THROTTLED, &tty->flags) && tty->driver.unthrottle)
+ tty->driver.unthrottle(tty);
+}
+
/*
- * Flush the input buffer
+ * Reset the read buffer counters, clear the flags,
+ * and make sure the driver is unthrottled. Called
+ * from n_tty_open() and n_tty_flush_buffer().
*/
-void n_tty_flush_buffer(struct tty_struct * tty)
+static void reset_buffer_flags(struct tty_struct *tty)
{
tty->read_head = tty->read_tail = tty->read_cnt = 0;
tty->canon_head = tty->canon_data = tty->erasing = 0;
memset(&tty->read_flags, 0, sizeof tty->read_flags);
-
+ check_unthrottle(tty);
+}
+
+/*
+ * Flush the input buffer
+ */
+void n_tty_flush_buffer(struct tty_struct * tty)
+{
+ /* clear everything and unthrottle the driver */
+ reset_buffer_flags(tty);
+
if (!tty->link)
return;

- if (tty->driver.unthrottle)
- (tty->driver.unthrottle)(tty);
if (tty->link->packet) {
tty->ctrl_status |= TIOCPKT_FLUSHREAD;
wake_up_interruptible(&tty->link->read_wait);
@@ -438,7 +459,7 @@
return;
}
}
- if (L_ICANON(tty)) {
+ if (tty->icanon) {
if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
(c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
eraser(c, tty);
@@ -541,11 +562,29 @@
put_tty_queue(c, tty);
}

+static int n_tty_receive_room(struct tty_struct *tty)
+{
+ int left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
+
+ /*
+ * If we are doing input canonicalization, and there are no
+ * pending newlines, let characters through without limit, so
+ * that erase characters will be handled. Other excess
+ * characters will be beeped.
+ */
+ if (tty->icanon && !tty->canon_data)
+ return N_TTY_BUF_SIZE;
+
+ if (left > 0)
+ return left;
+ return 0;
+}
+
static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
char *fp, int count)
{
const unsigned char *p;
- char *f, flags = 0;
+ char *f, flags = TTY_NORMAL;
int i;

if (!tty->read_buf)
@@ -600,28 +639,17 @@
wake_up_interruptible(&tty->read_wait);
}

- if ((tty->read_cnt >= TTY_THRESHOLD_THROTTLE) &&
- tty->driver.throttle &&
- !set_bit(TTY_THROTTLED, &tty->flags))
- tty->driver.throttle(tty);
-}
-
-static int n_tty_receive_room(struct tty_struct *tty)
-{
- int left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
-
- /*
- * If we are doing input canonicalization, and there are no
- * pending newlines, let characters through without limit, so
- * that erase characters will be handled. Other excess
- * characters will be beeped.
+ /*
+ * Check the remaining room for the input canonicalization
+ * mode. We don't want to throttle the driver if we're in
+ * canonical mode and don't have a newline yet!
*/
- if (tty->icanon && !tty->canon_data)
- return N_TTY_BUF_SIZE;
-
- if (left > 0)
- return left;
- return 0;
+ if (n_tty_receive_room(tty) < TTY_THRESHOLD_THROTTLE) {
+ /* check TTY_THROTTLED first so it indicates our state */
+ if (!set_bit(TTY_THROTTLED, &tty->flags) &&
+ tty->driver.throttle)
+ tty->driver.throttle(tty);
+ }
}

int is_ignored(int sig)
@@ -711,10 +739,8 @@
return -ENOMEM;
}
memset(tty->read_buf, 0, N_TTY_BUF_SIZE);
- tty->read_head = tty->read_tail = tty->read_cnt = 0;
- tty->canon_head = tty->canon_data = tty->erasing = 0;
+ reset_buffer_flags(tty);
tty->column = 0;
- memset(tty->read_flags, 0, sizeof(tty->read_flags));
n_tty_set_termios(tty, 0);
tty->minimum_to_wake = 1;
tty->closing = 0;
@@ -723,7 +749,7 @@

static inline int input_available_p(struct tty_struct *tty, int amt)
{
- if (L_ICANON(tty)) {
+ if (tty->icanon) {
if (tty->canon_data)
return 1;
} else if (tty->read_cnt >= (amt ? amt : 1))
@@ -792,7 +818,7 @@
}
}

- if (L_ICANON(tty)) {
+ if (tty->icanon) {
minimum = time = 0;
current->timeout = (unsigned long) -1;
} else {
@@ -819,9 +845,10 @@
while (1) {
/* First test for status change. */
if (tty->packet && tty->link->ctrl_status) {
- if (b != buf)
+ if (b != buf || !nr)
break;
put_user(tty->link->ctrl_status, b++);
+ nr--;
tty->link->ctrl_status = 0;
break;
}
@@ -857,7 +884,7 @@
current->state = TASK_RUNNING;

/* Deal with packet mode. */
- if (tty->packet && b == buf) {
+ if (tty->packet && b == buf && nr) {
put_user(TIOCPKT_DATA, b++);
nr--;
}
@@ -901,12 +928,15 @@
}

/* If there is enough space in the read buffer now, let the
- low-level driver know. */
- if (tty->driver.unthrottle &&
- (tty->read_cnt <= TTY_THRESHOLD_UNTHROTTLE)
- && clear_bit(TTY_THROTTLED, &tty->flags))
- tty->driver.unthrottle(tty);
-
+ * low-level driver know. We use n_tty_chars_in_buffer() to
+ * check the buffer, as it now knows about canonical mode.
+ * Otherwise, if the driver is throttled and the line is
+ * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
+ * we won't get any more characters.
+ */
+ if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE)
+ check_unthrottle(tty);
+
if (b - buf >= minimum || !nr)
break;
if (time)
@@ -966,6 +996,10 @@
tty->driver.flush_chars(tty);
} else {
c = tty->driver.write(tty, 1, b, nr);
+ if (c < 0) {
+ retval = c;
+ break;
+ }
b += c;
nr -= c;
}

--------------C05F606B5616CF1FE14A85D2--