⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tty.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
		 * Give user character.		 */ 		error = ureadc(c, uio);		if (error)			break; 		if (uio->uio_resid == 0)			break;		/*		 * In canonical mode check for a "break character"		 * marking the end of a "line of input".		 */		if (ISSET(lflag, ICANON) && TTBREAKC(c))			break;		first = 0;	}	/*	 * Look to unblock output now that (presumably)	 * the input queue has gone down.	 */	s = spltty();	if (ISSET(tp->t_state, TS_TBLOCK) && tp->t_rawq.c_cc < TTYHOG/5) {		if (cc[VSTART] != _POSIX_VDISABLE &&		    putc(cc[VSTART], &tp->t_outq) == 0) {			CLR(tp->t_state, TS_TBLOCK);			ttstart(tp);		}	}	splx(s);	return (error);}/* * Check the output queue on tp for space for a kernel message (from uprintf * or tprintf).  Allow some space over the normal hiwater mark so we don't * 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 * arrive. */intttycheckoutq(tp, wait)	register struct tty *tp;	int wait;{	int hiwat, s, oldsig;	hiwat = tp->t_hiwat;	s = spltty();	oldsig = wait ? curproc->p_siglist : 0;	if (tp->t_outq.c_cc > hiwat + 200)		while (tp->t_outq.c_cc > hiwat) {			ttstart(tp);			if (wait == 0 || curproc->p_siglist != oldsig) {				splx(s);				return (0);			}			timeout((void (*)__P((void *)))wakeup,			    (void *)&tp->t_outq, hz);			SET(tp->t_state, TS_ASLEEP);			sleep((caddr_t)&tp->t_outq, PZERO - 1);		}	splx(s);	return (1);}/* * Process a write call on a tty device. */intttwrite(tp, uio, flag)	register struct tty *tp;	register struct uio *uio;	int flag;{	register char *cp;	register int cc, ce;	register struct proc *p;	int i, hiwat, cnt, error, s;	char obuf[OBUFSIZ];	hiwat = tp->t_hiwat;	cnt = uio->uio_resid;	error = 0;	cc = 0;loop:	s = spltty();	if (!ISSET(tp->t_state, TS_CARR_ON) &&	    !ISSET(tp->t_cflag, CLOCAL)) {		if (ISSET(tp->t_state, TS_ISOPEN)) {			splx(s);			return (EIO);		} else if (flag & IO_NDELAY) {			splx(s);			error = EWOULDBLOCK;			goto out;		} else {			/* Sleep awaiting carrier. */			error = ttysleep(tp,			    &tp->t_rawq, TTIPRI | PCATCH,ttopen, 0);			splx(s);			if (error)				goto out;			goto loop;		}	}	splx(s);	/*	 * Hang the process if it's in the background.	 */	p = curproc;	if (isbackground(p, tp) &&	    ISSET(tp->t_lflag, TOSTOP) && (p->p_flag & P_PPWAIT) == 0 &&	    (p->p_sigignore & sigmask(SIGTTOU)) == 0 &&	    (p->p_sigmask & sigmask(SIGTTOU)) == 0 &&	     p->p_pgrp->pg_jobc) {		pgsignal(p->p_pgrp, SIGTTOU, 1);		if (error = ttysleep(tp, &lbolt, TTIPRI | PCATCH, ttybg, 0))			goto out;		goto loop;	}	/*	 * Process the user's data in at most OBUFSIZ chunks.  Perform any	 * output translation.  Keep track of high water mark, sleep on	 * overflow awaiting device aid in acquiring new space.	 */	while (uio->uio_resid > 0 || cc > 0) {		if (ISSET(tp->t_lflag, FLUSHO)) {			uio->uio_resid = 0;			return (0);		}		if (tp->t_outq.c_cc > hiwat)			goto ovhiwat;		/*		 * Grab a hunk of data from the user, unless we have some		 * leftover from last time.		 */		if (cc == 0) {			cc = min(uio->uio_resid, OBUFSIZ);			cp = obuf;			error = uiomove(cp, cc, uio);			if (error) {				cc = 0;				break;			}		}		/*		 * 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 (error = ttysleep(tp, &lbolt,						    TTOPRI | PCATCH, ttybuf, 0))							break;						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 (error = ttysleep(tp,				    &lbolt, TTOPRI | PCATCH, ttybuf, 0))					break;				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_ASLEEP);	error = ttysleep(tp, &tp->t_outq, TTOPRI | PCATCH, ttyout, 0);	splx(s);	if (error)		goto out;	goto loop;}/* * Rubout one character from the rawq of tp * as cleanly as possible. */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. */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) &&	    (!ISSET(tp->t_lflag, ECHONL) || c == '\n')) ||	    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;{	selwakeup(&tp->t_rsel);	if (ISSET(tp->t_state, TS_ASYNC))		pgsignal(tp->t_pgrp, SIGIO, 1);	wakeup((caddr_t)&tp->t_rawq);}/* * 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}/* * 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 + 5000) / 10000);		/* Print system time. */		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,		    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 */}/* * 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_CARR_ON | TS_ISOPEN) != (TS_CARR_ON | TS_ISOPEN)) {		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;	short gen;	gen = tp->t_gen;	if (error = tsleep(chan, pri, wmesg, timo))		return (error);	return (tp->t_gen == gen ? 0 : ERESTART);}

⌨️ 快捷键说明

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