summaryrefslogtreecommitdiff
path: root/sys/kern/tty.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/tty.c')
-rw-r--r--sys/kern/tty.c545
1 files changed, 295 insertions, 250 deletions
diff --git a/sys/kern/tty.c b/sys/kern/tty.c
index 519b910ccfdb..146aa1545efe 100644
--- a/sys/kern/tty.c
+++ b/sys/kern/tty.c
@@ -32,7 +32,22 @@
* SUCH DAMAGE.
*
* from: @(#)tty.c 7.44 (Berkeley) 5/28/91
- * $Id: tty.c,v 1.19.2.1 1994/03/24 08:19:44 rgrimes Exp $
+ * $Id: tty.c,v 1.32 1994/05/30 21:53:17 ache Exp $
+ */
+
+/*-
+ * TODO:
+ * o Fix races for sending the start char in ttyflush().
+ * o Handle inter-byte timeout for "MIN > 0, TIME > 0" in ttselect().
+ * With luck, there will be MIN chars before select() returns().
+ * o Handle CLOCAL consistently for ptys. Perhaps disallow setting it.
+ * o Don't allow input in TS_ZOMBIE case. It would be visible through
+ * FIONREAD.
+ * o Do the new sio locking stuff here and use it to avoid special
+ * case for EXTPROC?
+ * o Lock PENDIN too?
+ * o Move EXTPROC and/or PENDIN to t_state?
+ * o Wrap most of ttioctl in spltty/splx.
*/
#include "param.h"
@@ -47,6 +62,7 @@
#include "dkstat.h"
#include "uio.h"
#include "kernel.h"
+#include "malloc.h"
#include "vnode.h"
#include "syslog.h"
#include "signalvar.h"
@@ -64,11 +80,12 @@
#define I_LOW_WATER ((TTYHOG - 2 * 256) * 7 / 8) /* XXX */
/* XXX RB_LEN() is too slow. */
-#define INPUT_LEN(tp) (RB_LEN(&(tp)->t_can) + RB_LEN(&(tp)->t_raw))
+#define INPUT_LEN(tp) (RB_LEN((tp)->t_can) + RB_LEN((tp)->t_raw))
#undef MAX_INPUT /* XXX wrong in <sys/syslimits.h> */
#define MAX_INPUT TTYHOG
static int proc_compare __P((struct proc *p1, struct proc *p2));
+static int ttnread(struct tty *tp);
static void ttyblock __P((struct tty *tp));
static void ttyecho __P((int c, struct tty *tp));
static int ttyoutput __P((int c, register struct tty *tp));
@@ -79,14 +96,6 @@ static void ttyrub __P((int c, struct tty *tp));
static void ttyrubo __P((struct tty *tp, int cnt));
static void ttyunblock __P((struct tty *tp));
-/* symbolic sleep message strings */
-const char ttyin[] = "ttyin";
-const char ttyout[] = "ttyout";
-const char ttopen[] = "ttyopn";
-const char ttclos[] = "ttycls";
-const char ttybg[] = "ttybg";
-const char ttybuf[] = "ttybuf";
-
/*
* Table giving parity for characters and indicating
* character classes to tty driver. The 8th bit
@@ -172,11 +181,19 @@ extern int nldisp;
(c) == cc[VEOL] || (c) == cc[VEOL2]) && (c) != _POSIX_VDISABLE)
void
+termioschars(t)
+ struct termios *t;
+{
+
+ bcopy(ttydefchars, t->c_cc, sizeof t->c_cc);
+}
+
+void
ttychars(tp)
struct tty *tp;
{
- bcopy(ttydefchars, tp->t_cc, sizeof(ttydefchars));
+ termioschars(&tp->t_termios);
}
/*
@@ -202,36 +219,18 @@ ttywait(tp)
{
int error = 0, s = spltty();
- while ((RB_LEN(&tp->t_out) || tp->t_state&TS_BUSY) &&
- (tp->t_state&TS_CARR_ON || tp->t_cflag&CLOCAL) &&
- tp->t_oproc) {
- /*
- * XXX temporary fix for deadlock.
- *
- * If two processes wait for output to drain from the same
- * tty, and the amount of output to drain is > 0 and
- * <= tp->t_lowat, then the processes will take turns
- * uselessly waking each other up until the output drains,
- * with cpl higher than spltty() throughout.
- *
- * The sleep address and TS_ASLEEP flag ought to be different
- * for the different events (output done) and (output almost
- * done).
- */
- tp->t_lowat = 0;
-
+ while ((RB_LEN(tp->t_out) || tp->t_state&TS_BUSY) &&
+ CAN_DO_IO(tp) && tp->t_oproc) {
(*tp->t_oproc)(tp);
- if ((RB_LEN(&tp->t_out) || tp->t_state&TS_BUSY) &&
- (tp->t_state&TS_CARR_ON || tp->t_cflag&CLOCAL)) {
- tp->t_state |= TS_ASLEEP;
- if (error = ttysleep(tp, (caddr_t)&tp->t_out,
+ if ((RB_LEN(tp->t_out) || tp->t_state&TS_BUSY) &&
+ CAN_DO_IO(tp)) {
+ tp->t_state |= TS_SO_OCOMPLETE;
+ if (error = ttysleep(tp, TSA_OCOMPLETE(tp),
TTOPRI | PCATCH, "ttywai", 0))
break;
} else
break;
}
- if (tp->t_lowat == 0)
- ttsetwater(tp);
splx(s);
return (error);
}
@@ -257,21 +256,17 @@ ttyflush(tp, rw)
tp->t_state &= ~TS_TTSTOP;
(*cdevsw[major(tp->t_dev)].d_stop)(tp, rw);
if (rw & FREAD) {
- flushq(&tp->t_can);
- flushq(&tp->t_raw);
+ flushq(tp->t_can);
+ flushq(tp->t_raw);
+ tp->t_lflag &= ~PENDIN;
tp->t_rocount = 0;
tp->t_rocol = 0;
tp->t_state &= ~TS_LOCAL;
ttwakeup(tp);
}
if (rw & FWRITE) {
- flushq(&tp->t_out);
- wakeup((caddr_t)&tp->t_out);
- if (tp->t_wsel) {
- selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
- tp->t_wsel = 0;
- tp->t_state &= ~TS_WCOLL;
- }
+ flushq(tp->t_out);
+ ttwwakeup(tp);
}
if (rw & FREAD) {
if (tp->t_state & (TS_TBLOCK | TS_HW_IFLOW)
@@ -286,16 +281,19 @@ ttyflush(tp, rw)
* is still tricky because we don't want to add a
* new obstruction to draining the output queue.
*/
- out_cc = RB_LEN(&tp->t_out);
+ out_cc = RB_LEN(tp->t_out);
t_state = tp->t_state;
ttyunblock(tp);
tp->t_state &= ~TS_TBLOCK;
- if (t_state & TS_TBLOCK && RB_LEN(&tp->t_out) != 0)
- ttysleep(tp, (caddr_t)&tp->t_out, TTIPRI,
+ if (t_state & TS_TBLOCK && RB_LEN(tp->t_out) != 0) {
+ tp->t_state |= TS_SO_OCOMPLETE;
+ ttysleep(tp, TSA_OCOMPLETE(tp), TTIPRI,
"ttyfls", hz / 10);
- if (out_cc == 0 && RB_LEN(&tp->t_out) != 0) {
+ }
+ if (out_cc != 0 && RB_LEN(tp->t_out) != 0) {
(*cdevsw[major(tp->t_dev)].d_stop)(tp, FWRITE);
- flushq(&tp->t_out);
+ flushq(tp->t_out);
+ ttwwakeup(tp);
}
}
}
@@ -314,7 +312,7 @@ ttyblock(tp)
if ((tp->t_state & TS_TBLOCK) == 0
&& tp->t_cc[VSTOP] != _POSIX_VDISABLE
- && putc(tp->t_cc[VSTOP], &tp->t_out) == 0)
+ && putc(tp->t_cc[VSTOP], tp->t_out) == 0)
tp->t_state |= TS_TBLOCK;
if (tp->t_cflag & CDTR_IFLOW)
tp->t_state |= TS_DTR_IFLOW;
@@ -334,7 +332,7 @@ ttyunblock(tp)
if (tp->t_state & TS_TBLOCK
&& tp->t_cc[VSTART] != _POSIX_VDISABLE
- && putc(tp->t_cc[VSTART], &tp->t_out) == 0)
+ && putc(tp->t_cc[VSTART], tp->t_out) == 0)
tp->t_state &= ~TS_TBLOCK;
tp->t_state &= ~TS_HW_IFLOW;
ttstart(tp);
@@ -413,7 +411,7 @@ ttioctl(tp, com, data, flag)
(p->p_sigmask & sigmask(SIGTTOU)) == 0) {
pgsignal(p->p_pgrp, SIGTTOU, 1);
if (error = ttysleep(tp, (caddr_t)&lbolt,
- TTOPRI | PCATCH, ttybg, 0))
+ TTOPRI | PCATCH, "ttybg1", 0))
return (error);
}
break;
@@ -490,11 +488,15 @@ ttioctl(tp, com, data, flag)
/* return number of characters immediately available */
case FIONREAD:
+ s = spltty();
*(off_t *)data = ttnread(tp);
+ splx(s);
break;
case TIOCOUTQ:
- *(int *)data = RB_LEN(&tp->t_out);
+ s = spltty();
+ *(int *)data = RB_LEN(tp->t_out);
+ splx(s);
break;
case TIOCSTOP:
@@ -555,47 +557,27 @@ ttioctl(tp, com, data, flag)
if (tp->t_param && (error = (*tp->t_param)(tp, t))) {
splx(s);
return (error);
- } else {
- /*
- * XXX doubtful. We mostly check both CLOCAL
- * and TS_CARR_ON before doing anything, and
- * changing TS_ISOPEN here just give another
- * flag to worry about, and is probably
- * inconsistent with not changing TS_ISOPEN
- * when carrier drops or CLOCAL rises. OTOH
- * we should maintain a flag to keep track
- * of the combination of CLOCAL and TS_CARR_ON.
- * This could be just TS_CARR_ON (if we don't
- * need to
- *
- * XXX ttselect() doesn't worry about
- * TS_ISOPEN, so it is inconsistent with
- * ttread() after TS_ISOPEN gets cleared here.
- */
- if ((tp->t_state&TS_CARR_ON) == 0 &&
- (tp->t_cflag&CLOCAL) &&
- (t->c_cflag&CLOCAL) == 0) {
- tp->t_state &= ~TS_ISOPEN;
- tp->t_state |= TS_WOPEN;
- ttwakeup(tp);
- }
- tp->t_cflag = t->c_cflag;
- tp->t_ispeed = t->c_ispeed;
- tp->t_ospeed = t->c_ospeed;
}
+ if (t->c_cflag & CLOCAL && !(tp->t_cflag & CLOCAL)) {
+ wakeup(TSA_CARR_ON(tp));
+ ttwakeup(tp);
+ ttwwakeup(tp);
+ }
+ tp->t_cflag = t->c_cflag;
+ tp->t_ispeed = t->c_ispeed;
+ tp->t_ospeed = t->c_ospeed;
ttsetwater(tp);
}
- if (com != TIOCSETAF) {
- if ((t->c_lflag&ICANON) != (tp->t_lflag&ICANON))
- if (t->c_lflag&ICANON) {
- tp->t_lflag |= PENDIN;
- ttwakeup(tp);
- }
+ if ((t->c_lflag&ICANON) != (tp->t_lflag&ICANON) &&
+ com != TIOCSETAF) {
+ if (t->c_lflag&ICANON)
+ t->c_lflag |= PENDIN;
else {
- catb(&tp->t_raw, &tp->t_can);
- catb(&tp->t_can, &tp->t_raw);
+ catb(tp->t_raw, tp->t_can);
+ catb(tp->t_can, tp->t_raw);
}
- }
+ ttwakeup(tp);
+ }
tp->t_iflag = t->c_iflag;
tp->t_oflag = t->c_oflag;
/*
@@ -606,6 +588,9 @@ ttioctl(tp, com, data, flag)
else
t->c_lflag &= ~EXTPROC;
tp->t_lflag = t->c_lflag;
+ if (t->c_cc[VMIN] != tp->t_cc[VMIN] ||
+ t->c_cc[VTIME] != tp->t_cc[VTIME])
+ ttwakeup(tp);
bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc));
splx(s);
break;
@@ -640,7 +625,13 @@ ttioctl(tp, com, data, flag)
case TIOCSPGRP: {
register struct pgrp *pgrp = pgfind(*(int *)data);
+#ifdef broken_for_F_SETOWN
+ if (!suser(p->p_ucred, &p->p_acflag))
+ ;
+ else if (!isctty(p, tp))
+#else
if (!isctty(p, tp))
+#endif
return (ENOTTY);
else if (pgrp == NULL || pgrp->pg_session != p->p_session)
return (EPERM);
@@ -668,9 +659,7 @@ ttioctl(tp, com, data, flag)
case TIOCCONS:
if (*(int *)data) {
- if (constty && constty != tp &&
- (constty->t_state & (TS_CARR_ON|TS_ISOPEN)) ==
- (TS_CARR_ON|TS_ISOPEN))
+ if (constty && constty != tp && CAN_DO_IO(constty))
return (EBUSY);
#ifndef UCONSOLE
if (error = suser(p->p_ucred, &p->p_acflag))
@@ -696,19 +685,21 @@ ttioctl(tp, com, data, flag)
return (0);
}
-int
+/*
+ * Call at spltty().
+ */
+static int
ttnread(tp)
struct tty *tp;
{
int nread = 0;
- /* XXX races. */
if (tp->t_lflag & PENDIN)
ttypend(tp);
- nread = RB_LEN(&tp->t_can);
+ nread = RB_LEN(tp->t_can);
if ((tp->t_lflag & ICANON) == 0) {
- nread += RB_LEN(&tp->t_raw);
- if (nread < tp->t_cc[VMIN])
+ nread += RB_LEN(tp->t_raw);
+ if (nread < tp->t_cc[VMIN] && tp->t_cc[VTIME] == 0)
nread = 0;
}
return (nread);
@@ -720,17 +711,14 @@ ttselect(dev, rw, p)
int rw;
struct proc *p;
{
- register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
- int nread;
+ register struct tty *tp = cdevsw[major(dev)].d_ttys[minor(dev)];
int s = spltty();
struct proc *selp;
switch (rw) {
case FREAD:
- nread = ttnread(tp);
- if (nread > 0 ||
- ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0))
+ if (ttnread(tp) > 0 || tp->t_state & TS_ZOMBIE)
goto win;
if (tp->t_rsel && (selp = pfind(tp->t_rsel)) && selp->p_wchan == (caddr_t)&selwait)
tp->t_state |= TS_RCOLL;
@@ -739,7 +727,8 @@ ttselect(dev, rw, p)
break;
case FWRITE:
- if (RB_LEN(&tp->t_out) <= tp->t_lowat)
+ if (RB_LEN(tp->t_out) <= tp->t_lowat && CAN_DO_IO(tp)
+ || tp->t_state & TS_ZOMBIE)
goto win;
if (tp->t_wsel && (selp = pfind(tp->t_wsel)) && selp->p_wchan == (caddr_t)&selwait)
tp->t_state |= TS_WCOLL;
@@ -766,12 +755,11 @@ ttyopen(dev, tp, dummy)
tp->t_dev = dev;
- tp->t_state &= ~TS_WOPEN;
if ((tp->t_state & TS_ISOPEN) == 0) {
tp->t_state |= TS_ISOPEN;
- initrb(&tp->t_raw);
- initrb(&tp->t_can);
- initrb(&tp->t_out);
+ initrb(tp->t_raw);
+ initrb(tp->t_can);
+ initrb(tp->t_out);
bzero((caddr_t)&tp->t_winsize, sizeof(tp->t_winsize));
}
return (0);
@@ -793,7 +781,7 @@ ttylclose(tp, flag)
}
/*
- * Handle close() on a tty line: flush and set to initial state,
+ * Handle close() on a tty line: set to initial state,
* bumping generation number so that pending read/write calls
* can detect recycling of the tty.
*/
@@ -803,7 +791,6 @@ ttyclose(tp)
{
if (constty == tp)
constty = NULL;
- ttyflush(tp, FREAD|FWRITE);
tp->t_session = NULL;
tp->t_pgrp = NULL;
tp->t_state = 0;
@@ -822,7 +809,7 @@ ttymodem(tp, flag)
int flag;
{
- if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_lflag&MDMBUF)) {
+ if (tp->t_state & TS_CARR_ON && tp->t_lflag & MDMBUF) {
/*
* MDMBUF: do flow control according to carrier flag
*/
@@ -839,6 +826,7 @@ ttymodem(tp, flag)
*/
tp->t_state &= ~TS_CARR_ON;
if (tp->t_state&TS_ISOPEN && (tp->t_cflag&CLOCAL) == 0) {
+ tp->t_state |= TS_ZOMBIE;
if (tp->t_session && tp->t_session->s_leader)
psignal(tp->t_session->s_leader, SIGHUP);
ttyflush(tp, FREAD|FWRITE);
@@ -849,30 +837,9 @@ ttymodem(tp, flag)
* Carrier now on.
*/
tp->t_state |= TS_CARR_ON;
+ wakeup(TSA_CARR_ON(tp));
ttwakeup(tp);
- }
- return (1);
-}
-
-/*
- * Default modem control routine (for other line disciplines).
- * Return argument flag, to turn off device on carrier drop.
- */
-int
-nullmodem(tp, flag)
- register struct tty *tp;
- int flag;
-{
-
- if (flag)
- tp->t_state |= TS_CARR_ON;
- else {
- tp->t_state &= ~TS_CARR_ON;
- if ((tp->t_cflag&CLOCAL) == 0) {
- if (tp->t_session && tp->t_session->s_leader)
- psignal(tp->t_session->s_leader, SIGHUP);
- return (0);
- }
+ ttwwakeup(tp);
}
return (1);
}
@@ -889,12 +856,12 @@ ttypend(tp)
tp->t_lflag &= ~PENDIN;
tp->t_state |= TS_TYPEN;
- hd = tp->t_raw.rb_hd;
- tl = tp->t_raw.rb_tl;
- flushq(&tp->t_raw);
+ hd = tp->t_raw->rb_hd;
+ tl = tp->t_raw->rb_tl;
+ flushq(tp->t_raw);
while (hd != tl) {
ttyinput(*hd, tp);
- hd = RB_SUCC(&tp->t_raw, hd);
+ hd = RB_SUCC(tp->t_raw, hd);
}
tp->t_state &= ~TS_TYPEN;
}
@@ -937,7 +904,7 @@ ttyinput(c, tp)
if ((iflag & IXOFF && (tp->t_state & TS_TBLOCK) == 0
|| tp->t_cflag & TS_HW_IFLOW && (tp->t_state & TS_HW_IFLOW) == 0)
&& INPUT_LEN(tp) > I_HIGH_WATER - 3
- && ((lflag & ICANON) == 0 || RB_LEN(&tp->t_can) != 0))
+ && ((lflag & ICANON) == 0 || RB_LEN(tp->t_can) != 0))
ttyblock(tp);
/*
* Handle exceptional conditions (break, parity, framing).
@@ -959,9 +926,9 @@ ttyinput(c, tp)
parmrk:
if (INPUT_LEN(tp) > MAX_INPUT - 3)
goto input_overflow;
- putc(0377|TTY_QUOTE, &tp->t_raw);
- putc(0|TTY_QUOTE, &tp->t_raw);
- putc(c|TTY_QUOTE, &tp->t_raw);
+ putc(0377|TTY_QUOTE, tp->t_raw);
+ putc(0|TTY_QUOTE, tp->t_raw);
+ putc(c|TTY_QUOTE, tp->t_raw);
goto endcase;
} else
c = 0;
@@ -1074,23 +1041,23 @@ parmrk:
* erase (^H / ^?)
*/
if (CCEQ(cc[VERASE], c)) {
- if (RB_LEN(&tp->t_raw))
- ttyrub(unputc(&tp->t_raw), tp);
+ if (RB_LEN(tp->t_raw))
+ ttyrub(unputc(tp->t_raw), tp);
goto endcase;
}
/*
* kill (^U)
*/
if (CCEQ(cc[VKILL], c)) {
- if (lflag&ECHOKE && RB_LEN(&tp->t_raw) == tp->t_rocount &&
+ if (lflag&ECHOKE && RB_LEN(tp->t_raw) == tp->t_rocount &&
(lflag&ECHOPRT) == 0) {
- while (RB_LEN(&tp->t_raw))
- ttyrub(unputc(&tp->t_raw), tp);
+ while (RB_LEN(tp->t_raw))
+ ttyrub(unputc(tp->t_raw), tp);
} else {
ttyecho(c, tp);
if (lflag&ECHOK || lflag&ECHOKE)
ttyecho('\n', tp);
- while (getc(&tp->t_raw) > 0)
+ while (getc(tp->t_raw) > 0)
;
tp->t_rocount = 0;
}
@@ -1106,7 +1073,7 @@ parmrk:
/*
* erase whitespace
*/
- while ((c = unputc(&tp->t_raw)) == ' ' || c == '\t')
+ while ((c = unputc(tp->t_raw)) == ' ' || c == '\t')
ttyrub(c, tp);
if (c == -1)
goto endcase;
@@ -1115,14 +1082,14 @@ parmrk:
* next chars type (for ALTWERASE)
*/
ttyrub(c, tp);
- c = unputc(&tp->t_raw);
+ c = unputc(tp->t_raw);
if (c == -1)
goto endcase;
/*
* Handle one-letter word cases.
*/
if (c == ' ' || c == '\t') {
- putc(c, &tp->t_raw);
+ putc(c, tp->t_raw);
goto endcase;
}
ctype = ISALPHA(c);
@@ -1131,13 +1098,13 @@ parmrk:
*/
do {
ttyrub(c, tp);
- c = unputc(&tp->t_raw);
+ c = unputc(tp->t_raw);
if (c == -1)
goto endcase;
} while (c != ' ' && c != '\t' &&
((lflag & ALTWERASE) == 0
|| ISALPHA(c) == ctype));
- (void) putc(c, &tp->t_raw);
+ (void) putc(c, tp->t_raw);
goto endcase;
}
/*
@@ -1163,7 +1130,7 @@ parmrk:
if (INPUT_LEN(tp) >= MAX_INPUT) {
input_overflow:
if (iflag&IMAXBEL) {
- if (RB_LEN(&tp->t_out) < tp->t_hiwat)
+ if (RB_LEN(tp->t_out) < tp->t_hiwat)
(void) ttyoutput(CTRL('g'), tp);
} else
ttyflush(tp, FREAD);
@@ -1173,7 +1140,7 @@ input_overflow:
* Put data char in q for user and
* wakeup on seeing a line delimiter.
*/
- if (putc(c, &tp->t_raw) >= 0) {
+ if (putc(c, tp->t_raw) >= 0) {
if ((lflag&ICANON) == 0) {
ttwakeup(tp);
ttyecho(c, tp);
@@ -1181,7 +1148,7 @@ input_overflow:
}
if (ttbreakc(c)) {
tp->t_rocount = 0;
- catb(&tp->t_raw, &tp->t_can);
+ catb(tp->t_raw, tp->t_can);
ttwakeup(tp);
} else if (tp->t_rocount++ == 0)
tp->t_rocol = tp->t_col;
@@ -1236,7 +1203,7 @@ ttyoutput(c, tp)
if ((oflag&OPOST) == 0) {
if (tp->t_lflag&FLUSHO)
return (-1);
- if (putc(c, &tp->t_out))
+ if (putc(c, tp->t_out))
return (c);
tk_nout++;
tp->t_outcc++;
@@ -1261,17 +1228,17 @@ ttyoutput(c, tp)
#ifdef was
c -= b_to_q(" ", c, &tp->t_outq);
#else
- i = imin(c, RB_CONTIGPUT(&tp->t_out));
- bcopy(" ", tp->t_out.rb_tl, i);
- tp->t_out.rb_tl =
- RB_ROLLOVER(&tp->t_out, tp->t_out.rb_tl+i);
- i = imin(c - i, RB_CONTIGPUT(&tp->t_out));
+ i = imin(c, RB_CONTIGPUT(tp->t_out));
+ bcopy(" ", tp->t_out->rb_tl, i);
+ tp->t_out->rb_tl =
+ RB_ROLLOVER(tp->t_out, tp->t_out->rb_tl+i);
+ i = imin(c - i, RB_CONTIGPUT(tp->t_out));
/* off end and still have space? */
if (i) {
- bcopy(" ", tp->t_out.rb_tl, i);
- tp->t_out.rb_tl =
- RB_ROLLOVER(&tp->t_out, tp->t_out.rb_tl+i);
+ bcopy(" ", tp->t_out->rb_tl, i);
+ tp->t_out->rb_tl =
+ RB_ROLLOVER(tp->t_out, tp->t_out->rb_tl+i);
}
#endif
tk_nout += c;
@@ -1291,7 +1258,7 @@ ttyoutput(c, tp)
*/
if (c == '\n' && (tp->t_oflag&ONLCR) && ttyoutput('\r', tp) >= 0)
return (c);
- if ((tp->t_lflag&FLUSHO) == 0 && putc(c, &tp->t_out))
+ if ((tp->t_lflag&FLUSHO) == 0 && putc(c, tp->t_out))
return (c);
col = tp->t_col;
@@ -1342,8 +1309,8 @@ ttread(tp, uio, flag)
long slp = 0; /* XXX this should be renamed `timo'. */
loop:
- lflag = tp->t_lflag;
s = spltty();
+ lflag = tp->t_lflag;
/*
* take pending input first
*/
@@ -1351,6 +1318,7 @@ loop:
ttypend(tp);
splx(s); /* reduce latency */
s = spltty();
+ lflag = tp->t_lflag; /* XXX ttypend() clobbers it */
}
/*
@@ -1364,18 +1332,32 @@ loop:
return (EIO);
pgsignal(p->p_pgrp, SIGTTIN, 1);
if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH,
- ttybg, 0))
+ "ttybg2", 0))
return (error);
goto loop;
}
+ if (tp->t_state & TS_ZOMBIE) {
+ splx(s);
+ return (0); /* EOF */
+ }
+
/*
* If canonical, use the canonical queue,
* else use the raw queue.
*/
- qp = lflag&ICANON ? &tp->t_can : &tp->t_raw;
+ qp = lflag&ICANON ? tp->t_can : tp->t_raw;
rblen = RB_LEN(qp);
-
+ if (flag & IO_NDELAY) {
+ if (rblen > 0)
+ goto read;
+ if ((lflag & ICANON) == 0 && cc[VMIN] == 0) {
+ splx(s);
+ return (0);
+ }
+ splx(s);
+ return (EWOULDBLOCK);
+ }
if ((lflag & ICANON) == 0) {
int m = cc[VMIN];
long t = cc[VTIME];
@@ -1460,45 +1442,24 @@ loop:
goto sleep;
}
if (rblen <= 0) {
- int carrier;
-
sleep:
/*
- * If there is no input, sleep on rawq
- * awaiting hardware receipt and notification.
- * If we have data, we don't need to check for carrier.
+ * There is no input, or not enough input and we can block.
*/
- carrier = (tp->t_state&TS_CARR_ON) || (tp->t_cflag&CLOCAL);
- if (!carrier && tp->t_state&TS_ISOPEN) {
- splx(s);
- return (0); /* EOF */
- }
- if (flag & IO_NDELAY) {
- splx(s);
- return (EWOULDBLOCK);
- }
- if (slp) {
- /*
- * Use plain wakeup() not ttwakeup().
- * XXX why not use the timeout built into tsleep?
- */
- timeout((timeout_func_t)wakeup, (caddr_t)qp, (int)slp);
- }
- error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH,
- carrier ? ttyin : ttopen, 0);
- if (slp) {
- slp = 0;
- untimeout((timeout_func_t)wakeup, (caddr_t)qp);
- }
+ error = ttysleep(tp, TSA_HUP_OR_INPUT(tp), TTIPRI | PCATCH,
+ CAN_DO_IO(tp) ? "ttyin" : "ttyhup", (int)slp);
splx(s);
- if (error)
+ if (error == EWOULDBLOCK)
+ error = 0;
+ else if (error)
return (error);
/*
- * XXX what happens if ICANON, MIN or TIME changes or
- * another process eats some input while we are asleep
- * (not just here)? It would be safest to detect changes
- * and reset our state variables (has_stime and last_cc).
+ * XXX what happens if another process eats some input
+ * while we are asleep (not just here)? It would be
+ * safest to detect changes and reset our state variables
+ * (has_stime and last_cc).
*/
+ slp = 0;
goto loop;
}
@@ -1548,7 +1509,8 @@ slowcase:
pgsignal(tp->t_pgrp, SIGTSTP, 1);
if (first) {
if (error = ttysleep(tp, (caddr_t)&lbolt,
- TTIPRI | PCATCH, ttybg, 0))
+ TTIPRI | PCATCH, "ttybg3",
+ 0))
break;
goto loop;
}
@@ -1612,17 +1574,17 @@ ttycheckoutq(tp, wait)
oldsig = curproc->p_sig;
else
oldsig = 0;
- if (RB_LEN(&tp->t_out) > hiwat + 200)
- while (RB_LEN(&tp->t_out) > hiwat) {
+ if (RB_LEN(tp->t_out) > hiwat + 200)
+ while (RB_LEN(tp->t_out) > hiwat) {
ttstart(tp);
+ if (RB_LEN(tp->t_out) <= hiwat)
+ break;
if (wait == 0 || (curproc && curproc->p_sig != oldsig)) {
splx(s);
return (0);
}
- timeout((timeout_func_t)wakeup, (caddr_t)&tp->t_out,
- hz); /* XXX */
- tp->t_state |= TS_ASLEEP;
- tsleep((caddr_t)&tp->t_out, PZERO - 1, "ttchout", 0);
+ tp->t_state |= TS_SO_OLOWAT;
+ tsleep(TSA_OLOWAT(tp), PZERO - 1, "ttchout", hz);
}
splx(s);
return (1);
@@ -1648,20 +1610,20 @@ ttwrite(tp, uio, flag)
error = 0;
loop:
s = spltty();
- if ((tp->t_state&TS_CARR_ON) == 0 && (tp->t_cflag&CLOCAL) == 0) {
- if (tp->t_state&TS_ISOPEN) {
- splx(s);
- return (EIO);
- } else if (flag & IO_NDELAY) {
+ if (tp->t_state & TS_ZOMBIE) {
+ splx(s);
+ if (uio->uio_resid == cnt)
+ error = EIO;
+ goto out;
+ }
+ if (!CAN_DO_IO(tp)) {
+ if (flag & IO_NDELAY) {
splx(s);
error = EWOULDBLOCK;
goto out;
} else {
- /*
- * sleep awaiting carrier
- */
- error = ttysleep(tp, (caddr_t)&tp->t_raw,
- TTIPRI | PCATCH,ttopen, 0);
+ error = ttysleep(tp, TSA_CARR_ON(tp), TTIPRI | PCATCH,
+ "ttydcd", 0);
splx(s);
if (error)
goto out;
@@ -1679,7 +1641,7 @@ loop:
p->p_pgrp->pg_jobc) {
pgsignal(p->p_pgrp, SIGTTOU, 1);
if (error = ttysleep(tp, (caddr_t)&lbolt, TTIPRI | PCATCH,
- ttybg, 0))
+ "ttybg4", 0))
goto out;
goto loop;
}
@@ -1704,7 +1666,7 @@ loop:
* to fix this is messy because of all the gotos.
*/
s = spltty();
- if (RB_LEN(&tp->t_out) > hiwat) {
+ if (RB_LEN(tp->t_out) > hiwat) {
splx(s);
goto ovhiwat;
}
@@ -1748,14 +1710,14 @@ loop:
ttstart(tp);
if (error = ttysleep(tp,
(caddr_t)&lbolt,
- TTOPRI | PCATCH, ttybuf, 0))
+ TTOPRI | PCATCH, "ttybf1", 0))
break;
goto loop;
}
cp++, cc--;
s = spltty();
if ((tp->t_lflag&FLUSHO) ||
- RB_LEN(&tp->t_out) > hiwat) {
+ RB_LEN(tp->t_out) > hiwat) {
splx(s);
goto ovhiwat;
}
@@ -1778,18 +1740,18 @@ loop:
#else
i = ce;
s = spltty();
- ce = imin(ce, RB_CONTIGPUT(&tp->t_out));
- bcopy(cp, tp->t_out.rb_tl, ce);
- tp->t_out.rb_tl = RB_ROLLOVER(&tp->t_out,
- tp->t_out.rb_tl + ce);
+ ce = imin(ce, RB_CONTIGPUT(tp->t_out));
+ bcopy(cp, tp->t_out->rb_tl, ce);
+ tp->t_out->rb_tl = RB_ROLLOVER(tp->t_out,
+ tp->t_out->rb_tl + ce);
i -= ce;
if (i > 0) {
int ii;
- ii = imin(i, RB_CONTIGPUT(&tp->t_out));
- bcopy(cp + ce, tp->t_out.rb_tl, ii);
- tp->t_out.rb_tl = RB_ROLLOVER(&tp->t_out,
- tp->t_out.rb_tl + ii);
+ ii = imin(i, RB_CONTIGPUT(tp->t_out));
+ bcopy(cp + ce, tp->t_out->rb_tl, ii);
+ tp->t_out->rb_tl = RB_ROLLOVER(tp->t_out,
+ tp->t_out->rb_tl + ii);
i -= ii;
ce += ii;
}
@@ -1801,14 +1763,15 @@ loop:
if (i > 0) {
ttstart(tp);
s = spltty();
- if (RB_CONTIGPUT(&tp->t_out) > 0) {
+ if (RB_CONTIGPUT(tp->t_out) > 0) {
splx(s);
goto loop; /* synchronous/fast */
}
/* out of space, wait a bit */
- tp->t_state |= TS_ASLEEP;
- if (error = ttysleep(tp, (caddr_t)&tp->t_out,
- TTOPRI | PCATCH, ttybuf, 0)) {
+ tp->t_state |= TS_SO_OLOWAT;
+ if (error = ttysleep(tp, TSA_OLOWAT(tp),
+ TTOPRI | PCATCH, "ttybf2",
+ 0)) {
splx(s);
break;
}
@@ -1816,7 +1779,7 @@ loop:
goto loop;
}
s = spltty();
- if (tp->t_lflag&FLUSHO || RB_LEN(&tp->t_out) > hiwat) {
+ if (tp->t_lflag&FLUSHO || RB_LEN(tp->t_out) > hiwat) {
splx(s);
break;
}
@@ -1841,7 +1804,7 @@ ovhiwat:
* This can only occur if FLUSHO is set in t_lflag,
* or if ttstart/oproc is synchronous (or very fast).
*/
- if (RB_LEN(&tp->t_out) <= hiwat) {
+ if (RB_LEN(tp->t_out) <= hiwat) {
splx(s);
goto loop;
}
@@ -1852,8 +1815,8 @@ ovhiwat:
return (EWOULDBLOCK);
return (0);
}
- tp->t_state |= TS_ASLEEP;
- error = ttysleep(tp, (caddr_t)&tp->t_out, TTOPRI | PCATCH, ttyout, 0);
+ tp->t_state |= TS_SO_OLOWAT;
+ error = ttysleep(tp, TSA_OLOWAT(tp), TTOPRI | PCATCH, "ttyout", 0);
splx(s);
if (error)
goto out;
@@ -1904,7 +1867,7 @@ ttyrub(c, tp)
case TAB: {
int c;
- if (tp->t_rocount < RB_LEN(&tp->t_raw)) {
+ if (tp->t_rocount < RB_LEN(tp->t_raw)) {
ttyretype(tp);
return;
}
@@ -1913,9 +1876,9 @@ ttyrub(c, tp)
tp->t_state |= TS_CNTTB;
tp->t_lflag |= FLUSHO;
tp->t_col = tp->t_rocol;
- cp = tp->t_raw.rb_hd;
- for (c = nextc(&cp, &tp->t_raw); c ;
- c = nextc(&cp, &tp->t_raw))
+ cp = tp->t_raw->rb_hd;
+ for (c = nextc(&cp, tp->t_raw); c ;
+ c = nextc(&cp, tp->t_raw))
ttyecho(c, tp);
tp->t_lflag &= ~FLUSHO;
tp->t_state &= ~TS_CNTTB;
@@ -1979,16 +1942,16 @@ ttyretype(tp)
(void) ttyoutput('\n', tp);
s = spltty();
- cp = tp->t_can.rb_hd;
- for (c = nextc(&cp, &tp->t_can); c ; c = nextc(&cp, &tp->t_can))
+ cp = tp->t_can->rb_hd;
+ for (c = nextc(&cp, tp->t_can); c ; c = nextc(&cp, tp->t_can))
ttyecho(c, tp);
- cp = tp->t_raw.rb_hd;
- for (c = nextc(&cp, &tp->t_raw); c ; c = nextc(&cp, &tp->t_raw))
+ cp = tp->t_raw->rb_hd;
+ for (c = nextc(&cp, tp->t_raw); c ; c = nextc(&cp, tp->t_raw))
ttyecho(c, tp);
tp->t_state &= ~TS_ERASE;
splx(s);
- tp->t_rocount = RB_LEN(&tp->t_raw);
+ tp->t_rocount = RB_LEN(tp->t_raw);
tp->t_rocol = 0;
}
@@ -2049,7 +2012,31 @@ ttwakeup(tp)
}
if (tp->t_state & TS_ASYNC)
pgsignal(tp->t_pgrp, SIGIO, 1);
- wakeup((caddr_t)&tp->t_raw);
+ wakeup(TSA_HUP_OR_INPUT(tp));
+}
+
+/*
+ * Wake up any writers on a tty.
+ */
+void
+ttwwakeup(tp)
+ register struct tty *tp;
+{
+ if (RB_LEN(tp->t_out) <= tp->t_lowat) {
+ if (tp->t_state & TS_SO_OCOMPLETE && RB_LEN(tp->t_out) == 0) {
+ tp->t_state &= ~TS_SO_OCOMPLETE;
+ wakeup(TSA_OCOMPLETE(tp));
+ }
+ if (tp->t_state & TS_SO_OLOWAT) {
+ tp->t_state &= ~TS_SO_OLOWAT;
+ wakeup(TSA_OLOWAT(tp));
+ }
+ if (tp->t_wsel) {
+ selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
+ tp->t_wsel = 0;
+ tp->t_state &= ~TS_WCOLL;
+ }
+ }
}
/*
@@ -2099,7 +2086,7 @@ ttyinfo(tp)
{
register struct proc *p, *pick;
struct timeval utime, stime;
- int loadtmp;
+ int loadtmp, tmp;
if (ttycheckoutq(tp,0) == 0)
return;
@@ -2152,8 +2139,13 @@ ttyinfo(tp)
* Lock out clock if process is running; get user/system
* cpu time.
*/
+ tmp = 0;
+ if (curproc == pick)
+ tmp = splclock();
utime = pick->p_utime;
stime = pick->p_stime;
+ if (curproc == pick)
+ splx(tmp);
ttyprintf(tp, " cmd: %s %d [%s] ", comm, pid, wmesg);
@@ -2258,7 +2250,7 @@ tputchar(c, tp)
{
register s = spltty();
- if ((tp->t_state & (TS_CARR_ON|TS_ISOPEN)) == (TS_CARR_ON|TS_ISOPEN)) {
+ if (CAN_DO_IO(tp)) {
if (c == '\n')
(void) ttyoutput('\r', tp);
(void) ttyoutput(c, tp);
@@ -2293,3 +2285,56 @@ ttysleep(tp, chan, pri, wmesg, timo)
return (ERESTART);
return (0);
}
+
+/*
+ * Allocate a tty structure and its associated buffers.
+ */
+struct tty *
+ttymalloc(itp)
+ struct tty *itp;
+{
+ struct tty *tp;
+
+#ifndef broken
+ /*
+ * Note that the itp input is not necessary when we can dealloc
+ * the struct tty.
+ */
+ if(itp == NULL) {
+ MALLOC(tp, struct tty *, sizeof(struct tty), M_TTYS, M_WAITOK);
+ bzero(tp, sizeof *tp);
+ } else {
+ tp = itp;
+ }
+#endif
+ if(tp->t_raw == NULL) {
+ MALLOC(tp->t_raw, struct ringb *, sizeof(struct ringb), M_TTYS, M_WAITOK);
+ bzero(tp->t_raw, sizeof *tp->t_raw);
+ }
+ if(tp->t_can == NULL) {
+ MALLOC(tp->t_can, struct ringb *, sizeof(struct ringb), M_TTYS, M_WAITOK);
+ bzero(tp->t_can, sizeof *tp->t_can);
+ }
+ if(tp->t_out == NULL) {
+ MALLOC(tp->t_out, struct ringb *, sizeof(struct ringb), M_TTYS, M_WAITOK);
+ bzero(tp->t_out, sizeof *tp->t_out);
+ }
+ return(tp);
+}
+
+/*
+ * Free a tty structure and its buffers.
+ */
+void
+ttyfree(tp)
+struct tty *tp;
+{
+ FREE(tp->t_raw, M_TTYS);
+ FREE(tp->t_can, M_TTYS);
+ FREE(tp->t_out, M_TTYS);
+ tp->t_raw = tp->t_can = tp->t_out = NULL;
+#ifdef broken /* session holds a ref to the tty; can't deallocate */
+ /* also set tp to NULL when this isn't broken anymore */
+ FREE(tp, M_TTYS);
+#endif
+}