aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey A. Chernov <ache@FreeBSD.org>1994-10-03 01:12:18 +0000
committerAndrey A. Chernov <ache@FreeBSD.org>1994-10-03 01:12:18 +0000
commitd32198f15b39a0f6dc29229ba4925d67d136956e (patch)
tree1fafa7349099d146bc15a3f88e76216b263faa9c
parent1546c307a648353a0c382f87b567aa01ef4a2af3 (diff)
Notes
-rw-r--r--sys/kern/tty.c149
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.
*/