summaryrefslogtreecommitdiff
path: root/sys/kern/tty.c
diff options
context:
space:
mode:
authorBruce Evans <bde@FreeBSD.org>1995-07-30 12:39:42 +0000
committerBruce Evans <bde@FreeBSD.org>1995-07-30 12:39:42 +0000
commitd7515ab5cfbd966405330355d231b2a2aa2e1ca7 (patch)
tree5d0eae0751ab4d6891b2edb481b05df4a958f90d /sys/kern/tty.c
parent70ad39a5d482ac0e715419ed3058559fe66cd069 (diff)
Notes
Diffstat (limited to 'sys/kern/tty.c')
-rw-r--r--sys/kern/tty.c61
1 files changed, 25 insertions, 36 deletions
diff --git a/sys/kern/tty.c b/sys/kern/tty.c
index c59aaca1c308..0df978656393 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.57 1995/07/22 16:45:07 bde Exp $
+ * $Id: tty.c,v 1.58 1995/07/29 13:35:33 bde Exp $
*/
/*-
@@ -833,6 +833,7 @@ ttioctl(tp, cmd, data, flag)
#endif
ttwakeup(tp);
}
+ ttwwakeup(tp);
tp->t_cflag = t->c_cflag;
tp->t_ispeed = t->c_ispeed;
tp->t_ospeed = t->c_ospeed;
@@ -961,7 +962,7 @@ ttioctl(tp, cmd, data, flag)
if (error)
return (error);
tp->t_timeout = *(int *)data * hz;
- wakeup(TSA_OLOWAT(tp));
+ ttwwakeup(tp);
break;
case TIOCGDRAINWAIT:
*(int *)data = tp->t_timeout / hz;
@@ -1055,30 +1056,13 @@ 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) {
- /*
- * 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);
+ (*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);
- error = ttysleep(tp, TSA_OLOWAT(tp), TTOPRI | PCATCH,
- "ttywai", tp->t_timeout);
+ SET(tp->t_state, TS_SO_OCOMPLETE);
+ error = ttysleep(tp, TSA_OCOMPLETE(tp),
+ TTOPRI | PCATCH, "ttywai",
+ tp->t_timeout);
if (error == EWOULDBLOCK)
error = EIO;
if (error)
@@ -1133,8 +1117,7 @@ ttyflush(tp, rw)
}
if (rw & FWRITE) {
FLUSHQ(&tp->t_outq);
- wakeup(TSA_OLOWAT(tp));
- selwakeup(&tp->t_wsel);
+ ttwwakeup(tp);
}
if ((rw & FREAD) &&
ISSET(tp->t_state, TS_TBLOCK) && tp->t_rawq.c_cc < TTYHOG/5) {
@@ -1294,6 +1277,7 @@ ttymodem(tp, flag)
*/
SET(tp->t_state, TS_CARR_ON);
ttwakeup(tp);
+ ttwwakeup(tp);
}
return (1);
}
@@ -1640,14 +1624,14 @@ ttycheckoutq(tp, wait)
if (tp->t_outq.c_cc > hiwat + 200)
while (tp->t_outq.c_cc > hiwat) {
ttstart(tp);
+ if (tp->t_outq.c_cc <= hiwat)
+ break;
if (wait == 0 || curproc->p_siglist != oldsig) {
splx(s);
return (0);
}
- timeout((void (*)__P((void *)))wakeup,
- (void *)&tp->t_outq, hz);
- SET(tp->t_state, TS_ASLEEP);
- (void) tsleep(TSA_OLOWAT(tp), PZERO - 1, "ttoutq", 0);
+ SET(tp->t_state, TS_SO_OLOWAT);
+ tsleep(TSA_OLOWAT(tp), PZERO - 1, "ttoutq", hz);
}
splx(s);
return (1);
@@ -1838,7 +1822,7 @@ ovhiwat:
uio->uio_resid += cc;
return (uio->uio_resid == cnt ? EWOULDBLOCK : 0);
}
- SET(tp->t_state, TS_ASLEEP);
+ SET(tp->t_state, TS_SO_OLOWAT);
error = ttysleep(tp, TSA_OLOWAT(tp), TTOPRI | PCATCH, "ttywri",
tp->t_timeout);
splx(s);
@@ -2038,12 +2022,17 @@ ttwwakeup(tp)
register struct tty *tp;
{
- if (tp->t_outq.c_cc <= tp->t_lowat) {
- if (tp->t_state & TS_ASLEEP) {
- tp->t_state &= ~TS_ASLEEP;
- wakeup(TSA_OLOWAT(tp));
- }
+ if (tp->t_wsel.si_pid != 0 && tp->t_outq.c_cc <= tp->t_lowat)
selwakeup(&tp->t_wsel);
+ if (ISSET(tp->t_state, TS_BUSY | TS_SO_OCOMPLETE) ==
+ TS_SO_OCOMPLETE && tp->t_outq.c_cc == 0) {
+ CLR(tp->t_state, TS_SO_OCOMPLETE);
+ wakeup(TSA_OCOMPLETE(tp));
+ }
+ if (ISSET(tp->t_state, TS_SO_OLOWAT) &&
+ tp->t_outq.c_cc <= tp->t_lowat) {
+ CLR(tp->t_state, TS_SO_OLOWAT);
+ wakeup(TSA_OLOWAT(tp));
}
}