Add VMIN/VTIME support

Obtained from:  scratch :-)
This commit is contained in:
Andrey A. Chernov 1994-10-03 01:12:18 +00:00
parent 1546c307a6
commit d32198f15b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=3323

View File

@ -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.
*/