summaryrefslogtreecommitdiffstats
path: root/sys/kern/tty.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/tty.c')
-rw-r--r--sys/kern/tty.c25
1 files changed, 21 insertions, 4 deletions
diff --git a/sys/kern/tty.c b/sys/kern/tty.c
index b5b5f67..1df2b4a 100644
--- a/sys/kern/tty.c
+++ b/sys/kern/tty.c
@@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)tty.c 8.8 (Berkeley) 1/21/94
- * $Id: tty.c,v 1.44 1995/05/07 23:53:36 ache Exp $
+ * $Id: tty.c,v 1.45.2.3 1995/06/05 01:23:10 davidg Exp $
*/
#include "snp.h"
@@ -1037,7 +1037,25 @@ ttywait(tp)
while ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&
(ISSET(tp->t_state, TS_CARR_ON) || ISSET(tp->t_cflag, CLOCAL))
&& tp->t_oproc) {
- (*tp->t_oproc)(tp);
+ /*
+ * XXX the call to t_oproc() can cause livelock.
+ *
+ * If two processes wait for output to drain from the same
+ * tty, and the amount of output to drain is <= tp->t_lowat,
+ * then the processes will take turns uselessly waking each
+ * other up until the output drains, all running at spltty()
+ * so that even interrupts on other terminals are blocked.
+ *
+ * Skipping the call when TS_BUSY is set avoids the problem
+ * for current drivers but isn't "right". There is no
+ * problem for ptys - we only get woken up when the output
+ * queue is actually reduced. Hardware ttys should be
+ * handled similarly. There would still be excessive
+ * wakeups for output below low water when we only care
+ * about output complete.
+ */
+ if (!ISSET(tp->t_state, TS_BUSY))
+ (*tp->t_oproc)(tp);
if ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) &&
(ISSET(tp->t_state, TS_CARR_ON) || ISSET(tp->t_cflag, CLOCAL))) {
SET(tp->t_state, TS_ASLEEP);
@@ -1812,8 +1830,7 @@ ovhiwat:
return (uio->uio_resid == cnt ? EWOULDBLOCK : 0);
}
SET(tp->t_state, TS_ASLEEP);
- error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, "ttywri",
- tp->t_timeout);
+ error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, "ttywri", tp->t_timeout);
splx(s);
if (error)
goto out;
OpenPOWER on IntegriCloud