X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/3ea52422f66b38ef51e27dd55269e58b4e82f791..c01ca9709f7728353e608a09b815a10dc93eaa73:/sys/kern/tty.c diff --git a/sys/kern/tty.c b/sys/kern/tty.c index 3ba838aab2..0b2b715b01 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -32,7 +32,33 @@ * SUCH DAMAGE. * * from: @(#)tty.c 7.44 (Berkeley) 5/28/91 - * $Id: tty.c,v 1.16 1994/01/28 23:17:43 ache Exp $ + * $Id: tty.c,v 1.28 1994/03/26 14:08:23 ache Exp $ + */ + +/*- + * TODO: + * o Fix or remove TS_WOPEN. It's only used for forcing a HUPCL + * when a port is closed without being fully opened (this is + * better decided by noticing if the close is a device close) + * and for distinguishing the first CD change from later ones + * for MDMBUF handling. TS_WOPEN is broken for multiple opens + * and for non-blocking opens. + * o Fix races in ttnread(). + * o Do ttymodem() and nullmodem() in the same order and with + * early returns instead of inconsistent elses. + * o Some or all of the t_out wakeups need to do a selwakeup() + * since ttselect() now blocks when ttwrite() would be blocked + * by lack of carrier. + * o Fix various flags races in sio. E.g., the CLOCAL locking is + * harmed by the wakeups for delta-CLOCAL, the carrier wait loop + * needs to start nearer the top of sioopen(), and the there may + * need to be a wakeup on t_raw in comhardclose() to kick other + * processes out of the wait loop. "take it from the top" code + * gives DTR glitch in usual case (!com->active). bidir open + * doesn't set TS_WOPEN and triggers ttymodem() warning. com-> + * active may help recover. bidir open doesn't set CLOCAL early + * enough. + * o Call suser() to log privileged CLOCAL changes. */ #include "param.h" @@ -47,11 +73,14 @@ #include "dkstat.h" #include "uio.h" #include "kernel.h" +#include "malloc.h" #include "vnode.h" #include "syslog.h" #include "signalvar.h" - #include "vm/vm.h" +#include "kinfo.h" +#include "kinfo_proc.h" + /* * Input control starts when we would not be able to fit the maximum @@ -62,7 +91,7 @@ #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 */ #define MAX_INPUT TTYHOG @@ -200,9 +229,8 @@ 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) { + while ((RB_LEN(tp->t_out) || tp->t_state&TS_BUSY) && + CAN_DO_IO(tp) && tp->t_oproc) { /* * XXX temporary fix for deadlock. * @@ -219,11 +247,11 @@ ttywait(tp) tp->t_lowat = 0; (*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)) { + if ((RB_LEN(tp->t_out) || tp->t_state&TS_BUSY) && + CAN_DO_IO(tp)) { tp->t_state |= TS_ASLEEP; - if (error = ttysleep(tp, (caddr_t)&tp->t_out, - TTOPRI | PCATCH, ttyout, 0)) + if (error = ttysleep(tp, (caddr_t)tp->t_out, + TTOPRI | PCATCH, "ttywai", 0)) break; } else break; @@ -255,16 +283,16 @@ 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_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); + 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; @@ -284,16 +312,16 @@ 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, - ttyout, hz / 10); - if (out_cc == 0 && RB_LEN(&tp->t_out) != 0) { + if (t_state & TS_TBLOCK && RB_LEN(tp->t_out) != 0) + ttysleep(tp, (caddr_t)tp->t_out, TTIPRI, + "ttyfls", hz / 10); + 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); } } } @@ -312,7 +340,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; @@ -332,7 +360,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); @@ -492,7 +520,7 @@ ttioctl(tp, com, data, flag) break; case TIOCOUTQ: - *(int *)data = RB_LEN(&tp->t_out); + *(int *)data = RB_LEN(tp->t_out); break; case TIOCSTOP: @@ -547,41 +575,26 @@ ttioctl(tp, com, data, flag) ttyflush(tp, FREAD); } if ((t->c_cflag&CIGNORE) == 0) { + tcflag_t old_cflag; + /* * set device hardware */ 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; } + old_cflag = tp->t_cflag; + tp->t_cflag = t->c_cflag; + tp->t_ispeed = t->c_ispeed; + tp->t_ospeed = t->c_ospeed; ttsetwater(tp); + if (tp->t_cflag & CLOCAL) + tp->t_state &= ~TS_ZOMBIE; + if ((tp->t_cflag ^ old_cflag) & CLOCAL) { + ttwakeup(tp); + wakeup((caddr_t)tp->t_out); + } } if (com != TIOCSETAF) { if ((t->c_lflag&ICANON) != (tp->t_lflag&ICANON)) @@ -590,8 +603,8 @@ ttioctl(tp, com, data, flag) ttwakeup(tp); } 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); } } tp->t_iflag = t->c_iflag; @@ -638,7 +651,9 @@ ttioctl(tp, com, data, flag) case TIOCSPGRP: { register struct pgrp *pgrp = pgfind(*(int *)data); - if (!isctty(p, tp)) + if (!suser(p->p_ucred, &p->p_acflag)) + ; + else if (!isctty(p, tp)) return (ENOTTY); else if (pgrp == NULL || pgrp->pg_session != p->p_session) return (EPERM); @@ -666,9 +681,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)) @@ -703,9 +716,9 @@ ttnread(tp) /* 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); + nread += RB_LEN(tp->t_raw); if (nread < tp->t_cc[VMIN]) nread = 0; } @@ -718,17 +731,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; @@ -737,7 +747,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; @@ -767,9 +778,9 @@ ttyopen(dev, tp, dummy) 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); @@ -791,7 +802,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. */ @@ -801,7 +812,6 @@ ttyclose(tp) { if (constty == tp) constty = NULL; - ttyflush(tp, FREAD|FWRITE); tp->t_session = NULL; tp->t_pgrp = NULL; tp->t_state = 0; @@ -820,6 +830,10 @@ ttymodem(tp, flag) int flag; { +#ifdef DIAGNOSTIC + if ((tp->t_state & (TS_ISOPEN | TS_WOPEN)) == 0) + printf("ttymodem: not open\n"); +#endif if ((tp->t_state&TS_WOPEN) == 0 && (tp->t_lflag&MDMBUF)) { /* * MDMBUF: do flow control according to carrier flag @@ -837,10 +851,14 @@ 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); return (0); + } else { + wakeup((caddr_t)tp->t_raw); + wakeup((caddr_t)tp->t_out); } } else { /* @@ -848,6 +866,7 @@ ttymodem(tp, flag) */ tp->t_state |= TS_CARR_ON; ttwakeup(tp); + wakeup((caddr_t)tp->t_out); } return (1); } @@ -861,12 +880,17 @@ nullmodem(tp, flag) register struct tty *tp; int flag; { - + +#ifdef DIAGNOSTIC + if ((tp->t_state & (TS_ISOPEN | TS_WOPEN)) == 0) + printf("nullmodem: not open\n"); +#endif if (flag) tp->t_state |= TS_CARR_ON; else { tp->t_state &= ~TS_CARR_ON; - if ((tp->t_cflag&CLOCAL) == 0) { + 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); return (0); @@ -887,12 +911,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; } @@ -935,7 +959,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). @@ -957,9 +981,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; @@ -1072,23 +1096,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; } @@ -1104,7 +1128,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; @@ -1113,14 +1137,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); @@ -1129,13 +1153,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; } /* @@ -1161,7 +1185,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); @@ -1171,7 +1195,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); @@ -1179,7 +1203,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; @@ -1234,7 +1258,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++; @@ -1259,17 +1283,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; @@ -1289,7 +1313,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; @@ -1371,7 +1395,7 @@ loop: * 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 ((lflag & ICANON) == 0) { @@ -1421,6 +1445,8 @@ loop: } else { /* nothing, check expiration */ slp = t - diff(timecopy, stime); + if (slp <= 0) + goto read; } last_cc = rblen; } else { /* m == 0 */ @@ -1443,35 +1469,32 @@ loop: } } #undef diff - if (slp > 0) { - /* - * Rounding down may make us wake up just short - * of the target, so we round up. - * The formula is ceiling(slp * hz/1000000). - * 32-bit arithmetic is enough for hz < 169. - * XXX see hzto() for how to avoid overflow if hz - * is large (divide by `tick' and/or arrange to - * use hzto() if hz is large). - */ - slp = (long) (((u_long)slp * hz) + 999999) / 1000000; - goto sleep; - } else - slp = 0; + /* + * Rounding down may make us wake up just short + * of the target, so we round up. + * The formula is ceiling(slp * hz/1000000). + * 32-bit arithmetic is enough for hz < 169. + * XXX see hzto() for how to avoid overflow if hz + * is large (divide by `tick' and/or arrange to + * use hzto() if hz is large). + */ + slp = (long) (((u_long)slp * hz) + 999999) / 1000000; + goto sleep; } if (rblen <= 0) { int carrier; sleep: + if (tp->t_state & TS_ZOMBIE) { + splx(s); + return (0); /* EOF */ + } /* * 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. */ - carrier = (tp->t_state&TS_CARR_ON) || (tp->t_cflag&CLOCAL); - if (!carrier && tp->t_state&TS_ISOPEN) { - splx(s); - return (0); /* EOF */ - } + carrier = CAN_DO_IO(tp); if (flag & IO_NDELAY) { splx(s); return (EWOULDBLOCK); @@ -1483,7 +1506,7 @@ sleep: */ timeout((timeout_func_t)wakeup, (caddr_t)qp, (int)slp); } - error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH, + error = ttysleep(tp, (caddr_t)tp->t_raw, TTIPRI | PCATCH, carrier ? ttyin : ttopen, 0); if (slp) { slp = 0; @@ -1611,17 +1634,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 (wait == 0 || (curproc && curproc->p_sig != oldsig)) { splx(s); return (0); } - timeout((timeout_func_t)wakeup, (caddr_t)&tp->t_out, + 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); + tsleep((caddr_t)tp->t_out, PZERO - 1, "ttchout", 0); } splx(s); return (1); @@ -1647,11 +1670,12 @@ 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); + goto out; + } + if (!CAN_DO_IO(tp)) { + if (flag & IO_NDELAY) { splx(s); error = EWOULDBLOCK; goto out; @@ -1659,7 +1683,7 @@ loop: /* * sleep awaiting carrier */ - error = ttysleep(tp, (caddr_t)&tp->t_raw, + error = ttysleep(tp, (caddr_t)tp->t_raw, TTIPRI | PCATCH,ttopen, 0); splx(s); if (error) @@ -1703,7 +1727,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; } @@ -1754,7 +1778,7 @@ 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; } @@ -1777,18 +1801,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; } @@ -1800,13 +1824,13 @@ 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, + if (error = ttysleep(tp, (caddr_t)tp->t_out, TTOPRI | PCATCH, ttybuf, 0)) { splx(s); break; @@ -1815,7 +1839,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; } @@ -1840,7 +1864,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,7 +1876,7 @@ ovhiwat: return (0); } tp->t_state |= TS_ASLEEP; - error = ttysleep(tp, (caddr_t)&tp->t_out, TTOPRI | PCATCH, ttyout, 0); + error = ttysleep(tp, (caddr_t)tp->t_out, TTOPRI | PCATCH, ttyout, 0); splx(s); if (error) goto out; @@ -1903,7 +1927,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; } @@ -1912,9 +1936,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; @@ -1978,16 +2002,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; } @@ -2048,7 +2072,7 @@ ttwakeup(tp) } if (tp->t_state & TS_ASYNC) pgsignal(tp->t_pgrp, SIGIO, 1); - wakeup((caddr_t)&tp->t_raw); + wakeup((caddr_t)tp->t_raw); } /* @@ -2098,14 +2122,14 @@ ttyinfo(tp) { register struct proc *p, *pick; struct timeval utime, stime; - int tmp; + int loadtmp, tmp = 0; if (ttycheckoutq(tp,0) == 0) return; /* Print load average. */ - tmp = (averunnable[0] * 100 + FSCALE / 2) >> FSHIFT; - ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100); + loadtmp = (averunnable[0] * 100 + FSCALE / 2) >> FSHIFT; + ttyprintf(tp, "load: %d.%02d ", loadtmp / 100, loadtmp % 100); if (tp->t_session == NULL) ttyprintf(tp, "not a controlling terminal\n"); @@ -2114,14 +2138,38 @@ ttyinfo(tp) else if ((p = tp->t_pgrp->pg_mem) == NULL) ttyprintf(tp, "empty foreground process group\n"); else { + int kspace; + int s; + pid_t pid; + char wmesg[WMESGLEN+1]; + char comm[MAXCOMLEN+1]; /* Pick interesting process. */ for (pick = NULL; p != NULL; p = p->p_pgrpnxt) if (proc_compare(pick, p)) pick = p; - ttyprintf(tp, " cmd: %s %d [%s] ", pick->p_comm, pick->p_pid, + if( pick == NULL) { + ttyprintf(tp, "process went away\n"); + goto finish; + } + +#define pgtok(a) (((a) * NBPG) / 1024) + + if( (pick->p_flag & SLOAD) && (pick->p_vmspace)) + kspace = pgtok(pick->p_vmspace->vm_pmap.pm_stats.resident_count); + else + kspace = 0; + strncpy(wmesg, ((pick->p_flag & SLOAD) == 0 ? "swapped": pick->p_stat == SRUN ? "running" : - pick->p_wmesg ? pick->p_wmesg : "iowait"); + pick->p_wmesg ? pick->p_wmesg : "iowait"), WMESGLEN); + wmesg[WMESGLEN] = 0; + + strncpy(comm, pick->p_comm ? pick->p_comm : "", MAXCOMLEN); + comm[MAXCOMLEN] = 0; + + loadtmp = (pick->p_pctcpu * 10000 + FSCALE / 2) >> FSHIFT; + + pid = pick->p_pid; /* * Lock out clock if process is running; get user/system @@ -2134,6 +2182,8 @@ ttyinfo(tp) if (curproc == pick) splx(tmp); + ttyprintf(tp, " cmd: %s %d [%s] ", comm, pid, wmesg); + /* Print user time. */ ttyprintf(tp, "%d.%02du ", utime.tv_sec, (utime.tv_usec + 5000) / 10000); @@ -2142,12 +2192,10 @@ ttyinfo(tp) ttyprintf(tp, "%d.%02ds ", stime.tv_sec, (stime.tv_usec + 5000) / 10000); -#define pgtok(a) (((a) * NBPG) / 1024) /* Print percentage cpu, resident set size. */ - tmp = (pick->p_pctcpu * 10000 + FSCALE / 2) >> FSHIFT; - ttyprintf(tp, "%d%% %dk\n", - tmp / 100, pgtok(pick->p_vmspace->vm_pmap.pm_stats.resident_count)); + ttyprintf(tp, "%d%% %dk\n", loadtmp / 100, kspace); } +finish: tp->t_rocount = 0; /* so pending input will be retyped if BS */ } @@ -2237,7 +2285,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); @@ -2272,3 +2320,57 @@ 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 +}