version 1.197.6.8, 2007/12/09 19:38:26 |
version 1.198, 2007/09/25 14:04:07 |
Line 62 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 62 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <sys/namei.h> |
#include <sys/namei.h> |
#include <sys/sysctl.h> |
#include <sys/sysctl.h> |
#include <sys/kauth.h> |
#include <sys/kauth.h> |
#include <sys/intr.h> |
|
|
|
#include <machine/stdarg.h> |
#include <machine/stdarg.h> |
|
|
Line 73 static void ttyrubo(struct tty *, int); |
|
Line 72 static void ttyrubo(struct tty *, int); |
|
static void ttyprintf_nolock(struct tty *, const char *fmt, ...) |
static void ttyprintf_nolock(struct tty *, const char *fmt, ...) |
__attribute__((__format__(__printf__,2,3))); |
__attribute__((__format__(__printf__,2,3))); |
static int proc_compare(struct proc *, struct proc *); |
static int proc_compare(struct proc *, struct proc *); |
static void ttysigintr(void *); |
|
|
|
/* Symbolic sleep message strings. */ |
/* Symbolic sleep message strings. */ |
const char ttclos[] = "ttycls"; |
const char ttclos[] = "ttycls"; |
Line 165 unsigned char const char_type[] = { |
|
Line 163 unsigned char const char_type[] = { |
|
#undef TB |
#undef TB |
#undef VT |
#undef VT |
|
|
static struct ttylist_head tty_sigqueue = TAILQ_HEAD_INITIALIZER(tty_sigqueue); |
kmutex_t ttylist_lock; |
static void *tty_sigsih; |
|
|
|
struct ttylist_head ttylist = TAILQ_HEAD_INITIALIZER(ttylist); |
struct ttylist_head ttylist = TAILQ_HEAD_INITIALIZER(ttylist); |
int tty_count; |
int tty_count; |
kmutex_t tty_lock; |
|
|
|
POOL_INIT(tty_pool, sizeof(struct tty), 0, 0, 0, "ttypl", |
POOL_INIT(tty_pool, sizeof(struct tty), 0, 0, 0, "ttypl", |
&pool_allocator_nointr, IPL_NONE); |
&pool_allocator_nointr, IPL_NONE); |
Line 225 SYSCTL_SETUP(sysctl_kern_tkstat_setup, " |
|
Line 220 SYSCTL_SETUP(sysctl_kern_tkstat_setup, " |
|
int |
int |
ttyopen(struct tty *tp, int dialout, int nonblock) |
ttyopen(struct tty *tp, int dialout, int nonblock) |
{ |
{ |
int error; |
int s, error; |
|
|
error = 0; |
error = 0; |
|
|
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
|
|
if (dialout) { |
if (dialout) { |
/* |
/* |
Line 252 ttyopen(struct tty *tp, int dialout, int |
|
Line 248 ttyopen(struct tty *tp, int dialout, int |
|
while (ISSET(tp->t_state, TS_DIALOUT) || |
while (ISSET(tp->t_state, TS_DIALOUT) || |
!CONNECTED(tp)) { |
!CONNECTED(tp)) { |
tp->t_wopen++; |
tp->t_wopen++; |
error = ttysleep(tp, &tp->t_rawq.c_cv, true, 0); |
error = ttysleep(tp, &tp->t_rawq, |
|
TTIPRI | PCATCH, ttopen, 0); |
tp->t_wopen--; |
tp->t_wopen--; |
if (error) |
if (error) |
goto out; |
goto out; |
Line 270 ttyopen(struct tty *tp, int dialout, int |
|
Line 267 ttyopen(struct tty *tp, int dialout, int |
|
} |
} |
|
|
out: |
out: |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
return (error); |
return (error); |
} |
} |
|
|
|
|
int |
int |
ttylopen(dev_t device, struct tty *tp) |
ttylopen(dev_t device, struct tty *tp) |
{ |
{ |
|
int s; |
|
|
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
tp->t_dev = device; |
tp->t_dev = device; |
if (!ISSET(tp->t_state, TS_ISOPEN)) { |
if (!ISSET(tp->t_state, TS_ISOPEN)) { |
SET(tp->t_state, TS_ISOPEN); |
SET(tp->t_state, TS_ISOPEN); |
Line 290 ttylopen(dev_t device, struct tty *tp) |
|
Line 290 ttylopen(dev_t device, struct tty *tp) |
|
tp->t_flags = 0; |
tp->t_flags = 0; |
#endif |
#endif |
} |
} |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
return (0); |
return (0); |
} |
} |
|
|
|
|
ttyclose(struct tty *tp) |
ttyclose(struct tty *tp) |
{ |
{ |
extern struct tty *constty; /* Temporary virtual console. */ |
extern struct tty *constty; /* Temporary virtual console. */ |
struct session *sess; |
int s; |
|
|
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
|
|
if (constty == tp) |
if (constty == tp) |
constty = NULL; |
constty = NULL; |
Line 316 ttyclose(struct tty *tp) |
|
Line 318 ttyclose(struct tty *tp) |
|
tp->t_pgrp = NULL; |
tp->t_pgrp = NULL; |
tp->t_state = 0; |
tp->t_state = 0; |
|
|
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
|
|
mutex_enter(&proclist_lock); |
mutex_enter(&proclist_lock); |
if ((sess = tp->t_session) != NULL) { |
s = spltty(); |
|
TTY_LOCK(tp); |
|
if (tp->t_session != NULL) { |
SESSRELE(tp->t_session); |
SESSRELE(tp->t_session); |
tp->t_session = NULL; |
tp->t_session = NULL; |
} |
} |
|
TTY_UNLOCK(tp); |
|
splx(s); |
mutex_exit(&proclist_lock); |
mutex_exit(&proclist_lock); |
|
|
return (0); |
return (0); |
Line 348 ttyclose(struct tty *tp) |
|
Line 355 ttyclose(struct tty *tp) |
|
|
|
/* |
/* |
* ttyinput() helper. |
* ttyinput() helper. |
* Call with the tty lock held. |
* Call at spltty() and with the tty slock held. |
*/ |
*/ |
static int |
static int |
ttyinput_wlock(int c, struct tty *tp) |
ttyinput_wlock(int c, struct tty *tp) |
{ |
{ |
|
const struct cdevsw *cdev; |
int iflag, lflag, i, error; |
int iflag, lflag, i, error; |
u_char *cc; |
u_char *cc; |
|
|
KASSERT(mutex_owned(&tty_lock)); |
|
|
|
/* |
/* |
* If input is pending take it first. |
* If input is pending take it first. |
*/ |
*/ |
Line 389 ttyinput_wlock(int c, struct tty *tp) |
|
Line 395 ttyinput_wlock(int c, struct tty *tp) |
|
return (0); |
return (0); |
else if (ISSET(iflag, BRKINT)) { |
else if (ISSET(iflag, BRKINT)) { |
ttyflush(tp, FREAD | FWRITE); |
ttyflush(tp, FREAD | FWRITE); |
ttysig(tp, TTYSIG_PG1, SIGINT); |
mutex_enter(&proclist_mutex); |
|
pgsignal(tp->t_pgrp, SIGINT, 1); |
|
mutex_exit(&proclist_mutex); |
return (0); |
return (0); |
} else if (ISSET(iflag, PARMRK)) |
} else if (ISSET(iflag, PARMRK)) |
goto parmrk; |
goto parmrk; |
Line 473 ttyinput_wlock(int c, struct tty *tp) |
|
Line 481 ttyinput_wlock(int c, struct tty *tp) |
|
if (!ISSET(lflag, NOFLSH)) |
if (!ISSET(lflag, NOFLSH)) |
ttyflush(tp, FREAD | FWRITE); |
ttyflush(tp, FREAD | FWRITE); |
ttyecho(c, tp); |
ttyecho(c, tp); |
ttysig(tp, TTYSIG_PG1, CCEQ(cc[VINTR], c) ? |
mutex_enter(&proclist_mutex); |
SIGINT : SIGQUIT); |
pgsignal(tp->t_pgrp, |
|
CCEQ(cc[VINTR], c) ? SIGINT : SIGQUIT, 1); |
|
mutex_exit(&proclist_mutex); |
goto endcase; |
goto endcase; |
} |
} |
if (CCEQ(cc[VSUSP], c)) { |
if (CCEQ(cc[VSUSP], c)) { |
if (!ISSET(lflag, NOFLSH)) |
if (!ISSET(lflag, NOFLSH)) |
ttyflush(tp, FREAD); |
ttyflush(tp, FREAD); |
ttyecho(c, tp); |
ttyecho(c, tp); |
ttysig(tp, TTYSIG_PG1, SIGTSTP); |
mutex_enter(&proclist_mutex); |
|
pgsignal(tp->t_pgrp, SIGTSTP, 1); |
|
mutex_exit(&proclist_mutex); |
goto endcase; |
goto endcase; |
} |
} |
} |
} |
Line 492 ttyinput_wlock(int c, struct tty *tp) |
|
Line 504 ttyinput_wlock(int c, struct tty *tp) |
|
if (CCEQ(cc[VSTOP], c)) { |
if (CCEQ(cc[VSTOP], c)) { |
if (!ISSET(tp->t_state, TS_TTSTOP)) { |
if (!ISSET(tp->t_state, TS_TTSTOP)) { |
SET(tp->t_state, TS_TTSTOP); |
SET(tp->t_state, TS_TTSTOP); |
cdev_stop(tp, 0); |
cdev = cdevsw_lookup(tp->t_dev); |
|
if (cdev != NULL) |
|
(*cdev->d_stop)(tp, 0); |
return (0); |
return (0); |
} |
} |
if (!CCEQ(cc[VSTART], c)) |
if (!CCEQ(cc[VSTART], c)) |
Line 607 ttyinput_wlock(int c, struct tty *tp) |
|
Line 621 ttyinput_wlock(int c, struct tty *tp) |
|
if (CCEQ(cc[VSTATUS], c)) { |
if (CCEQ(cc[VSTATUS], c)) { |
if (!ISSET(lflag, NOKERNINFO)) |
if (!ISSET(lflag, NOKERNINFO)) |
ttyinfo(tp, 1); |
ttyinfo(tp, 1); |
if (ISSET(lflag, ISIG)) |
if (ISSET(lflag, ISIG)) { |
ttysig(tp, TTYSIG_PG1, SIGINFO); |
mutex_enter(&proclist_mutex); |
|
pgsignal(tp->t_pgrp, SIGINFO, 1); |
|
mutex_exit(&proclist_mutex); |
|
} |
goto endcase; |
goto endcase; |
} |
} |
} |
} |
Line 677 ttyinput_wlock(int c, struct tty *tp) |
|
Line 694 ttyinput_wlock(int c, struct tty *tp) |
|
|
|
/* |
/* |
* Process input of a single character received on a tty. |
* Process input of a single character received on a tty. |
|
* Must be called at spltty(). |
* |
* |
* XXX - this is a hack, all drivers must changed to acquire the |
* XXX - this is a hack, all drivers must changed to acquire the |
* lock before calling linesw->l_rint() |
* lock before calling linesw->l_rint() |
|
|
ttyinput(int c, struct tty *tp) |
ttyinput(int c, struct tty *tp) |
{ |
{ |
int error; |
int error; |
|
int s; |
|
|
/* |
/* |
* Unless the receiver is enabled, drop incoming data. |
* Unless the receiver is enabled, drop incoming data. |
Line 692 ttyinput(int c, struct tty *tp) |
|
Line 711 ttyinput(int c, struct tty *tp) |
|
if (!ISSET(tp->t_cflag, CREAD)) |
if (!ISSET(tp->t_cflag, CREAD)) |
return (0); |
return (0); |
|
|
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
error = ttyinput_wlock(c, tp); |
error = ttyinput_wlock(c, tp); |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
return (error); |
return (error); |
} |
} |
|
|
Line 704 ttyinput(int c, struct tty *tp) |
|
Line 724 ttyinput(int c, struct tty *tp) |
|
* as needed (expanding tabs, newline processing, etc.). |
* as needed (expanding tabs, newline processing, etc.). |
* Returns < 0 if succeeds, otherwise returns char to resend. |
* Returns < 0 if succeeds, otherwise returns char to resend. |
* Must be recursive. |
* Must be recursive. |
* |
* Call with tty slock held. |
* Call with tty lock held. |
|
*/ |
*/ |
int |
int |
ttyoutput(int c, struct tty *tp) |
ttyoutput(int c, struct tty *tp) |
{ |
{ |
long oflag; |
long oflag; |
int col, notout; |
int col, notout, s; |
|
|
KASSERT(mutex_owned(&tty_lock)); |
|
|
|
oflag = tp->t_oflag; |
oflag = tp->t_oflag; |
if (!ISSET(oflag, OPOST)) { |
if (!ISSET(oflag, OPOST)) { |
Line 736 ttyoutput(int c, struct tty *tp) |
|
Line 753 ttyoutput(int c, struct tty *tp) |
|
if (ISSET(tp->t_lflag, FLUSHO)) { |
if (ISSET(tp->t_lflag, FLUSHO)) { |
notout = 0; |
notout = 0; |
} else { |
} else { |
|
s = spltty(); /* Don't interrupt tabs. */ |
notout = b_to_q(" ", c, &tp->t_outq); |
notout = b_to_q(" ", c, &tp->t_outq); |
c -= notout; |
c -= notout; |
tk_nout += c; |
tk_nout += c; |
tp->t_outcc += c; |
tp->t_outcc += c; |
|
splx(s); |
} |
} |
tp->t_column += c; |
tp->t_column += c; |
return (notout ? '\t' : -1); |
return (notout ? '\t' : -1); |
Line 843 ttioctl(struct tty *tp, u_long cmd, void |
|
Line 862 ttioctl(struct tty *tp, u_long cmd, void |
|
while (isbackground(curproc, tp) && |
while (isbackground(curproc, tp) && |
p->p_pgrp->pg_jobc && (p->p_sflag & PS_PPWAIT) == 0 && |
p->p_pgrp->pg_jobc && (p->p_sflag & PS_PPWAIT) == 0 && |
!sigismasked(l, SIGTTOU)) { |
!sigismasked(l, SIGTTOU)) { |
mutex_spin_enter(&tty_lock); |
mutex_enter(&proclist_mutex); |
ttysig(tp, TTYSIG_PG1, SIGTTOU); |
pgsignal(p->p_pgrp, SIGTTOU, 1); |
error = ttysleep(tp, &lbolt, true, 0); |
mutex_exit(&proclist_mutex); |
mutex_spin_exit(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
|
error = ttysleep(tp, &lbolt, |
|
TTOPRI | PCATCH | PNORELOCK, ttybg, 0); |
|
splx(s); |
if (error) { |
if (error) { |
return (error); |
return (error); |
} |
} |
Line 856 ttioctl(struct tty *tp, u_long cmd, void |
|
Line 879 ttioctl(struct tty *tp, u_long cmd, void |
|
|
|
switch (cmd) { /* Process the ioctl. */ |
switch (cmd) { /* Process the ioctl. */ |
case FIOASYNC: /* set/clear async i/o */ |
case FIOASYNC: /* set/clear async i/o */ |
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
if (*(int *)data) |
if (*(int *)data) |
SET(tp->t_state, TS_ASYNC); |
SET(tp->t_state, TS_ASYNC); |
else |
else |
CLR(tp->t_state, TS_ASYNC); |
CLR(tp->t_state, TS_ASYNC); |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
break; |
break; |
case FIONBIO: /* set/clear non-blocking i/o */ |
case FIONBIO: /* set/clear non-blocking i/o */ |
break; /* XXX: delete. */ |
break; /* XXX: delete. */ |
case FIONREAD: /* get # bytes to read */ |
case FIONREAD: /* get # bytes to read */ |
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
*(int *)data = ttnread(tp); |
*(int *)data = ttnread(tp); |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
break; |
break; |
case FIONWRITE: /* get # bytes to written & unsent */ |
case FIONWRITE: /* get # bytes to written & unsent */ |
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
*(int *)data = tp->t_outq.c_cc; |
*(int *)data = tp->t_outq.c_cc; |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
break; |
break; |
case FIONSPACE: /* get # bytes to written & unsent */ |
case FIONSPACE: /* get # bytes to written & unsent */ |
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
*(int *)data = tp->t_outq.c_cn - tp->t_outq.c_cc; |
*(int *)data = tp->t_outq.c_cn - tp->t_outq.c_cc; |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
break; |
break; |
case TIOCEXCL: /* set exclusive use of tty */ |
case TIOCEXCL: /* set exclusive use of tty */ |
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
SET(tp->t_state, TS_XCLUDE); |
SET(tp->t_state, TS_XCLUDE); |
mutex_spin_exit(&tty_lock); |
splx(s); |
|
TTY_UNLOCK(tp); |
break; |
break; |
case TIOCFLUSH: { /* flush buffers */ |
case TIOCFLUSH: { /* flush buffers */ |
int flags = *(int *)data; |
int flags = *(int *)data; |
Line 892 ttioctl(struct tty *tp, u_long cmd, void |
|
Line 925 ttioctl(struct tty *tp, u_long cmd, void |
|
flags = FREAD | FWRITE; |
flags = FREAD | FWRITE; |
else |
else |
flags &= FREAD | FWRITE; |
flags &= FREAD | FWRITE; |
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
ttyflush(tp, flags); |
ttyflush(tp, flags); |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
break; |
break; |
} |
} |
case TIOCCONS: /* become virtual console */ |
case TIOCCONS: /* become virtual console */ |
Line 905 ttioctl(struct tty *tp, u_long cmd, void |
|
Line 940 ttioctl(struct tty *tp, u_long cmd, void |
|
return EBUSY; |
return EBUSY; |
|
|
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, |
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, |
"/dev/console"); |
"/dev/console", l); |
if ((error = namei(&nd)) != 0) |
if ((error = namei(&nd)) != 0) |
return error; |
return error; |
error = VOP_ACCESS(nd.ni_vp, VREAD, l->l_cred); |
error = VOP_ACCESS(nd.ni_vp, VREAD, l->l_cred, l); |
vput(nd.ni_vp); |
vput(nd.ni_vp); |
if (error) |
if (error) |
return error; |
return error; |
Line 954 ttioctl(struct tty *tp, u_long cmd, void |
|
Line 989 ttioctl(struct tty *tp, u_long cmd, void |
|
break; |
break; |
#ifdef TIOCHPCL |
#ifdef TIOCHPCL |
case TIOCHPCL: /* hang up on last close */ |
case TIOCHPCL: /* hang up on last close */ |
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
SET(tp->t_cflag, HUPCL); |
SET(tp->t_cflag, HUPCL); |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
break; |
break; |
#endif |
#endif |
case TIOCNXCL: /* reset exclusive use of tty */ |
case TIOCNXCL: /* reset exclusive use of tty */ |
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
CLR(tp->t_state, TS_XCLUDE); |
CLR(tp->t_state, TS_XCLUDE); |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
break; |
break; |
case TIOCOUTQ: /* output queue size */ |
case TIOCOUTQ: /* output queue size */ |
*(int *)data = tp->t_outq.c_cc; |
*(int *)data = tp->t_outq.c_cc; |
Line 977 ttioctl(struct tty *tp, u_long cmd, void |
|
Line 1016 ttioctl(struct tty *tp, u_long cmd, void |
|
return (error); |
return (error); |
|
|
if (cmd == TIOCSETAF) { |
if (cmd == TIOCSETAF) { |
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
ttyflush(tp, FREAD); |
ttyflush(tp, FREAD); |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
} |
} |
} |
} |
|
|
Line 989 ttioctl(struct tty *tp, u_long cmd, void |
|
Line 1030 ttioctl(struct tty *tp, u_long cmd, void |
|
* don't take the tty spin lock here. |
* don't take the tty spin lock here. |
* require t_param() to unlock upon callback? |
* require t_param() to unlock upon callback? |
*/ |
*/ |
/* wanted here: mutex_spin_enter(&tty_lock); */ |
/* wanted here: TTY_LOCK(tp); */ |
if (!ISSET(t->c_cflag, CIGNORE)) { |
if (!ISSET(t->c_cflag, CIGNORE)) { |
/* |
/* |
* Set device hardware. |
* Set device hardware. |
*/ |
*/ |
if (tp->t_param && (error = (*tp->t_param)(tp, t))) { |
if (tp->t_param && (error = (*tp->t_param)(tp, t))) { |
/* wanted here: mutex_spin_exit(&tty_lock); */ |
/* wanted here: TTY_UNLOCK(tp); */ |
splx(s); |
splx(s); |
return (error); |
return (error); |
} else { |
} else { |
tp->t_cflag = t->c_cflag; |
tp->t_cflag = t->c_cflag; |
tp->t_ispeed = t->c_ispeed; |
tp->t_ispeed = t->c_ispeed; |
tp->t_ospeed = t->c_ospeed; |
tp->t_ospeed = t->c_ospeed; |
if (t->c_ospeed == 0) |
if (t->c_ospeed == 0 && tp->t_session && |
ttysig(tp, TTYSIG_LEADER, SIGHUP); |
tp->t_session->s_leader) { |
|
mutex_enter(&proclist_mutex); |
|
psignal(tp->t_session->s_leader, |
|
SIGHUP); |
|
mutex_exit(&proclist_mutex); |
|
} |
} |
} |
ttsetwater(tp); |
ttsetwater(tp); |
} |
} |
|
|
/* delayed lock acquiring */ |
/* delayed lock acquiring */TTY_LOCK(tp); |
mutex_spin_enter(&tty_lock); |
|
if (cmd != TIOCSETAF) { |
if (cmd != TIOCSETAF) { |
if (ISSET(t->c_lflag, ICANON) != |
if (ISSET(t->c_lflag, ICANON) != |
ISSET(tp->t_lflag, ICANON)) { |
ISSET(tp->t_lflag, ICANON)) { |
Line 1038 ttioctl(struct tty *tp, u_long cmd, void |
|
Line 1083 ttioctl(struct tty *tp, u_long cmd, void |
|
CLR(t->c_lflag, EXTPROC); |
CLR(t->c_lflag, EXTPROC); |
tp->t_lflag = t->c_lflag | ISSET(tp->t_lflag, PENDIN); |
tp->t_lflag = t->c_lflag | ISSET(tp->t_lflag, PENDIN); |
memcpy(tp->t_cc, t->c_cc, sizeof(t->c_cc)); |
memcpy(tp->t_cc, t->c_cc, sizeof(t->c_cc)); |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
splx(s); |
splx(s); |
break; |
break; |
} |
} |
Line 1078 ttioctl(struct tty *tp, u_long cmd, void |
|
Line 1123 ttioctl(struct tty *tp, u_long cmd, void |
|
break; |
break; |
} |
} |
case TIOCSTART: /* start output, like ^Q */ |
case TIOCSTART: /* start output, like ^Q */ |
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
if (ISSET(tp->t_state, TS_TTSTOP) || |
if (ISSET(tp->t_state, TS_TTSTOP) || |
ISSET(tp->t_lflag, FLUSHO)) { |
ISSET(tp->t_lflag, FLUSHO)) { |
CLR(tp->t_lflag, FLUSHO); |
CLR(tp->t_lflag, FLUSHO); |
CLR(tp->t_state, TS_TTSTOP); |
CLR(tp->t_state, TS_TTSTOP); |
ttstart(tp); |
ttstart(tp); |
} |
} |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
break; |
break; |
case TIOCSTI: /* simulate terminal input */ |
case TIOCSTI: /* simulate terminal input */ |
if (kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, |
if (kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, |
Line 1099 ttioctl(struct tty *tp, u_long cmd, void |
|
Line 1146 ttioctl(struct tty *tp, u_long cmd, void |
|
break; |
break; |
case TIOCSTOP: /* stop output, like ^S */ |
case TIOCSTOP: /* stop output, like ^S */ |
{ |
{ |
mutex_spin_enter(&tty_lock); |
const struct cdevsw *cdev; |
|
s = spltty(); |
|
TTY_LOCK(tp); |
if (!ISSET(tp->t_state, TS_TTSTOP)) { |
if (!ISSET(tp->t_state, TS_TTSTOP)) { |
SET(tp->t_state, TS_TTSTOP); |
SET(tp->t_state, TS_TTSTOP); |
cdev_stop(tp, 0); |
cdev = cdevsw_lookup(tp->t_dev); |
|
if (cdev != NULL) |
|
(*cdev->d_stop)(tp, 0); |
} |
} |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
break; |
break; |
} |
} |
case TIOCSCTTY: /* become controlling tty */ |
case TIOCSCTTY: /* become controlling tty */ |
Line 1180 ttioctl(struct tty *tp, u_long cmd, void |
|
Line 1232 ttioctl(struct tty *tp, u_long cmd, void |
|
break; |
break; |
} |
} |
case TIOCSTAT: /* get load avg stats */ |
case TIOCSTAT: /* get load avg stats */ |
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
ttyinfo(tp, 0); |
ttyinfo(tp, 0); |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
break; |
break; |
case TIOCSWINSZ: /* set window size */ |
case TIOCSWINSZ: /* set window size */ |
mutex_spin_enter(&tty_lock); |
|
if (memcmp((void *)&tp->t_winsize, data, |
if (memcmp((void *)&tp->t_winsize, data, |
sizeof(struct winsize))) { |
sizeof(struct winsize))) { |
tp->t_winsize = *(struct winsize *)data; |
tp->t_winsize = *(struct winsize *)data; |
ttysig(tp, TTYSIG_PG1, SIGWINCH); |
mutex_enter(&proclist_mutex); |
|
pgsignal(tp->t_pgrp, SIGWINCH, 1); |
|
mutex_exit(&proclist_mutex); |
} |
} |
mutex_spin_exit(&tty_lock); |
|
break; |
break; |
default: |
default: |
#ifdef COMPAT_OLDTTY |
#ifdef COMPAT_OLDTTY |
Line 1206 ttioctl(struct tty *tp, u_long cmd, void |
|
Line 1260 ttioctl(struct tty *tp, u_long cmd, void |
|
int |
int |
ttpoll(struct tty *tp, int events, struct lwp *l) |
ttpoll(struct tty *tp, int events, struct lwp *l) |
{ |
{ |
int revents; |
int revents, s; |
|
|
revents = 0; |
revents = 0; |
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
if (events & (POLLIN | POLLRDNORM)) |
if (events & (POLLIN | POLLRDNORM)) |
if (ttnread(tp) > 0) |
if (ttnread(tp) > 0) |
revents |= events & (POLLIN | POLLRDNORM); |
revents |= events & (POLLIN | POLLRDNORM); |
Line 1230 ttpoll(struct tty *tp, int events, struc |
|
Line 1285 ttpoll(struct tty *tp, int events, struc |
|
selrecord(l, &tp->t_wsel); |
selrecord(l, &tp->t_wsel); |
} |
} |
|
|
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
return (revents); |
return (revents); |
} |
} |
|
|
|
|
filt_ttyrdetach(struct knote *kn) |
filt_ttyrdetach(struct knote *kn) |
{ |
{ |
struct tty *tp; |
struct tty *tp; |
|
int s; |
|
|
tp = kn->kn_hook; |
tp = kn->kn_hook; |
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
SLIST_REMOVE(&tp->t_rsel.sel_klist, kn, knote, kn_selnext); |
SLIST_REMOVE(&tp->t_rsel.sel_klist, kn, knote, kn_selnext); |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
} |
} |
|
|
static int |
static int |
filt_ttyread(struct knote *kn, long hint) |
filt_ttyread(struct knote *kn, long hint) |
{ |
{ |
struct tty *tp; |
struct tty *tp; |
|
int s; |
|
|
tp = kn->kn_hook; |
tp = kn->kn_hook; |
|
s = spltty(); |
if ((hint & NOTE_SUBMIT) == 0) |
if ((hint & NOTE_SUBMIT) == 0) |
mutex_spin_enter(&tty_lock); |
TTY_LOCK(tp); |
kn->kn_data = ttnread(tp); |
kn->kn_data = ttnread(tp); |
if ((hint & NOTE_SUBMIT) == 0) |
if ((hint & NOTE_SUBMIT) == 0) |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
return (kn->kn_data > 0); |
return (kn->kn_data > 0); |
} |
} |
|
|
|
|
filt_ttywdetach(struct knote *kn) |
filt_ttywdetach(struct knote *kn) |
{ |
{ |
struct tty *tp; |
struct tty *tp; |
|
int s; |
|
|
tp = kn->kn_hook; |
tp = kn->kn_hook; |
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
SLIST_REMOVE(&tp->t_wsel.sel_klist, kn, knote, kn_selnext); |
SLIST_REMOVE(&tp->t_wsel.sel_klist, kn, knote, kn_selnext); |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
} |
} |
|
|
static int |
static int |
filt_ttywrite(struct knote *kn, long hint) |
filt_ttywrite(struct knote *kn, long hint) |
{ |
{ |
struct tty *tp; |
struct tty *tp; |
int canwrite; |
int canwrite, s; |
|
|
tp = kn->kn_hook; |
tp = kn->kn_hook; |
|
s = spltty(); |
if ((hint & NOTE_SUBMIT) == 0) |
if ((hint & NOTE_SUBMIT) == 0) |
mutex_spin_enter(&tty_lock); |
TTY_LOCK(tp); |
kn->kn_data = tp->t_outq.c_cn - tp->t_outq.c_cc; |
kn->kn_data = tp->t_outq.c_cn - tp->t_outq.c_cc; |
canwrite = (tp->t_outq.c_cc <= tp->t_lowat) && CONNECTED(tp); |
canwrite = (tp->t_outq.c_cc <= tp->t_lowat) && CONNECTED(tp); |
if ((hint & NOTE_SUBMIT) == 0) |
if ((hint & NOTE_SUBMIT) == 0) |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
return (canwrite); |
return (canwrite); |
} |
} |
|
|
Line 1297 ttykqfilter(dev_t dev, struct knote *kn) |
|
Line 1363 ttykqfilter(dev_t dev, struct knote *kn) |
|
{ |
{ |
struct tty *tp; |
struct tty *tp; |
struct klist *klist; |
struct klist *klist; |
|
int s; |
|
const struct cdevsw *cdev; |
|
|
if ((tp = cdev_tty(dev)) == NULL) |
if (((cdev = cdevsw_lookup(dev)) == NULL) || |
|
(cdev->d_tty == NULL) || |
|
((tp = (*cdev->d_tty)(dev)) == NULL)) |
return (ENXIO); |
return (ENXIO); |
|
|
switch (kn->kn_filter) { |
switch (kn->kn_filter) { |
Line 1316 ttykqfilter(dev_t dev, struct knote *kn) |
|
Line 1386 ttykqfilter(dev_t dev, struct knote *kn) |
|
|
|
kn->kn_hook = tp; |
kn->kn_hook = tp; |
|
|
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
SLIST_INSERT_HEAD(klist, kn, kn_selnext); |
SLIST_INSERT_HEAD(klist, kn, kn_selnext); |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
|
|
return (0); |
return (0); |
} |
} |
|
|
/* |
/* |
* Find the number of chars ready to be read from this tty. |
* Find the number of chars ready to be read from this tty. |
* Call with the tty lock held. |
* Call at spltty() and with the tty slock held. |
*/ |
*/ |
static int |
static int |
ttnread(struct tty *tp) |
ttnread(struct tty *tp) |
{ |
{ |
int nread; |
int nread; |
|
|
KASSERT(mutex_owned(&tty_lock)); |
|
|
|
if (ISSET(tp->t_lflag, PENDIN)) |
if (ISSET(tp->t_lflag, PENDIN)) |
ttypend(tp); |
ttypend(tp); |
nread = tp->t_canq.c_cc; |
nread = tp->t_canq.c_cc; |
Line 1351 ttnread(struct tty *tp) |
|
Line 1421 ttnread(struct tty *tp) |
|
int |
int |
ttywait(struct tty *tp) |
ttywait(struct tty *tp) |
{ |
{ |
int error; |
int error, s; |
|
|
error = 0; |
error = 0; |
|
s = spltty(); |
mutex_spin_enter(&tty_lock); |
TTY_LOCK(tp); |
while ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) && |
while ((tp->t_outq.c_cc || ISSET(tp->t_state, TS_BUSY)) && |
CONNECTED(tp) && tp->t_oproc) { |
CONNECTED(tp) && tp->t_oproc) { |
(*tp->t_oproc)(tp); |
(*tp->t_oproc)(tp); |
error = ttysleep(tp, &tp->t_outq.c_cv, true, 0); |
SET(tp->t_state, TS_ASLEEP); |
|
error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0); |
if (error) |
if (error) |
break; |
break; |
} |
} |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
return (error); |
return (error); |
} |
} |
|
|
|
|
ttywflush(struct tty *tp) |
ttywflush(struct tty *tp) |
{ |
{ |
int error; |
int error; |
|
int s; |
|
|
if ((error = ttywait(tp)) == 0) { |
if ((error = ttywait(tp)) == 0) { |
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
ttyflush(tp, FREAD); |
ttyflush(tp, FREAD); |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
} |
} |
return (error); |
return (error); |
} |
} |
|
|
/* |
/* |
* Flush tty read and/or write queues, notifying anyone waiting. |
* Flush tty read and/or write queues, notifying anyone waiting. |
* Call with the tty lock held. |
* Call at spltty() and with the tty slock held. |
*/ |
*/ |
void |
void |
ttyflush(struct tty *tp, int rw) |
ttyflush(struct tty *tp, int rw) |
{ |
{ |
|
const struct cdevsw *cdev; |
KASSERT(mutex_owned(&tty_lock)); |
|
|
|
if (rw & FREAD) { |
if (rw & FREAD) { |
FLUSHQ(&tp->t_canq); |
FLUSHQ(&tp->t_canq); |
Line 1404 ttyflush(struct tty *tp, int rw) |
|
Line 1477 ttyflush(struct tty *tp, int rw) |
|
} |
} |
if (rw & FWRITE) { |
if (rw & FWRITE) { |
CLR(tp->t_state, TS_TTSTOP); |
CLR(tp->t_state, TS_TTSTOP); |
cdev_stop(tp, rw); |
cdev = cdevsw_lookup(tp->t_dev); |
|
if (cdev != NULL) |
|
(*cdev->d_stop)(tp, rw); |
FLUSHQ(&tp->t_outq); |
FLUSHQ(&tp->t_outq); |
clwakeup(&tp->t_outq); |
wakeup((void *)&tp->t_outq); |
selnotify(&tp->t_wsel, NOTE_SUBMIT); |
selnotify(&tp->t_wsel, NOTE_SUBMIT); |
} |
} |
} |
} |
Line 1423 ttychars(struct tty *tp) |
|
Line 1498 ttychars(struct tty *tp) |
|
|
|
/* |
/* |
* Send stop character on input overflow. |
* Send stop character on input overflow. |
* Call with the tty lock held. |
* Call at spltty() and with the tty slock held. |
*/ |
*/ |
static void |
static void |
ttyblock(struct tty *tp) |
ttyblock(struct tty *tp) |
{ |
{ |
int total; |
int total; |
|
|
KASSERT(mutex_owned(&tty_lock)); |
|
|
|
total = tp->t_rawq.c_cc + tp->t_canq.c_cc; |
total = tp->t_rawq.c_cc + tp->t_canq.c_cc; |
if (tp->t_rawq.c_cc > TTYHOG) { |
if (tp->t_rawq.c_cc > TTYHOG) { |
ttyflush(tp, FREAD | FWRITE); |
ttyflush(tp, FREAD | FWRITE); |
|
|
ttrstrt(void *tp_arg) |
ttrstrt(void *tp_arg) |
{ |
{ |
struct tty *tp; |
struct tty *tp; |
|
int s; |
|
|
#ifdef DIAGNOSTIC |
#ifdef DIAGNOSTIC |
if (tp_arg == NULL) |
if (tp_arg == NULL) |
panic("ttrstrt"); |
panic("ttrstrt"); |
#endif |
#endif |
tp = tp_arg; |
tp = tp_arg; |
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
|
|
CLR(tp->t_state, TS_TIMEOUT); |
CLR(tp->t_state, TS_TIMEOUT); |
ttstart(tp); /* XXX - Shouldn't this be tp->l_start(tp)? */ |
ttstart(tp); /* XXX - Shouldn't this be tp->l_start(tp)? */ |
|
|
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
} |
} |
|
|
/* |
/* |
* start a line discipline |
* start a line discipline |
* Always call with tty lock held? |
* Always call at spltty() and with tty slock held? |
*/ |
*/ |
int |
int |
ttstart(struct tty *tp) |
ttstart(struct tty *tp) |
Line 1497 ttstart(struct tty *tp) |
|
Line 1573 ttstart(struct tty *tp) |
|
int |
int |
ttylclose(struct tty *tp, int flag) |
ttylclose(struct tty *tp, int flag) |
{ |
{ |
|
int s; |
|
|
if (flag & FNONBLOCK) { |
if (flag & FNONBLOCK) { |
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
ttyflush(tp, FREAD | FWRITE); |
ttyflush(tp, FREAD | FWRITE); |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
} else |
} else |
ttywflush(tp); |
ttywflush(tp); |
return (0); |
return (0); |
Line 1511 ttylclose(struct tty *tp, int flag) |
|
Line 1590 ttylclose(struct tty *tp, int flag) |
|
* Handle modem control transition on a tty. |
* Handle modem control transition on a tty. |
* Flag indicates new state of carrier. |
* Flag indicates new state of carrier. |
* Returns 0 if the line should be turned off, otherwise 1. |
* Returns 0 if the line should be turned off, otherwise 1. |
|
* |
|
* Must be called at spltty(). |
|
* XXX except that it is often isn't, which should be fixed. |
*/ |
*/ |
int |
int |
ttymodem(struct tty *tp, int flag) |
ttymodem(struct tty *tp, int flag) |
{ |
{ |
|
int s; |
|
|
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
if (flag == 0) { |
if (flag == 0) { |
if (ISSET(tp->t_state, TS_CARR_ON)) { |
if (ISSET(tp->t_state, TS_CARR_ON)) { |
/* |
/* |
Line 1524 ttymodem(struct tty *tp, int flag) |
|
Line 1608 ttymodem(struct tty *tp, int flag) |
|
*/ |
*/ |
CLR(tp->t_state, TS_CARR_ON); |
CLR(tp->t_state, TS_CARR_ON); |
if (ISSET(tp->t_state, TS_ISOPEN) && !CONNECTED(tp)) { |
if (ISSET(tp->t_state, TS_ISOPEN) && !CONNECTED(tp)) { |
ttysig(tp, TTYSIG_LEADER, SIGHUP); |
if (tp->t_session && tp->t_session->s_leader) { |
|
mutex_enter(&proclist_mutex); |
|
psignal(tp->t_session->s_leader, |
|
SIGHUP); |
|
mutex_exit(&proclist_mutex); |
|
} |
ttyflush(tp, FREAD | FWRITE); |
ttyflush(tp, FREAD | FWRITE); |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
return (0); |
return (0); |
} |
} |
} |
} |
Line 1539 ttymodem(struct tty *tp, int flag) |
|
Line 1629 ttymodem(struct tty *tp, int flag) |
|
ttwakeup(tp); |
ttwakeup(tp); |
} |
} |
} |
} |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
return (1); |
return (1); |
} |
} |
|
|
/* |
/* |
* Default modem control routine (for other line disciplines). |
* Default modem control routine (for other line disciplines). |
* Return argument flag, to turn off device on carrier drop. |
* Return argument flag, to turn off device on carrier drop. |
|
* |
|
* Must be called at spltty(). |
|
* XXX except that it is often isn't, which should be fixed. |
*/ |
*/ |
int |
int |
nullmodem(struct tty *tp, int flag) |
nullmodem(struct tty *tp, int flag) |
{ |
{ |
|
int s; |
|
|
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
if (flag) |
if (flag) |
SET(tp->t_state, TS_CARR_ON); |
SET(tp->t_state, TS_CARR_ON); |
else { |
else { |
CLR(tp->t_state, TS_CARR_ON); |
CLR(tp->t_state, TS_CARR_ON); |
if (!CONNECTED(tp)) { |
if (!CONNECTED(tp)) { |
ttysig(tp, TTYSIG_LEADER, SIGHUP); |
if (tp->t_session && tp->t_session->s_leader) { |
mutex_spin_exit(&tty_lock); |
mutex_enter(&proclist_mutex); |
|
psignal(tp->t_session->s_leader, SIGHUP); |
|
mutex_exit(&proclist_mutex); |
|
} |
|
TTY_UNLOCK(tp); |
|
splx(s); |
return (0); |
return (0); |
} |
} |
} |
} |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
return (1); |
return (1); |
} |
} |
|
|
/* |
/* |
* Reinput pending characters after state switch. |
* Reinput pending characters after state switch. |
|
* Call at spltty() and with the tty slock held. |
*/ |
*/ |
void |
void |
ttypend(struct tty *tp) |
ttypend(struct tty *tp) |
Line 1577 ttypend(struct tty *tp) |
|
Line 1678 ttypend(struct tty *tp) |
|
struct clist tq; |
struct clist tq; |
int c; |
int c; |
|
|
KASSERT(mutex_owned(&tty_lock)); |
|
|
|
CLR(tp->t_lflag, PENDIN); |
CLR(tp->t_lflag, PENDIN); |
SET(tp->t_state, TS_TYPEN); |
SET(tp->t_state, TS_TYPEN); |
tq = tp->t_rawq; |
tq = tp->t_rawq; |
Line 1598 ttread(struct tty *tp, struct uio *uio, |
|
Line 1697 ttread(struct tty *tp, struct uio *uio, |
|
struct clist *qp; |
struct clist *qp; |
u_char *cc; |
u_char *cc; |
struct proc *p; |
struct proc *p; |
int c, first, error, has_stime, last_cc; |
int c, s, first, error, has_stime, last_cc; |
long lflag, slp; |
long lflag, slp; |
struct timeval now, stime; |
struct timeval now, stime; |
|
|
Line 1613 ttread(struct tty *tp, struct uio *uio, |
|
Line 1712 ttread(struct tty *tp, struct uio *uio, |
|
slp = 0; |
slp = 0; |
|
|
loop: |
loop: |
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
lflag = tp->t_lflag; |
lflag = tp->t_lflag; |
/* |
/* |
* take pending input first |
* take pending input first |
Line 1628 ttread(struct tty *tp, struct uio *uio, |
|
Line 1728 ttread(struct tty *tp, struct uio *uio, |
|
if (sigismember(&p->p_sigctx.ps_sigignore, SIGTTIN) || |
if (sigismember(&p->p_sigctx.ps_sigignore, SIGTTIN) || |
sigismember(&curlwp->l_sigmask, SIGTTIN) || |
sigismember(&curlwp->l_sigmask, SIGTTIN) || |
p->p_sflag & PS_PPWAIT || p->p_pgrp->pg_jobc == 0) { |
p->p_sflag & PS_PPWAIT || p->p_pgrp->pg_jobc == 0) { |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
return (EIO); |
return (EIO); |
} |
} |
ttysig(tp, TTYSIG_PG1, SIGTTIN); |
mutex_enter(&proclist_mutex); |
error = ttysleep(tp, &lbolt, true, 0); |
pgsignal(p->p_pgrp, SIGTTIN, 1); |
mutex_spin_exit(&tty_lock); |
mutex_exit(&proclist_mutex); |
|
error = ttysleep(tp, &lbolt, TTIPRI | PCATCH | PNORELOCK, ttybg, 0); |
|
splx(s); |
if (error) |
if (error) |
return (error); |
return (error); |
goto loop; |
goto loop; |
Line 1722 ttread(struct tty *tp, struct uio *uio, |
|
Line 1825 ttread(struct tty *tp, struct uio *uio, |
|
*/ |
*/ |
carrier = CONNECTED(tp); |
carrier = CONNECTED(tp); |
if (!carrier && ISSET(tp->t_state, TS_ISOPEN)) { |
if (!carrier && ISSET(tp->t_state, TS_ISOPEN)) { |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
return (0); /* EOF */ |
return (0); /* EOF */ |
} |
} |
if (flag & IO_NDELAY) { |
if (flag & IO_NDELAY) { |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
return (EWOULDBLOCK); |
return (EWOULDBLOCK); |
} |
} |
error = ttysleep(tp, &tp->t_rawq.c_cv, true, slp); |
error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH | PNORELOCK, |
mutex_spin_exit(&tty_lock); |
carrier ? ttyin : ttopen, slp); |
|
splx(s); |
/* VMIN == 0: any quantity read satisfies */ |
/* VMIN == 0: any quantity read satisfies */ |
if (cc[VMIN] == 0 && error == EWOULDBLOCK) |
if (cc[VMIN] == 0 && error == EWOULDBLOCK) |
return (0); |
return (0); |
Line 1739 ttread(struct tty *tp, struct uio *uio, |
|
Line 1845 ttread(struct tty *tp, struct uio *uio, |
|
goto loop; |
goto loop; |
} |
} |
read: |
read: |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
|
|
/* |
/* |
* Input present, check for input mapping and processing. |
* Input present, check for input mapping and processing. |
Line 1751 ttread(struct tty *tp, struct uio *uio, |
|
Line 1858 ttread(struct tty *tp, struct uio *uio, |
|
*/ |
*/ |
if (CCEQ(cc[VDSUSP], c) && |
if (CCEQ(cc[VDSUSP], c) && |
ISSET(lflag, IEXTEN|ISIG) == (IEXTEN|ISIG)) { |
ISSET(lflag, IEXTEN|ISIG) == (IEXTEN|ISIG)) { |
mutex_spin_enter(&tty_lock); |
mutex_enter(&proclist_mutex); |
ttysig(tp, TTYSIG_PG1, SIGTSTP); |
pgsignal(tp->t_pgrp, SIGTSTP, 1); |
|
mutex_exit(&proclist_mutex); |
if (first) { |
if (first) { |
error = ttysleep(tp, &lbolt, true, 0); |
s = spltty(); |
mutex_spin_exit(&tty_lock); |
TTY_LOCK(tp); |
|
error = ttysleep(tp, &lbolt, |
|
TTIPRI | PCATCH | PNORELOCK, ttybg, 0); |
|
splx(s); |
if (error) |
if (error) |
break; |
break; |
goto loop; |
goto loop; |
} else |
} |
mutex_spin_exit(&tty_lock); |
|
break; |
break; |
} |
} |
/* |
/* |
Line 1788 ttread(struct tty *tp, struct uio *uio, |
|
Line 1898 ttread(struct tty *tp, struct uio *uio, |
|
* Look to unblock output now that (presumably) |
* Look to unblock output now that (presumably) |
* the input queue has gone down. |
* the input queue has gone down. |
*/ |
*/ |
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
if (ISSET(tp->t_state, TS_TBLOCK) && tp->t_rawq.c_cc < TTYHOG / 5) { |
if (ISSET(tp->t_state, TS_TBLOCK) && tp->t_rawq.c_cc < TTYHOG / 5) { |
if (ISSET(tp->t_iflag, IXOFF) && |
if (ISSET(tp->t_iflag, IXOFF) && |
cc[VSTART] != _POSIX_VDISABLE && |
cc[VSTART] != _POSIX_VDISABLE && |
Line 1801 ttread(struct tty *tp, struct uio *uio, |
|
Line 1912 ttread(struct tty *tp, struct uio *uio, |
|
(*tp->t_hwiflow)(tp, 0) != 0) |
(*tp->t_hwiflow)(tp, 0) != 0) |
CLR(tp->t_state, TS_TBLOCK); |
CLR(tp->t_state, TS_TBLOCK); |
} |
} |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
return (error); |
return (error); |
} |
} |
|
|
Line 1812 ttread(struct tty *tp, struct uio *uio, |
|
Line 1923 ttread(struct tty *tp, struct uio *uio, |
|
* lose messages due to normal flow control, but don't let the tty run amok. |
* lose messages due to normal flow control, but don't let the tty run amok. |
* Sleeps here are not interruptible, but we return prematurely if new signals |
* Sleeps here are not interruptible, but we return prematurely if new signals |
* arrive. |
* arrive. |
* Call with tty lock held. |
* Call with tty slock held. |
*/ |
*/ |
static int |
static int |
ttycheckoutq_wlock(struct tty *tp, int wait) |
ttycheckoutq_wlock(struct tty *tp, int wait) |
{ |
{ |
int hiwat, error; |
int hiwat, s, error; |
|
|
KASSERT(mutex_owned(&tty_lock)); |
|
|
|
hiwat = tp->t_hiwat; |
hiwat = tp->t_hiwat; |
|
s = spltty(); |
if (tp->t_outq.c_cc > hiwat + 200) |
if (tp->t_outq.c_cc > hiwat + 200) |
while (tp->t_outq.c_cc > hiwat) { |
while (tp->t_outq.c_cc > hiwat) { |
ttstart(tp); |
ttstart(tp); |
if (wait == 0) |
if (wait == 0) { |
|
splx(s); |
return (0); |
return (0); |
error = ttysleep(tp, &tp->t_outq.c_cv, true, hz); |
} |
|
SET(tp->t_state, TS_ASLEEP); |
|
error = ltsleep(&tp->t_outq, (PZERO - 1) | PCATCH, |
|
"ttckoutq", hz, &tp->t_slock); |
if (error == EINTR) |
if (error == EINTR) |
wait = 0; |
wait = 0; |
} |
} |
|
|
|
splx(s); |
return (1); |
return (1); |
} |
} |
|
|
int |
int |
ttycheckoutq(struct tty *tp, int wait) |
ttycheckoutq(struct tty *tp, int wait) |
{ |
{ |
int r; |
int r, s; |
|
|
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
r = ttycheckoutq_wlock(tp, wait); |
r = ttycheckoutq_wlock(tp, wait); |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
return (r); |
return (r); |
} |
} |
|
|
Line 1855 ttwrite(struct tty *tp, struct uio *uio, |
|
Line 1971 ttwrite(struct tty *tp, struct uio *uio, |
|
{ |
{ |
u_char *cp; |
u_char *cp; |
struct proc *p; |
struct proc *p; |
int cc, ce, i, hiwat, error; |
int cc, ce, i, hiwat, error, s; |
size_t cnt; |
size_t cnt; |
u_char obuf[OBUFSIZ]; |
u_char obuf[OBUFSIZ]; |
|
|
Line 1865 ttwrite(struct tty *tp, struct uio *uio, |
|
Line 1981 ttwrite(struct tty *tp, struct uio *uio, |
|
error = 0; |
error = 0; |
cc = 0; |
cc = 0; |
loop: |
loop: |
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
if (!CONNECTED(tp)) { |
if (!CONNECTED(tp)) { |
if (ISSET(tp->t_state, TS_ISOPEN)) { |
if (ISSET(tp->t_state, TS_ISOPEN)) { |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
return (EIO); |
return (EIO); |
} else if (flag & IO_NDELAY) { |
} else if (flag & IO_NDELAY) { |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
error = EWOULDBLOCK; |
error = EWOULDBLOCK; |
goto out; |
goto out; |
} else { |
} else { |
/* Sleep awaiting carrier. */ |
/* Sleep awaiting carrier. */ |
error = ttysleep(tp, &tp->t_rawq.c_cv, true, 0); |
error = ttysleep(tp, |
mutex_spin_exit(&tty_lock); |
&tp->t_rawq, TTIPRI | PCATCH | PNORELOCK, ttopen, 0); |
|
splx(s); |
if (error) |
if (error) |
goto out; |
goto out; |
goto loop; |
goto loop; |
} |
} |
} |
} |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
/* |
/* |
* Hang the process if it's in the background. XXXSMP |
* Hang the process if it's in the background. XXXSMP |
*/ |
*/ |
Line 1896 ttwrite(struct tty *tp, struct uio *uio, |
|
Line 2017 ttwrite(struct tty *tp, struct uio *uio, |
|
error = EIO; |
error = EIO; |
goto out; |
goto out; |
} |
} |
mutex_spin_enter(&tty_lock); |
mutex_enter(&proclist_mutex); |
ttysig(tp, TTYSIG_PG1, SIGTTOU); |
pgsignal(p->p_pgrp, SIGTTOU, 1); |
error = ttysleep(tp, &lbolt, true, 0); |
mutex_exit(&proclist_mutex); |
mutex_spin_exit(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
|
error = ttysleep(tp, &lbolt, TTIPRI | PCATCH | PNORELOCK, ttybg, 0); |
|
splx(s); |
if (error) |
if (error) |
goto out; |
goto out; |
goto loop; |
goto loop; |
Line 1938 ttwrite(struct tty *tp, struct uio *uio, |
|
Line 2062 ttwrite(struct tty *tp, struct uio *uio, |
|
* a hunk of data, look for FLUSHO so ^O's will take effect |
* a hunk of data, look for FLUSHO so ^O's will take effect |
* immediately. |
* immediately. |
*/ |
*/ |
mutex_spin_enter(&tty_lock); |
s = spltty(); |
|
TTY_LOCK(tp); |
while (cc > 0) { |
while (cc > 0) { |
if (!ISSET(tp->t_oflag, OPOST)) |
if (!ISSET(tp->t_oflag, OPOST)) |
ce = cc; |
ce = cc; |
Line 1953 ttwrite(struct tty *tp, struct uio *uio, |
|
Line 2078 ttwrite(struct tty *tp, struct uio *uio, |
|
tp->t_rocount = 0; |
tp->t_rocount = 0; |
if (ttyoutput(*cp, tp) >= 0) { |
if (ttyoutput(*cp, tp) >= 0) { |
/* out of space */ |
/* out of space */ |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
goto overfull; |
goto overfull; |
} |
} |
cp++; |
cp++; |
cc--; |
cc--; |
if (ISSET(tp->t_lflag, FLUSHO) || |
if (ISSET(tp->t_lflag, FLUSHO) || |
tp->t_outq.c_cc > hiwat) { |
tp->t_outq.c_cc > hiwat) { |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
goto ovhiwat; |
goto ovhiwat; |
} |
} |
continue; |
continue; |
Line 1982 ttwrite(struct tty *tp, struct uio *uio, |
|
Line 2109 ttwrite(struct tty *tp, struct uio *uio, |
|
tp->t_outcc += ce; |
tp->t_outcc += ce; |
if (i > 0) { |
if (i > 0) { |
/* out of space */ |
/* out of space */ |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
goto overfull; |
goto overfull; |
} |
} |
if (ISSET(tp->t_lflag, FLUSHO) || |
if (ISSET(tp->t_lflag, FLUSHO) || |
tp->t_outq.c_cc > hiwat) |
tp->t_outq.c_cc > hiwat) |
break; |
break; |
} |
} |
|
TTY_UNLOCK(tp); |
|
splx(s); |
ttstart(tp); |
ttstart(tp); |
mutex_spin_exit(&tty_lock); |
|
} |
} |
|
|
out: |
out: |
Line 2012 ttwrite(struct tty *tp, struct uio *uio, |
|
Line 2141 ttwrite(struct tty *tp, struct uio *uio, |
|
hiwat = tp->t_outq.c_cc - 1; |
hiwat = tp->t_outq.c_cc - 1; |
|
|
ovhiwat: |
ovhiwat: |
mutex_spin_enter(&tty_lock); |
|
ttstart(tp); |
ttstart(tp); |
|
s = spltty(); |
|
TTY_LOCK(tp); |
/* |
/* |
* This can only occur if FLUSHO is set in t_lflag, |
* This can only occur if FLUSHO is set in t_lflag, |
* or if ttstart/oproc is synchronous (or very fast). |
* or if ttstart/oproc is synchronous (or very fast). |
*/ |
*/ |
if (tp->t_outq.c_cc <= hiwat) { |
if (tp->t_outq.c_cc <= hiwat) { |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
goto loop; |
goto loop; |
} |
} |
if (flag & IO_NDELAY) { |
if (flag & IO_NDELAY) { |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
error = EWOULDBLOCK; |
error = EWOULDBLOCK; |
goto out; |
goto out; |
} |
} |
error = ttysleep(tp, &tp->t_outq.c_cv, true, 0); |
SET(tp->t_state, TS_ASLEEP); |
mutex_spin_exit(&tty_lock); |
error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH | PNORELOCK, ttyout, 0); |
|
splx(s); |
if (error) |
if (error) |
goto out; |
goto out; |
goto loop; |
goto loop; |
} |
} |
|
|
/* |
/* |
* Try to pull more output from the producer. Return non-zero if |
|
* there is output ready to be sent. |
|
*/ |
|
bool |
|
ttypull(struct tty *tp) |
|
{ |
|
|
|
/* XXXSMP not yet KASSERT(mutex_owned(&tty_lock)); */ |
|
|
|
if (tp->t_outq.c_cc <= tp->t_lowat) { |
|
clwakeup(&tp->t_outq); |
|
selnotify(&tp->t_wsel, NOTE_SUBMIT); |
|
} |
|
return tp->t_outq.c_cc != 0; |
|
} |
|
|
|
/* |
|
* Rubout one character from the rawq of tp |
* Rubout one character from the rawq of tp |
* as cleanly as possible. |
* as cleanly as possible. |
* Called with tty lock held. |
* Called with tty slock held. |
*/ |
*/ |
void |
void |
ttyrub(int c, struct tty *tp) |
ttyrub(int c, struct tty *tp) |
{ |
{ |
u_char *cp; |
u_char *cp; |
int savecol, tabc; |
int savecol, tabc, s; |
|
|
KASSERT(mutex_owned(&tty_lock)); |
|
|
|
if (!ISSET(tp->t_lflag, ECHO) || ISSET(tp->t_lflag, EXTPROC)) |
if (!ISSET(tp->t_lflag, ECHO) || ISSET(tp->t_lflag, EXTPROC)) |
return; |
return; |
Line 2096 ttyrub(int c, struct tty *tp) |
|
Line 2210 ttyrub(int c, struct tty *tp) |
|
ttyretype(tp); |
ttyretype(tp); |
return; |
return; |
} |
} |
|
s = spltty(); |
savecol = tp->t_column; |
savecol = tp->t_column; |
SET(tp->t_state, TS_CNTTB); |
SET(tp->t_state, TS_CNTTB); |
SET(tp->t_lflag, FLUSHO); |
SET(tp->t_lflag, FLUSHO); |
Line 2105 ttyrub(int c, struct tty *tp) |
|
Line 2220 ttyrub(int c, struct tty *tp) |
|
ttyecho(tabc, tp); |
ttyecho(tabc, tp); |
CLR(tp->t_lflag, FLUSHO); |
CLR(tp->t_lflag, FLUSHO); |
CLR(tp->t_state, TS_CNTTB); |
CLR(tp->t_state, TS_CNTTB); |
|
splx(s); |
|
|
/* savecol will now be length of the tab. */ |
/* savecol will now be length of the tab. */ |
savecol -= tp->t_column; |
savecol -= tp->t_column; |
Line 2132 ttyrub(int c, struct tty *tp) |
|
Line 2248 ttyrub(int c, struct tty *tp) |
|
|
|
/* |
/* |
* Back over cnt characters, erasing them. |
* Back over cnt characters, erasing them. |
* Called with tty lock held. |
* Called with tty slock held. |
*/ |
*/ |
static void |
static void |
ttyrubo(struct tty *tp, int cnt) |
ttyrubo(struct tty *tp, int cnt) |
{ |
{ |
|
|
KASSERT(mutex_owned(&tty_lock)); |
|
|
|
while (cnt-- > 0) { |
while (cnt-- > 0) { |
(void)ttyoutput('\b', tp); |
(void)ttyoutput('\b', tp); |
(void)ttyoutput(' ', tp); |
(void)ttyoutput(' ', tp); |
Line 2152 ttyrubo(struct tty *tp, int cnt) |
|
Line 2266 ttyrubo(struct tty *tp, int cnt) |
|
* Reprint the rawq line. Note, it is assumed that c_cc has already |
* Reprint the rawq line. Note, it is assumed that c_cc has already |
* been checked. |
* been checked. |
* |
* |
* Called with tty lock held. |
* Called with tty slock held. |
*/ |
*/ |
void |
void |
ttyretype(struct tty *tp) |
ttyretype(struct tty *tp) |
{ |
{ |
u_char *cp; |
u_char *cp; |
int c; |
int s, c; |
|
|
KASSERT(mutex_owned(&tty_lock)); |
|
|
|
/* Echo the reprint character. */ |
/* Echo the reprint character. */ |
if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE) |
if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE) |
Line 2168 ttyretype(struct tty *tp) |
|
Line 2280 ttyretype(struct tty *tp) |
|
|
|
(void)ttyoutput('\n', tp); |
(void)ttyoutput('\n', tp); |
|
|
|
s = spltty(); |
for (cp = firstc(&tp->t_canq, &c); cp; cp = nextc(&tp->t_canq, cp, &c)) |
for (cp = firstc(&tp->t_canq, &c); cp; cp = nextc(&tp->t_canq, cp, &c)) |
ttyecho(c, tp); |
ttyecho(c, tp); |
for (cp = firstc(&tp->t_rawq, &c); cp; cp = nextc(&tp->t_rawq, cp, &c)) |
for (cp = firstc(&tp->t_rawq, &c); cp; cp = nextc(&tp->t_rawq, cp, &c)) |
ttyecho(c, tp); |
ttyecho(c, tp); |
CLR(tp->t_state, TS_ERASE); |
CLR(tp->t_state, TS_ERASE); |
|
splx(s); |
|
|
tp->t_rocount = tp->t_rawq.c_cc; |
tp->t_rocount = tp->t_rawq.c_cc; |
tp->t_rocol = 0; |
tp->t_rocol = 0; |
Line 2180 ttyretype(struct tty *tp) |
|
Line 2294 ttyretype(struct tty *tp) |
|
|
|
/* |
/* |
* Echo a typed character to the terminal. |
* Echo a typed character to the terminal. |
* Called with tty lock held. |
* Called with tty slock held. |
*/ |
*/ |
static void |
static void |
ttyecho(int c, struct tty *tp) |
ttyecho(int c, struct tty *tp) |
{ |
{ |
|
|
KASSERT(mutex_owned(&tty_lock)); |
|
|
|
if (!ISSET(tp->t_state, TS_CNTTB)) |
if (!ISSET(tp->t_state, TS_CNTTB)) |
CLR(tp->t_lflag, FLUSHO); |
CLR(tp->t_lflag, FLUSHO); |
if ((!ISSET(tp->t_lflag, ECHO) && |
if ((!ISSET(tp->t_lflag, ECHO) && |
Line 2209 ttyecho(int c, struct tty *tp) |
|
Line 2321 ttyecho(int c, struct tty *tp) |
|
|
|
/* |
/* |
* Wake up any readers on a tty. |
* Wake up any readers on a tty. |
* Called with tty lock held. |
* Called with tty slock held. |
*/ |
*/ |
void |
void |
ttwakeup(struct tty *tp) |
ttwakeup(struct tty *tp) |
{ |
{ |
|
|
KASSERT(mutex_owned(&tty_lock)); |
|
|
|
selnotify(&tp->t_rsel, NOTE_SUBMIT); |
selnotify(&tp->t_rsel, NOTE_SUBMIT); |
if (ISSET(tp->t_state, TS_ASYNC)) |
if (ISSET(tp->t_state, TS_ASYNC)) { |
ttysig(tp, TTYSIG_PG2, SIGIO); |
mutex_enter(&proclist_mutex); |
#if 0 |
pgsignal(tp->t_pgrp, SIGIO, tp->t_session != NULL); |
/* XXX tp->t_rawq.c_cv.cv_waiters dropping to zero early!? */ |
mutex_exit(&proclist_mutex); |
clwakeup(&tp->t_rawq); |
} |
#else |
wakeup((void *)&tp->t_rawq); |
cv_wakeup(&tp->t_rawq.c_cv); |
|
#endif |
|
} |
} |
|
|
/* |
/* |
Line 2253 ttsetwater(struct tty *tp) |
|
Line 2361 ttsetwater(struct tty *tp) |
|
{ |
{ |
int cps, x; |
int cps, x; |
|
|
/* XXX not yet KASSERT(mutex_owned(&tty_lock)); */ |
|
|
|
#define CLAMP(x, h, l) ((x) > h ? h : ((x) < l) ? l : (x)) |
#define CLAMP(x, h, l) ((x) > h ? h : ((x) < l) ? l : (x)) |
|
|
cps = tp->t_ospeed / 10; |
cps = tp->t_ospeed / 10; |
Line 2267 ttsetwater(struct tty *tp) |
|
Line 2373 ttsetwater(struct tty *tp) |
|
|
|
/* |
/* |
* Report on state of foreground process group. |
* Report on state of foreground process group. |
* Call with tty lock held. |
* Call with tty slock held. |
* XXXSMP locking. |
* XXXSMP locking. |
*/ |
*/ |
void |
void |
Line 2367 ttyinfo(struct tty *tp, int fromsig) |
|
Line 2473 ttyinfo(struct tty *tp, int fromsig) |
|
* |
* |
* 1) Only foreground processes are eligible - implied. |
* 1) Only foreground processes are eligible - implied. |
* 2) Runnable processes are favored over anything else. The runner |
* 2) Runnable processes are favored over anything else. The runner |
* with the highest CPU utilization is picked (l_pctcpu). Ties are |
* with the highest CPU utilization is picked (p_estcpu). Ties are |
* broken by picking the highest pid. |
* broken by picking the highest pid. |
* 3) The sleeper with the shortest sleep time is next. With ties, |
* 3) The sleeper with the shortest sleep time is next. With ties, |
* we pick out just "short-term" sleepers (P_SINTR == 0). |
* we pick out just "short-term" sleepers (P_SINTR == 0). |
Line 2384 ttyinfo(struct tty *tp, int fromsig) |
|
Line 2490 ttyinfo(struct tty *tp, int fromsig) |
|
static int |
static int |
proc_compare(struct proc *p1, struct proc *p2) |
proc_compare(struct proc *p1, struct proc *p2) |
{ |
{ |
lwp_t *l1, *l2; |
|
|
|
if (p1 == NULL) |
if (p1 == NULL) |
return (1); |
return (1); |
Line 2400 proc_compare(struct proc *p1, struct pro |
|
Line 2505 proc_compare(struct proc *p1, struct pro |
|
/* |
/* |
* tie - favor one with highest recent CPU utilization |
* tie - favor one with highest recent CPU utilization |
*/ |
*/ |
l1 = LIST_FIRST(&p1->p_lwps); |
if (p2->p_estcpu > p1->p_estcpu) |
l2 = LIST_FIRST(&p2->p_lwps); |
|
if (l2->l_pctcpu > l1->l_pctcpu) |
|
return (1); |
return (1); |
|
if (p1->p_estcpu > p2->p_estcpu) |
|
return (0); |
return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ |
return (p2->p_pid > p1->p_pid); /* tie - return highest pid */ |
} |
} |
/* |
/* |
Line 2443 proc_compare(struct proc *p1, struct pro |
|
Line 2548 proc_compare(struct proc *p1, struct pro |
|
int |
int |
tputchar(int c, int flags, struct tty *tp) |
tputchar(int c, int flags, struct tty *tp) |
{ |
{ |
int r = 0; |
int s, r = 0; |
|
|
|
s = spltty(); |
if ((flags & NOLOCK) == 0) |
if ((flags & NOLOCK) == 0) |
mutex_spin_enter(&tty_lock); |
simple_lock(&tp->t_slock); |
if (!CONNECTED(tp)) { |
if (!CONNECTED(tp)) { |
r = -1; |
r = -1; |
goto out; |
goto out; |
Line 2457 tputchar(int c, int flags, struct tty *t |
|
Line 2563 tputchar(int c, int flags, struct tty *t |
|
ttstart(tp); |
ttstart(tp); |
out: |
out: |
if ((flags & NOLOCK) == 0) |
if ((flags & NOLOCK) == 0) |
mutex_spin_exit(&tty_lock); |
TTY_UNLOCK(tp); |
|
splx(s); |
return (r); |
return (r); |
} |
} |
|
|
|
|
* the tty is revoked, restarting a pending call will redo validation done |
* the tty is revoked, restarting a pending call will redo validation done |
* at the start of the call. |
* at the start of the call. |
* |
* |
* Must be called with the tty lock held. |
* Must be called with the tty slock held. |
*/ |
*/ |
int |
int |
ttysleep(struct tty *tp, kcondvar_t *cv, bool catch, int timo) |
ttysleep(struct tty *tp, void *chan, int pri, const char *wmesg, int timo) |
{ |
{ |
int error; |
int error; |
short gen; |
short gen; |
|
|
KASSERT(mutex_owned(&tty_lock)); |
|
|
|
gen = tp->t_gen; |
gen = tp->t_gen; |
if (catch) |
if ((error = ltsleep(chan, pri, wmesg, timo, &tp->t_slock)) != 0) |
error = cv_timedwait_sig(cv, &tty_lock, timo); |
|
else |
|
error = cv_timedwait(cv, &tty_lock, timo); |
|
if (error != 0) |
|
return (error); |
return (error); |
return (tp->t_gen == gen ? 0 : ERESTART); |
return (tp->t_gen == gen ? 0 : ERESTART); |
} |
} |
Line 2502 ttysleep(struct tty *tp, kcondvar_t *cv, |
|
Line 2603 ttysleep(struct tty *tp, kcondvar_t *cv, |
|
void |
void |
tty_attach(struct tty *tp) |
tty_attach(struct tty *tp) |
{ |
{ |
|
static bool again; |
|
|
mutex_spin_enter(&tty_lock); |
if (!again) { |
|
again = true; |
|
mutex_init(&ttylist_lock, MUTEX_DEFAULT, IPL_NONE); |
|
} |
|
|
|
mutex_enter(&ttylist_lock); |
TAILQ_INSERT_TAIL(&ttylist, tp, tty_link); |
TAILQ_INSERT_TAIL(&ttylist, tp, tty_link); |
++tty_count; |
++tty_count; |
mutex_spin_exit(&tty_lock); |
mutex_exit(&ttylist_lock); |
} |
} |
|
|
/* |
/* |
|
|
tty_detach(struct tty *tp) |
tty_detach(struct tty *tp) |
{ |
{ |
|
|
mutex_spin_enter(&tty_lock); |
mutex_enter(&ttylist_lock); |
--tty_count; |
--tty_count; |
#ifdef DIAGNOSTIC |
#ifdef DIAGNOSTIC |
if (tty_count < 0) |
if (tty_count < 0) |
panic("tty_detach: tty_count < 0"); |
panic("tty_detach: tty_count < 0"); |
#endif |
#endif |
TAILQ_REMOVE(&ttylist, tp, tty_link); |
TAILQ_REMOVE(&ttylist, tp, tty_link); |
mutex_spin_exit(&tty_lock); |
mutex_exit(&ttylist_lock); |
} |
} |
|
|
/* |
/* |
|
|
ttymalloc(void) |
ttymalloc(void) |
{ |
{ |
struct tty *tp; |
struct tty *tp; |
int i; |
|
|
|
tp = pool_get(&tty_pool, PR_WAITOK); |
tp = pool_get(&tty_pool, PR_WAITOK); |
memset(tp, 0, sizeof(*tp)); |
memset(tp, 0, sizeof(*tp)); |
|
simple_lock_init(&tp->t_slock); |
callout_init(&tp->t_rstrt_ch, 0); |
callout_init(&tp->t_rstrt_ch, 0); |
callout_setfunc(&tp->t_rstrt_ch, ttrstrt, tp); |
|
/* XXX: default to 1024 chars for now */ |
/* XXX: default to 1024 chars for now */ |
clalloc(&tp->t_rawq, 1024, 1); |
clalloc(&tp->t_rawq, 1024, 1); |
clalloc(&tp->t_canq, 1024, 1); |
clalloc(&tp->t_canq, 1024, 1); |
Line 2548 ttymalloc(void) |
|
Line 2654 ttymalloc(void) |
|
tp->t_linesw = ttyldisc_default(); |
tp->t_linesw = ttyldisc_default(); |
selinit(&tp->t_rsel); |
selinit(&tp->t_rsel); |
selinit(&tp->t_wsel); |
selinit(&tp->t_wsel); |
for (i = 0; i < TTYSIG_COUNT; i++) |
|
sigemptyset(&tp->t_sigs[i]); |
|
return (tp); |
return (tp); |
} |
} |
|
|
Line 2562 ttymalloc(void) |
|
Line 2666 ttymalloc(void) |
|
void |
void |
ttyfree(struct tty *tp) |
ttyfree(struct tty *tp) |
{ |
{ |
int i; |
|
|
|
mutex_enter(&tty_lock); |
|
for (i = 0; i < TTYSIG_COUNT; i++) |
|
sigemptyset(&tp->t_sigs[i]); |
|
if (tp->t_sigcount != 0) |
|
TAILQ_REMOVE(&tty_sigqueue, tp, t_sigqueue); |
|
mutex_exit(&tty_lock); |
|
|
|
callout_stop(&tp->t_rstrt_ch); |
callout_stop(&tp->t_rstrt_ch); |
ttyldisc_release(tp->t_linesw); |
ttyldisc_release(tp->t_linesw); |
clfree(&tp->t_rawq); |
clfree(&tp->t_rawq); |
clfree(&tp->t_canq); |
clfree(&tp->t_canq); |
clfree(&tp->t_outq); |
clfree(&tp->t_outq); |
callout_destroy(&tp->t_rstrt_ch); |
|
seldestroy(&tp->t_rsel); |
seldestroy(&tp->t_rsel); |
seldestroy(&tp->t_wsel); |
seldestroy(&tp->t_wsel); |
pool_put(&tty_pool, tp); |
pool_put(&tty_pool, tp); |
Line 2599 ttyprintf_nolock(struct tty *tp, const c |
|
Line 2694 ttyprintf_nolock(struct tty *tp, const c |
|
kprintf(fmt, TOTTY|NOLOCK, tp, NULL, ap); |
kprintf(fmt, TOTTY|NOLOCK, tp, NULL, ap); |
va_end(ap); |
va_end(ap); |
} |
} |
|
|
/* |
|
* Initialize the tty subsystem. |
|
*/ |
|
void |
|
tty_init(void) |
|
{ |
|
|
|
mutex_init(&tty_lock, MUTEX_DEFAULT, IPL_VM); |
|
tty_sigsih = softint_establish(SOFTINT_CLOCK, ttysigintr, NULL); |
|
KASSERT(tty_sigsih != NULL); |
|
} |
|
|
|
/* |
|
* Send a signal from a tty to its process group or session leader. |
|
* Handoff to the target is deferred to a soft interrupt. |
|
*/ |
|
void |
|
ttysig(struct tty *tp, enum ttysigtype st, int sig) |
|
{ |
|
sigset_t *sp; |
|
|
|
/* XXXSMP not yet KASSERT(mutex_owned(&tty_lock)); */ |
|
|
|
sp = &tp->t_sigs[st]; |
|
if (sigismember(sp, sig)) |
|
return; |
|
sigaddset(sp, sig); |
|
if (tp->t_sigcount++ == 0) |
|
TAILQ_INSERT_TAIL(&tty_sigqueue, tp, t_sigqueue); |
|
softint_schedule(tty_sigsih); |
|
} |
|
|
|
/* |
|
* Deliver deferred signals from ttys. Note that the process groups |
|
* and sessions associated with the ttys may have changed from when |
|
* the signal was originally sent, but in practice it should not matter. |
|
* For signals produced as a result of a syscall, the soft interrupt |
|
* will fire before the syscall returns to the user. |
|
*/ |
|
static void |
|
ttysigintr(void *cookie) |
|
{ |
|
struct tty *tp; |
|
enum ttysigtype st; |
|
struct pgrp *pgrp; |
|
struct session *sess; |
|
int sig; |
|
|
|
mutex_enter(&proclist_lock); |
|
for (;;) { |
|
mutex_spin_enter(&tty_lock); |
|
if ((tp = TAILQ_FIRST(&tty_sigqueue)) == NULL) { |
|
mutex_spin_exit(&tty_lock); |
|
break; |
|
} |
|
KASSERT(tp->t_sigcount > 0); |
|
for (st = 0; st < TTYSIG_COUNT; st++) { |
|
if ((sig = firstsig(&tp->t_sigs[st])) != 0) |
|
break; |
|
} |
|
KASSERT(st < TTYSIG_COUNT); |
|
sigdelset(&tp->t_sigs[st], sig); |
|
if (--tp->t_sigcount == 0) |
|
TAILQ_REMOVE(&tty_sigqueue, tp, t_sigqueue); |
|
pgrp = tp->t_pgrp; |
|
sess = tp->t_session; |
|
mutex_spin_exit(&tty_lock); |
|
if (sig == 0) |
|
panic("ttysigintr"); |
|
mutex_enter(&proclist_mutex); |
|
switch (st) { |
|
case TTYSIG_PG1: |
|
if (pgrp != NULL) |
|
pgsignal(pgrp, sig, 1); |
|
break; |
|
case TTYSIG_PG2: |
|
if (pgrp != NULL) |
|
pgsignal(pgrp, sig, sess != NULL); |
|
break; |
|
case TTYSIG_LEADER: |
|
if (sess != NULL && sess->s_leader != NULL) |
|
psignal(sess->s_leader, sig); |
|
break; |
|
default: |
|
/* NOTREACHED */ |
|
break; |
|
} |
|
mutex_exit(&proclist_mutex); |
|
} |
|
mutex_exit(&proclist_lock); |
|
} |
|