tty.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 2,414 行 · 第 1/4 页

C
2,414
字号
				break;			}#if NSNP > 0			if (ISSET(tp->t_state, TS_SNOOP) && tp->t_sc != NULL)				snpin((struct snoop *)tp->t_sc, cp, cc);#endif		}		/*		 * If nothing fancy need be done, grab those characters we		 * can handle without any of ttyoutput's processing and		 * just transfer them to the output q.  For those chars		 * which require special processing (as indicated by the		 * bits in char_type), call ttyoutput.  After processing		 * a hunk of data, look for FLUSHO so ^O's will take effect		 * immediately.		 */		while (cc > 0) {			if (!ISSET(tp->t_oflag, OPOST))				ce = cc;			else {				ce = cc - scanc((u_int)cc, (u_char *)cp,				   (u_char *)char_type, CCLASSMASK);				/*				 * If ce is zero, then we're processing				 * a special character through ttyoutput.				 */				if (ce == 0) {					tp->t_rocount = 0;					if (ttyoutput(*cp, tp) >= 0) {						/* No Clists, wait a bit. */						ttstart(tp);						if (flag & IO_NDELAY) {							error = EWOULDBLOCK;							goto out;						}						error = ttysleep(tp, &lbolt,								 TTOPRI|PCATCH,								 "ttybf1", 0);						if (error)							goto out;						goto loop;					}					cp++;					cc--;					if (ISSET(tp->t_lflag, FLUSHO) ||					    tp->t_outq.c_cc > hiwat)						goto ovhiwat;					continue;				}			}			/*			 * A bunch of normal characters have been found.			 * Transfer them en masse to the output queue and			 * continue processing at the top of the loop.			 * If there are any further characters in this			 * <= OBUFSIZ chunk, the first should be a character			 * requiring special handling by ttyoutput.			 */			tp->t_rocount = 0;			i = b_to_q(cp, ce, &tp->t_outq);			ce -= i;			tp->t_column += ce;			cp += ce, cc -= ce, tk_nout += ce;			tp->t_outcc += ce;			if (i > 0) {				/* No Clists, wait a bit. */				ttstart(tp);				if (flag & IO_NDELAY) {					error = EWOULDBLOCK;					goto out;				}				error = ttysleep(tp, &lbolt, TTOPRI | PCATCH,						 "ttybf2", 0);				if (error)					goto out;				goto loop;			}			if (ISSET(tp->t_lflag, FLUSHO) ||			    tp->t_outq.c_cc > hiwat)				break;		}		ttstart(tp);	}out:	/*	 * If cc is nonzero, we leave the uio structure inconsistent, as the	 * offset and iov pointers have moved forward, but it doesn't matter	 * (the call will either return short or restart with a new uio).	 */	uio->uio_resid += cc;	return (error);ovhiwat:	ttstart(tp);	s = spltty();	/*	 * This can only occur if FLUSHO is set in t_lflag,	 * or if ttstart/oproc is synchronous (or very fast).	 */	if (tp->t_outq.c_cc <= hiwat) {		splx(s);		goto loop;	}	if (flag & IO_NDELAY) {		splx(s);		uio->uio_resid += cc;		return (uio->uio_resid == cnt ? EWOULDBLOCK : 0);	}	SET(tp->t_state, TS_SO_OLOWAT);	error = ttysleep(tp, TSA_OLOWAT(tp), TTOPRI | PCATCH, "ttywri",			 tp->t_timeout);	splx(s);	if (error == EWOULDBLOCK)		error = EIO;	if (error)		goto out;	goto loop;}/* * Rubout one character from the rawq of tp * as cleanly as possible. */static voidttyrub(c, tp)	register int c;	register struct tty *tp;{	register char *cp;	register int savecol;	int tabc, s;	if (!ISSET(tp->t_lflag, ECHO) || ISSET(tp->t_lflag, EXTPROC))		return;	CLR(tp->t_lflag, FLUSHO);	if (ISSET(tp->t_lflag, ECHOE)) {		if (tp->t_rocount == 0) {			/*			 * Screwed by ttwrite; retype			 */			ttyretype(tp);			return;		}		if (c == ('\t' | TTY_QUOTE) || c == ('\n' | TTY_QUOTE))			ttyrubo(tp, 2);		else {			CLR(c, ~TTY_CHARMASK);			switch (CCLASS(c)) {			case ORDINARY:				ttyrubo(tp, 1);				break;			case BACKSPACE:			case CONTROL:			case NEWLINE:			case RETURN:			case VTAB:				if (ISSET(tp->t_lflag, ECHOCTL))					ttyrubo(tp, 2);				break;			case TAB:				if (tp->t_rocount < tp->t_rawq.c_cc) {					ttyretype(tp);					return;				}				s = spltty();				savecol = tp->t_column;				SET(tp->t_state, TS_CNTTB);				SET(tp->t_lflag, FLUSHO);				tp->t_column = tp->t_rocol;				cp = tp->t_rawq.c_cf;				if (cp)					tabc = *cp;	/* XXX FIX NEXTC */				for (; cp; cp = nextc(&tp->t_rawq, cp, &tabc))					ttyecho(tabc, tp);				CLR(tp->t_lflag, FLUSHO);				CLR(tp->t_state, TS_CNTTB);				splx(s);				/* savecol will now be length of the tab. */				savecol -= tp->t_column;				tp->t_column += savecol;				if (savecol > 8)					savecol = 8;	/* overflow screw */				while (--savecol >= 0)					(void)ttyoutput('\b', tp);				break;			default:			/* XXX */#define	PANICSTR	"ttyrub: would panic c = %d, val = %d\n"				(void)printf(PANICSTR, c, CCLASS(c));#ifdef notdef				panic(PANICSTR, c, CCLASS(c));#endif			}		}	} else if (ISSET(tp->t_lflag, ECHOPRT)) {		if (!ISSET(tp->t_state, TS_ERASE)) {			SET(tp->t_state, TS_ERASE);			(void)ttyoutput('\\', tp);		}		ttyecho(c, tp);	} else		ttyecho(tp->t_cc[VERASE], tp);	--tp->t_rocount;}/* * Back over cnt characters, erasing them. */static voidttyrubo(tp, cnt)	register struct tty *tp;	int cnt;{	while (cnt-- > 0) {		(void)ttyoutput('\b', tp);		(void)ttyoutput(' ', tp);		(void)ttyoutput('\b', tp);	}}/* * ttyretype -- *	Reprint the rawq line.  Note, it is assumed that c_cc has already *	been checked. */static voidttyretype(tp)	register struct tty *tp;{	register char *cp;	int s, c;	/* Echo the reprint character. */	if (tp->t_cc[VREPRINT] != _POSIX_VDISABLE)		ttyecho(tp->t_cc[VREPRINT], tp);	(void)ttyoutput('\n', tp);	/*	 * XXX	 * FIX: NEXTC IS BROKEN - DOESN'T CHECK QUOTE	 * BIT OF FIRST CHAR.	 */	s = spltty();	for (cp = tp->t_canq.c_cf, c = (cp != NULL ? *cp : 0);	    cp != NULL; cp = nextc(&tp->t_canq, cp, &c))		ttyecho(c, tp);	for (cp = tp->t_rawq.c_cf, c = (cp != NULL ? *cp : 0);	    cp != NULL; cp = nextc(&tp->t_rawq, cp, &c))		ttyecho(c, tp);	CLR(tp->t_state, TS_ERASE);	splx(s);	tp->t_rocount = tp->t_rawq.c_cc;	tp->t_rocol = 0;}/* * Echo a typed character to the terminal. */static voidttyecho(c, tp)	register int c;	register struct tty *tp;{	if (!ISSET(tp->t_state, TS_CNTTB))		CLR(tp->t_lflag, FLUSHO);	if ((!ISSET(tp->t_lflag, ECHO) &&	     (c != '\n' || !ISSET(tp->t_lflag, ECHONL))) ||	    ISSET(tp->t_lflag, EXTPROC))		return;	if (ISSET(tp->t_lflag, ECHOCTL) &&	    ((ISSET(c, TTY_CHARMASK) <= 037 && c != '\t' && c != '\n') ||	    ISSET(c, TTY_CHARMASK) == 0177)) {		(void)ttyoutput('^', tp);		CLR(c, ~TTY_CHARMASK);		if (c == 0177)			c = '?';		else			c += 'A' - 1;	}	(void)ttyoutput(c, tp);}/* * Wake up any readers on a tty. */voidttwakeup(tp)	register struct tty *tp;{	if (tp->t_rsel.si_pid != 0)		selwakeup(&tp->t_rsel);	if (ISSET(tp->t_state, TS_ASYNC))		pgsignal(tp->t_pgrp, SIGIO, 1);	wakeup(TSA_HUP_OR_INPUT(tp));}/* * Wake up any writers on a tty. */voidttwwakeup(tp)	register struct tty *tp;{	if (tp->t_wsel.si_pid != 0 && tp->t_outq.c_cc <= tp->t_lowat)		selwakeup(&tp->t_wsel);	if (ISSET(tp->t_state, TS_BUSY | TS_SO_OCOMPLETE) ==	    TS_SO_OCOMPLETE && tp->t_outq.c_cc == 0) {		CLR(tp->t_state, TS_SO_OCOMPLETE);		wakeup(TSA_OCOMPLETE(tp));	}	if (ISSET(tp->t_state, TS_SO_OLOWAT) &&	    tp->t_outq.c_cc <= tp->t_lowat) {		CLR(tp->t_state, TS_SO_OLOWAT);		wakeup(TSA_OLOWAT(tp));	}}/* * Look up a code for a specified speed in a conversion table; * used by drivers to map software speed values to hardware parameters. */intttspeedtab(speed, table)	int speed;	register struct speedtab *table;{	for ( ; table->sp_speed != -1; table++)		if (table->sp_speed == speed)			return (table->sp_code);	return (-1);}/* * Set tty hi and low water marks. * * Try to arrange the dynamics so there's about one second * from hi to low water. * */voidttsetwater(tp)	struct tty *tp;{	register int cps, x;#define CLAMP(x, h, l)	((x) > h ? h : ((x) < l) ? l : (x))	cps = tp->t_ospeed / 10;	tp->t_lowat = x = CLAMP(cps / 2, TTMAXLOWAT, TTMINLOWAT);	x += cps;	x = CLAMP(x, TTMAXHIWAT, TTMINHIWAT);	tp->t_hiwat = roundup(x, CBSIZE);#undef	CLAMP}#ifdef OSKITvoidttyinfo(struct tty *tp){}#else/* * Report on state of foreground process group. */voidttyinfo(tp)	register struct tty *tp;{	register struct proc *p, *pick;	struct timeval utime, stime;	int tmp;	if (ttycheckoutq(tp,0) == 0)		return;	/* Print load average. */	tmp = (averunnable.ldavg[0] * 100 + FSCALE / 2) >> FSHIFT;	ttyprintf(tp, "load: %d.%02d ", tmp / 100, tmp % 100);	if (tp->t_session == NULL)		ttyprintf(tp, "not a controlling terminal\n");	else if (tp->t_pgrp == NULL)		ttyprintf(tp, "no foreground process group\n");	else if ((p = tp->t_pgrp->pg_mem) == NULL)		ttyprintf(tp, "empty foreground process group\n");	else {		/* 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,		    pick->p_stat == SRUN ? "running" :		    pick->p_wmesg ? pick->p_wmesg : "iowait");		calcru(pick, &utime, &stime, NULL);		/* Print user time. */		ttyprintf(tp, "%d.%02du ",		    utime.tv_sec, utime.tv_usec / 10000);		/* Print system time. */		ttyprintf(tp, "%d.%02ds ",		    stime.tv_sec, stime.tv_usec / 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,		    pick->p_stat == SIDL || pick->p_stat == SZOMB ? 0 :#ifdef pmap_resident_count			pgtok(pmap_resident_count(&pick->p_vmspace->vm_pmap))#else			pgtok(pick->p_vmspace->vm_rssize)#endif			);	}	tp->t_rocount = 0;	/* so pending input will be retyped if BS */}/* * Returns 1 if p2 is "better" than p1 * * The algorithm for picking the "interesting" process is thus: * *	1) Only foreground processes are eligible - implied. *	2) Runnable processes are favored over anything else.  The runner *	   with the highest cpu utilization is picked (p_estcpu).  Ties are *	   broken by picking the highest pid. *	3) The sleeper with the shortest sleep time is next.  With ties, *	   we pick out just "short-term" sleepers (P_SINTR == 0). *	4) Further ties are broken by picking the highest pid. */#define ISRUN(p)	(((p)->p_stat == SRUN) || ((p)->p_stat == SIDL))#define TESTAB(a, b)    ((a)<<1 | (b))#define ONLYA   2#define ONLYB   1#define BOTH    3static intproc_compare(p1, p2)	register struct proc *p1, *p2;{	if (p1 == NULL)		return (1);	/*	 * see if at least one of them is runnable	 */	switch (TESTAB(ISRUN(p1), ISRUN(p2))) {	case ONLYA:		return (0);	case ONLYB:		return (1);	case BOTH:		/*		 * tie - favor one with highest recent cpu utilization		 */		if (p2->p_estcpu > p1->p_estcpu)			return (1);		if (p1->p_estcpu > p2->p_estcpu)			return (0);		return (p2->p_pid > p1->p_pid);	/* tie - return highest pid */	}	/* 	 * weed out zombies	 */	switch (TESTAB(p1->p_stat == SZOMB, p2->p_stat == SZOMB)) {	case ONLYA:		return (1);	case ONLYB:		return (0);	case BOTH:		return (p2->p_pid > p1->p_pid); /* tie - return highest pid */	}	/*	 * pick the one with the smallest sleep time	 */	if (p2->p_slptime > p1->p_slptime)		return (0);	if (p1->p_slptime > p2->p_slptime)		return (1);	/*	 * favor one sleeping in a non-interruptible sleep	 */	if (p1->p_flag & P_SINTR && (p2->p_flag & P_SINTR) == 0)		return (1);	if (p2->p_flag & P_SINTR && (p1->p_flag & P_SINTR) == 0)		return (0);	return (p2->p_pid > p1->p_pid);		/* tie - return highest pid */}#endif /* !OSKIT *//* * Output char to tty; console putchar style. */inttputchar(c, tp)	int c;	struct tty *tp;{	register int s;	s = spltty();	if (!ISSET(tp->t_state, TS_CONNECTED)) {		splx(s);		return (-1);	}	if (c == '\n')		(void)ttyoutput('\r', tp);	(void)ttyoutput(c, tp);	ttstart(tp);	splx(s);	return (0);}/* * Sleep on chan, returning ERESTART if tty changed while we napped and * returning any errors (e.g. EINTR/ETIMEDOUT) reported by tsleep.  If * the tty is revoked, restarting a pending call will redo validation done * at the start of the call. */intttysleep(tp, chan, pri, wmesg, timo)	struct tty *tp;	void *chan;	int pri, timo;	char *wmesg;{	int error;	int gen;	gen = tp->t_gen;	error = tsleep(chan, pri, wmesg, timo);	if (error)		return (error);	return (tp->t_gen == gen ? 0 : ERESTART);}/* * XXX this is usable not useful or used.  Most tty drivers have * ifdefs for using ttymalloc() but assume a different interface. *//* * Allocate a tty struct.  Clists in the struct will be allocated by * ttyopen(). */struct tty *ttymalloc(){        struct tty *tp;        tp = malloc(sizeof *tp, M_TTYS, M_WAITOK);        bzero(tp, sizeof *tp);        return (tp);}#if 0 /* XXX not yet usable: session leader holds a ref (see kern_exit.c). *//* * Free a tty struct.  Clists in the struct should have been freed by * ttyclose(). */voidttyfree(tp)	struct tty *tp;{        free(tp, M_TTYS);}#endif /* 0 */#ifdef OSKIT#include <oskit/io/asyncio.h>/* * Well, this is dumb. Need to convert tty state into asyncio flags. */unsignedttyconds(tp)	struct tty *tp;{	unsigned conds = 0;		if (ttnread(tp) > 0 || ISSET(tp->t_state, TS_ZOMBIE))                conds |= OSKIT_ASYNCIO_READABLE;		if ((tp->t_outq.c_cc <= tp->t_lowat &&	     ISSET(tp->t_state, TS_CONNECTED))	    || ISSET(tp->t_state, TS_ZOMBIE))		conds |= OSKIT_ASYNCIO_WRITABLE;	return conds;}#endif

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?