diff options
Diffstat (limited to 'sys/kern/tty.c')
| -rw-r--r-- | sys/kern/tty.c | 149 | 
1 files changed, 131 insertions, 18 deletions
diff --git a/sys/kern/tty.c b/sys/kern/tty.c index 48e4fc5e1ec8..29898c1880be 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -36,7 +36,7 @@   * SUCH DAMAGE.   *   *	@(#)tty.c	8.8 (Berkeley) 1/21/94 - * $Id: tty.c,v 1.6 1994/08/18 09:16:21 davidg Exp $ + * $Id: tty.c,v 1.7 1994/10/02 17:35:29 phk Exp $   */  #include <sys/param.h> @@ -819,6 +819,9 @@ ttioctl(tp, cmd, data, flag)  		else  			CLR(t->c_lflag, EXTPROC);  		tp->t_lflag = t->c_lflag | ISSET(tp->t_lflag, PENDIN); +		if (t->c_cc[VMIN] != tp->t_cc[VMIN] || +		    t->c_cc[VTIME] != tp->t_cc[VTIME]) +			ttwakeup(tp);  		bcopy(t->c_cc, tp->t_cc, sizeof(t->c_cc));  		splx(s);  		break; @@ -954,8 +957,11 @@ ttnread(tp)  	if (ISSET(tp->t_lflag, PENDIN))  		ttypend(tp);  	nread = tp->t_canq.c_cc; -	if (!ISSET(tp->t_lflag, ICANON)) +	if (!ISSET(tp->t_lflag, ICANON)) {  		nread += tp->t_rawq.c_cc; +		if (nread < tp->t_cc[VMIN] && tp->t_cc[VTIME] == 0) +			nread = 0; +	}  	return (nread);  } @@ -1219,24 +1225,31 @@ ttread(tp, uio, flag)  {  	register struct clist *qp;  	register int c; -	register long lflag; -	register u_char *cc = tp->t_cc; +	register tcflag_t lflag; +	register cc_t *cc = tp->t_cc;  	register struct proc *p = curproc; -	int s, first, error = 0; +	int s, first, error = 0, carrier; +	int has_stime = 0, last_cc = 0; +	long slp = 0;		/* XXX this should be renamed `timo'. */ -loop:	lflag = tp->t_lflag; +loop:  	s = spltty(); +	lflag = tp->t_lflag;  	/*  	 * take pending input first  	 */ -	if (ISSET(lflag, PENDIN)) +	if (ISSET(lflag, PENDIN)) {  		ttypend(tp); -	splx(s); +		splx(s);	/* reduce latency */ +		s = spltty(); +		lflag = tp->t_lflag;	/* XXX ttypend() clobbers it */ +	}  	/*  	 * Hang process if it's in the background.  	 */  	if (isbackground(p, tp)) { +		splx(s);  		if ((p->p_sigignore & sigmask(SIGTTIN)) ||  		   (p->p_sigmask & sigmask(SIGTTIN)) ||  		    p->p_flag & P_PPWAIT || p->p_pgrp->pg_jobc == 0) @@ -1256,34 +1269,134 @@ loop:	lflag = tp->t_lflag;  	 */  	qp = ISSET(lflag, ICANON) ? &tp->t_canq : &tp->t_rawq; +	if (flag & IO_NDELAY) { +		if (qp->c_cc > 0) +			goto read; +		carrier = ISSET(tp->t_state, TS_CARR_ON) || +		    ISSET(tp->t_cflag, CLOCAL); +		if (!carrier && ISSET(tp->t_state, TS_ISOPEN) || +		    !ISSET(lflag, ICANON) && cc[VMIN] == 0) { +			splx(s); +			return (0); +		} +		splx(s); +		return (EWOULDBLOCK); +	} +	if (!ISSET(lflag, ICANON)) { +		int m = cc[VMIN]; +		long t = cc[VTIME]; +		struct timeval stime, timecopy; +		int x; + +		/* +		 * Check each of the four combinations. +		 * (m > 0 && t == 0) is the normal read case. +		 * It should be fairly efficient, so we check that and its +		 * companion case (m == 0 && t == 0) first. +		 * For the other two cases, we compute the target sleep time +		 * into slp. +		 */ +		if (t == 0) { +			if (qp->c_cc < m) +				goto sleep; +			if (qp->c_cc > 0) +				goto read; + +			/* m, t and qp->c_cc are all 0.  0 is enough input. */ +			splx(s); +			return (0); +		} +		t *= 100000;		/* time in us */ +#define diff(t1, t2) (((t1).tv_sec - (t2).tv_sec) * 1000000 + \ +			 ((t1).tv_usec - (t2).tv_usec)) +		if (m > 0) { +			if (qp->c_cc <= 0) +				goto sleep; +			if (qp->c_cc >= m) +				goto read; +			x = splclock(); +			timecopy = time; +			splx(x); +			if (!has_stime) { +				/* first character, start timer */ +				has_stime = 1; +				stime = timecopy; +				slp = t; +			} else if (qp->c_cc > last_cc) { +				/* got a character, restart timer */ +				stime = timecopy; +				slp = t; +			} else { +				/* nothing, check expiration */ +				slp = t - diff(timecopy, stime); +				if (slp <= 0) +					goto read; +			} +			last_cc = qp->c_cc; +		} else {	/* m == 0 */ +			if (qp->c_cc > 0) +				goto read; +			x = splclock(); +			timecopy = time; +			splx(x); +			if (!has_stime) { +				has_stime = 1; +				stime = timecopy; +				slp = t; +			} else { +				slp = t - diff(timecopy, stime); +				if (slp <= 0) { +					/* Timed out, but 0 is enough input. */ +					splx(s); +					return (0); +				} +			} +		} +#undef diff +		/* +		 * 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 there is no input, sleep on rawq  	 * awaiting hardware receipt and notification.  	 * If we have data, we don't need to check for carrier.  	 */ -	s = spltty();  	if (qp->c_cc <= 0) { -		int carrier; - +sleep:  		carrier = ISSET(tp->t_state, TS_CARR_ON) ||  		    ISSET(tp->t_cflag, CLOCAL);  		if (!carrier && ISSET(tp->t_state, TS_ISOPEN)) {  			splx(s);  			return (0);	/* EOF */  		} -		if (flag & IO_NDELAY) { -			splx(s); -			return (EWOULDBLOCK); -		}  		error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH, -		    carrier ? ttyin : ttopen, 0); +		    carrier ? ttyin : ttopen, (int)slp);  		splx(s); -		if (error) +		if (error == EWOULDBLOCK) +			error = 0; +		else if (error)  			return (error); +		/* +		 * XXX what happens if another process eats some input +		 * while we are asleep (not just here)?  It would be +		 * safest to detect changes and reset our state variables +		 * (has_stime and last_cc). +		 */ +		slp = 0;  		goto loop;  	} +read:  	splx(s); -  	/*  	 * Input present, check for input mapping and processing.  	 */  | 
