Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 27 Aug 2008 16:48:16 GMT
From:      Ed Schouten <ed@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 148628 for review
Message-ID:  <200808271648.m7RGmG5d020293@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=148628

Change 148628 by ed@ed_dull on 2008/08/27 16:48:04

	Fix a deadlock in TTY's. Not a kernel deadlock, but a situation
	where a TTY could become useless.
	
	Because we now only have one contiguous input buffer, there is a
	way for us to fill up the input buffer without needing to go
	into the high watermark, namely when we are in canonical mode
	and type in as much data as possble.
	
	Change the TTY discipline code to only enter the high watermark
	when we can't store any more data *and* when we actually have
	data available for read(). This means we must also fix up
	rint_poll() to return something (1) when there isn't actually
	any place to make pts(4) consumers happy.

Affected files ...

.. //depot/projects/mpsafetty/sys/kern/tty_ttydisc.c#15 edit
.. //depot/projects/mpsafetty/sys/sys/ttydisc.h#5 edit

Differences ...

==== //depot/projects/mpsafetty/sys/kern/tty_ttydisc.c#15 (text+ko) ====

@@ -307,7 +307,6 @@
 ttydisc_read(struct tty *tp, struct uio *uio, int ioflag)
 {
 	int error;
-	size_t c;
 
 	tty_lock_assert(tp, MA_OWNED);
 
@@ -324,8 +323,8 @@
 	else
 		error = ttydisc_read_raw_interbyte_timer(tp, uio, ioflag);
 
-	c = ttyinq_bytesleft(&tp->t_inq);
-	if (c >= tp->t_inlow) {
+	if (ttyinq_bytesleft(&tp->t_inq) >= tp->t_inlow ||
+	    ttyinq_bytescanonicalized(&tp->t_inq) == 0) {
 		/* Unset the input watermark when we've got enough space. */
 		tty_hiwat_in_unblock(tp);
 	}
@@ -1003,7 +1002,20 @@
 print:
 	/* See if we can store this on the input queue. */
 	if (ttyinq_write_nofrag(&tp->t_inq, ob, ol, quote) != 0) {
-		/* We cannot. Enable the input watermark. */
+		if (CMP_FLAG(i, IMAXBEL))
+			ttyoutq_write_nofrag(&tp->t_outq, "\a", 1);
+
+		/*
+		 * Prevent a deadlock here. It may be possible that a
+		 * user has entered so much data, there is no data
+		 * available to read(), but the buffers are full anyway.
+		 *
+		 * Only enter the high watermark if the device driver
+		 * can actually transmit something.
+		 */
+		if (ttyinq_bytescanonicalized(&tp->t_inq) == 0)
+			return (0);
+
 		tty_hiwat_in_block(tp);
 		return (-1);
 	}

==== //depot/projects/mpsafetty/sys/sys/ttydisc.h#5 (text+ko) ====

@@ -84,10 +84,21 @@
 static __inline size_t
 ttydisc_rint_poll(struct tty *tp)
 {
+	size_t l;
 
 	tty_lock_assert(tp, MA_OWNED);
 
-	return ttyinq_bytesleft(&tp->t_inq);
+	/*
+	 * XXX: Still allow character input when there's no space in the
+	 * buffers, but we haven't entered the high watermark. This is
+	 * to allow backspace characters to be inserted when in
+	 * canonical mode.
+	 */
+	l = ttyinq_bytesleft(&tp->t_inq);
+	if (l == 0 && (tp->t_flags & TF_HIWAT_IN) == 0)
+		return (1);
+	
+	return (l);
 }
 
 static __inline size_t



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200808271648.m7RGmG5d020293>