summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorbde <bde@FreeBSD.org>1995-07-30 12:39:42 +0000
committerbde <bde@FreeBSD.org>1995-07-30 12:39:42 +0000
commit817ff6d360efa18b42436d4ee46b8bee38315b17 (patch)
tree5d0eae0751ab4d6891b2edb481b05df4a958f90d /sys
parent117bc8a1c40f1d6d82ceb9154a481aac2780d463 (diff)
downloadFreeBSD-src-817ff6d360efa18b42436d4ee46b8bee38315b17.zip
FreeBSD-src-817ff6d360efa18b42436d4ee46b8bee38315b17.tar.gz
Split TS_ASLEEP (sleep on output [below low water])into TS_SO_OLOWAT (sleep
on output below low water) and TS_SO_OCOMPLETE (sleep on output complete). Most of the support for this has already been committed. Drivers should call ttwwakeup() to handle wakeups whenever output is below low water (and some output event causes this condition to be checked) or TS_BUSY is cleared. tty.c: Fix the livelock in ttywait() properly by sleeping on output complete, not on output below low water. Use ttwwakeup() instead of separate select and output wakeups for all wakeups of writers. Add wakeups of writers for output flushes and carrier/clocal transitions. Don't go to sleep in ttycheckoutq() if ttstart() reduces the queue to below low water. Use the timeout built into tsleep() in ttycheckoutq(). Optimize the select wakeup in ttwwakeup(). It seems reasonable to know too much about the internals of tp->t_wsel now that the knowledge is localised in tty.c.
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/tty.c61
-rw-r--r--sys/sys/tty.h9
2 files changed, 31 insertions, 39 deletions
diff --git a/sys/kern/tty.c b/sys/kern/tty.c
index c59aaca..0df9786 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));
}
}
diff --git a/sys/sys/tty.h b/sys/sys/tty.h
index c3843f4..121926f 100644
--- a/sys/sys/tty.h
+++ b/sys/sys/tty.h
@@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)tty.h 8.6 (Berkeley) 1/21/94
- * $Id: tty.h,v 1.24 1995/07/22 16:45:22 bde Exp $
+ * $Id: tty.h,v 1.25 1995/07/29 13:40:13 bde Exp $
*/
#ifndef _SYS_TTY_H_
@@ -130,7 +130,7 @@ struct tty {
#endif
/* These flags are kept in t_state. */
-#define TS_ASLEEP 0x00001 /* Process waiting for tty. */
+#define TS_SO_OLOWAT 0x00001 /* Wake up when output <= low water. */
#define TS_ASYNC 0x00002 /* Tty in async I/O mode. */
#define TS_BUSY 0x00004 /* Draining output. */
#define TS_CARR_ON 0x00008 /* Carrier is present. */
@@ -161,6 +161,8 @@ struct tty {
*/
#define TS_CAN_BYPASS_L_RINT 0x20000 /* device in "raw" mode */
+/* Extras. */
+#define TS_SO_OCOMPLETE 0x080000 /* Wake up when output completes. */
/* Character type information. */
#define ORDINARY 0
@@ -201,7 +203,8 @@ struct speedtab {
/* Unique sleep addresses. */
#define TSA_CARR_ON(tp) ((void *)&(tp)->t_rawq) /* XXX overloaded */
-#define TSA_OLOWAT(tp) ((void *)&(tp)->t_outq) /* XXX overloaded */
+#define TSA_OCOMPLETE(tp) ((void *)&(tp)->t_outq.c_cl)
+#define TSA_OLOWAT(tp) ((void *)&(tp)->t_outq)
#define TSA_PTC_READ(tp) ((void *)&(tp)->t_outq.c_cf)
#define TSA_PTC_WRITE(tp) ((void *)&(tp)->t_rawq.c_cl)
#define TSA_PTS_READ(tp) ((void *)&(tp)->t_canq)
OpenPOWER on IntegriCloud