UPAGES 8; dumpstack 96; msgbufmap; kernacc rounding bug fixed
[unix-history] / usr / src / sys / kern / tty_subr.c
index f193895..b702c1a 100644 (file)
@@ -1,18 +1,22 @@
-/*     tty_subr.c      3.1     %H%     */
+/*     tty_subr.c      4.4     %G%     */
 
 #include "../h/param.h"
 
 #include "../h/param.h"
-#include "../h/tty.h"
 #include "../h/systm.h"
 #include "../h/conf.h"
 #include "../h/buf.h"
 #include "../h/systm.h"
 #include "../h/conf.h"
 #include "../h/buf.h"
+#include "../h/tty.h"
+#include "tr.h"
 
 struct cblock {
 
 struct cblock {
-       struct cblock *c_next;
+       struct  cblock *c_next;
        char    c_info[CBSIZE];
 };
 
        char    c_info[CBSIZE];
 };
 
-struct cblock  cfree[NCLIST];
-struct cblock  *cfreelist;
+struct cblock cfree[NCLIST];
+struct cblock *cfreelist;
+
+int    cfreecount;
+char   cwaiting;
 
 /*
  * Character list get/put
 
 /*
  * Character list get/put
@@ -37,18 +41,53 @@ register struct clist *p;
                        p->c_cl = NULL;
                        bp->c_next = cfreelist;
                        cfreelist = bp;
                        p->c_cl = NULL;
                        bp->c_next = cfreelist;
                        cfreelist = bp;
+                       cfreecount += CBSIZE;
+                       if (cwaiting) {
+                               wakeup(&cwaiting);
+                               cwaiting = 0;
+                       }
                } else if (((int)p->c_cf & CROUND) == 0){
                        bp = (struct cblock *)(p->c_cf);
                        bp--;
                        p->c_cf = bp->c_next->c_info;
                        bp->c_next = cfreelist;
                        cfreelist = bp;
                } else if (((int)p->c_cf & CROUND) == 0){
                        bp = (struct cblock *)(p->c_cf);
                        bp--;
                        p->c_cf = bp->c_next->c_info;
                        bp->c_next = cfreelist;
                        cfreelist = bp;
+                       cfreecount += CBSIZE;
+                       if (cwaiting) {
+                               wakeup(&cwaiting);
+                               cwaiting = 0;
+                       }
                }
        }
        splx(s);
        return(c);
 }
 
                }
        }
        splx(s);
        return(c);
 }
 
+#if HAVTR > 0
+trgetc(p)
+register struct clist *p;
+{
+       register struct cblock *bp;
+       register int c, s;
+
+       if (p->c_cc <= 0) {
+               c = -1;
+               p->c_cc = 0;
+               p->c_cf = NULL;
+       } else {
+               c = *p->c_cf++ & 0377;
+               if (--p->c_cc<=0) {
+                       p->c_cf = NULL;
+               } else if (((int)p->c_cf & CROUND) == 0) {
+                       bp = (struct cblock *)(p->c_cf);
+                       bp--;
+                       p->c_cf = bp->c_next->c_info;
+               }
+       }
+       return(c);
+}
+#endif
+
 /*
  * copy clist to buffer.
  * return number of bytes moved.
 /*
  * copy clist to buffer.
  * return number of bytes moved.
@@ -67,6 +106,7 @@ register char *cp;
        if (q->c_cc <= 0) {
                q->c_cc = 0;
                q->c_cf = q->c_cl = NULL;
        if (q->c_cc <= 0) {
                q->c_cc = 0;
                q->c_cf = q->c_cl = NULL;
+               splx(s);
                return(0);
        }
        acp = cp;
                return(0);
        }
        acp = cp;
@@ -80,6 +120,11 @@ register char *cp;
                        q->c_cf = q->c_cl = NULL;
                        bp->c_next = cfreelist;
                        cfreelist = bp;
                        q->c_cf = q->c_cl = NULL;
                        bp->c_next = cfreelist;
                        cfreelist = bp;
+                       cfreecount += CBSIZE;
+                       if (cwaiting) {
+                               wakeup(&cwaiting);
+                               cwaiting = 0;
+                       }
                        break;
                }
                if (((int)q->c_cf & CROUND) == 0) {
                        break;
                }
                if (((int)q->c_cf & CROUND) == 0) {
@@ -88,12 +133,52 @@ register char *cp;
                        q->c_cf = bp->c_next->c_info;
                        bp->c_next = cfreelist;
                        cfreelist = bp;
                        q->c_cf = bp->c_next->c_info;
                        bp->c_next = cfreelist;
                        cfreelist = bp;
+                       cfreecount += CBSIZE;
+                       if (cwaiting) {
+                               wakeup(&cwaiting);
+                               cwaiting = 0;
+                       }
                }
        }
        splx(s);
        return(cp-acp);
 }
 
                }
        }
        splx(s);
        return(cp-acp);
 }
 
+#if HAVTR > 0
+/*
+ * Traverse a clist copying its contents to a buffer.
+ * q->cc and q->cf are updated with the current position
+ * in the list, but bytes are not released to the freelist.
+ */
+trq_to_b(q, cp, cc)
+register struct clist *q;
+register char *cp;
+register cc;
+{
+       register struct cblock *bp;
+       char *acp;
+
+       if (cc <= 0)
+               return(0);
+       if (q->c_cc <= 0)
+               return(0);
+
+       acp = cp;
+       cc++;
+       while (--cc) {
+               *cp++ = *q->c_cf++;
+               if (((int)q->c_cf & CROUND) == 0) {
+                       bp = (struct cblock *)(q->c_cf);
+                       bp--;
+                       q->c_cf = bp->c_next->c_info;
+               }
+               if (--q->c_cc <= 0)
+                       break;
+       }
+       return(cp-acp);
+}
+#endif
+
 
 /*
  * Return count of contiguous characters
 
 /*
  * Return count of contiguous characters
@@ -123,7 +208,8 @@ int s;
                end += cc;
                while (p < end) {
                        if (*p & flag) {
                end += cc;
                while (p < end) {
                        if (*p & flag) {
-                               cc = (int)p - (int)q->c_cf;
+                               cc = (int)p;
+                               cc -= (int)q->c_cf;
                                break;
                        }
                        p++;
                                break;
                        }
                        p++;
@@ -137,55 +223,68 @@ out:
 
 
 /*
 
 
 /*
- * Update clist to show that cc characters
- * were removed.  It is assumed that cc < CBSIZE.
+ * Flush cc bytes from q.
  */
 ndflush(q, cc)
 register struct clist *q;
 register cc;
 {
  */
 ndflush(q, cc)
 register struct clist *q;
 register cc;
 {
+register struct cblock *bp;
+char *end;
+int rem;
 register s;
 
 register s;
 
-       if (cc == 0)
-               return;
        s = spl6();
        if (q->c_cc < 0) {
        s = spl6();
        if (q->c_cc < 0) {
-               if (q->c_cf != NULL) {
-                       q->c_cc += cc;
-                       q->c_cf += cc;
-                       goto out;
-               }
-               q->c_cc = 0;
+               printf("neg q flush\n");
                goto out;
        }
        if (q->c_cc == 0) {
                goto out;
        }
                goto out;
        }
        if (q->c_cc == 0) {
                goto out;
        }
-       q->c_cc -= cc;
-       q->c_cf += cc;
-       if (((int)q->c_cf & CROUND) == 0) {
-               register struct cblock *bp;
-
-               bp = (struct cblock *)(q->c_cf) -1;
-               if (bp->c_next) {
+       while (cc>0 && q->c_cc) {
+               bp = (struct cblock *)((int)q->c_cf & ~CROUND);
+               if ((int)bp == (((int)q->c_cl-1) & ~CROUND)) {
+                       end = q->c_cl;
+               } else {
+                       end = (char *)((int)bp + sizeof (struct cblock));
+               }
+               rem = end - q->c_cf;
+               if (cc >= rem) {
+                       cc -= rem;
+                       q->c_cc -= rem;
                        q->c_cf = bp->c_next->c_info;
                        q->c_cf = bp->c_next->c_info;
+                       bp->c_next = cfreelist;
+                       cfreelist = bp;
+                       cfreecount += CBSIZE;
+                       if (cwaiting) {
+                               wakeup(&cwaiting);
+                               cwaiting = 0;
+                       }
                } else {
                } else {
-                       q->c_cf = q->c_cl = NULL;
+                       q->c_cc -= cc;
+                       q->c_cf += cc;
+                       if (q->c_cc <= 0) {
+                               bp->c_next = cfreelist;
+                               cfreelist = bp;
+                               cfreecount += CBSIZE;
+                               if (cwaiting) {
+                                       wakeup(&cwaiting);
+                                       cwaiting = 0;
+                               }
+                       }
+                       break;
                }
                }
-               bp->c_next = cfreelist;
-               cfreelist = bp;
-       } else
-       if (q->c_cc == 0) {
-               register struct cblock *bp;
-               q->c_cf = (char *)((int)q->c_cf & ~CROUND);
-               bp = (struct cblock *)(q->c_cf);
-               bp->c_next = cfreelist;
-               cfreelist = bp;
+       }
+       if (q->c_cc <= 0) {
                q->c_cf = q->c_cl = NULL;
                q->c_cf = q->c_cl = NULL;
+               q->c_cc = 0;
        }
 out:
        splx(s);
 }
        }
 out:
        splx(s);
 }
+
+
 putc(c, p)
 register struct clist *p;
 {
 putc(c, p)
 register struct clist *p;
 {
@@ -200,6 +299,7 @@ register struct clist *p;
                        return(-1);
                }
                cfreelist = bp->c_next;
                        return(-1);
                }
                cfreelist = bp->c_next;
+               cfreecount -= CBSIZE;
                bp->c_next = NULL;
                p->c_cf = cp = bp->c_info;
        } else if (((int)cp & CROUND) == 0) {
                bp->c_next = NULL;
                p->c_cf = cp = bp->c_info;
        } else if (((int)cp & CROUND) == 0) {
@@ -210,6 +310,7 @@ register struct clist *p;
                }
                bp = bp->c_next;
                cfreelist = bp->c_next;
                }
                bp = bp->c_next;
                cfreelist = bp->c_next;
+               cfreecount -= CBSIZE;
                bp->c_next = NULL;
                cp = bp->c_info;
        }
                bp->c_next = NULL;
                cp = bp->c_info;
        }
@@ -238,11 +339,14 @@ register int cc;
        if (cc <= 0)
                return(0);
        acc = cc;
        if (cc <= 0)
                return(0);
        acc = cc;
+
+
        s = spl6();
        if ((cq = q->c_cl) == NULL || q->c_cc < 0) {
                if ((bp = cfreelist) == NULL) 
                        goto out;
                cfreelist = bp->c_next;
        s = spl6();
        if ((cq = q->c_cl) == NULL || q->c_cc < 0) {
                if ((bp = cfreelist) == NULL) 
                        goto out;
                cfreelist = bp->c_next;
+               cfreecount -= CBSIZE;
                bp->c_next = NULL;
                q->c_cf = cq = bp->c_info;
        }
                bp->c_next = NULL;
                q->c_cf = cq = bp->c_info;
        }
@@ -254,6 +358,7 @@ register int cc;
                                goto out;
                        bp = bp->c_next;
                        cfreelist = bp->c_next;
                                goto out;
                        bp = bp->c_next;
                        cfreelist = bp->c_next;
+                       cfreecount -= CBSIZE;
                        bp->c_next = NULL;
                        cq = bp->c_info;
                }
                        bp->c_next = NULL;
                        cq = bp->c_info;
                }
@@ -267,6 +372,141 @@ out:
        return(cc);
 }
 
        return(cc);
 }
 
+char *
+wb_to_q(cp, cc, q)
+register char *cp;
+register struct clist *q;
+register cc;
+{
+char *f;
+register s;
+
+       s = spl6();
+       while (cc > cfreecount) {
+               cwaiting = 1;
+               sleep(&cwaiting, TTOPRI);
+       }
+       if (q->c_cc==0) {
+               b_to_q(cp, cc, q);
+               f = q->c_cf;
+       } else {
+               (void) putc(*cp++, q);
+               f = q->c_cl;
+               f--;
+               b_to_q(cp, --cc, q);
+       }
+       splx(s);
+       return(f);
+}
+
+#ifdef notdef
+char *
+nb_to_q(cp, cc, q)
+register char *cp;
+register struct clist *q;
+register cc;
+{
+char *f;
+register s;
+
+       s = spl6();
+       if (cc > cfreecount) {
+               f = NULL;
+               goto out;
+       }
+       if (q->c_cc==0) {
+               b_to_q(cp, cc, q);
+               f = q->c_cf;
+       } else {
+               (void) putc(*cp++, q);
+               f = q->c_cl;
+               f--;
+               b_to_q(cp, --cc, q);
+       }
+out:
+       splx(s);
+       return(f);
+}
+#endif
+
+/*
+ * Given a non-NULL pointter into the list (like c_cf which
+ * always points to a real character if non-NULL) return the pointer
+ * to the next character in the list or return NULL if no more chars.
+ *
+ * Callers must not allow getc's to happen between nextc's so that the
+ * pointer becomes invalid.  Note that interrupts are NOT masked.
+ */
+char *
+nextc(p, cp)
+register struct clist *p;
+register char *cp;
+{
+
+       if (p->c_cc && ++cp != p->c_cl) {
+               if (((int)cp & CROUND) == 0)
+                       return (((struct cblock *)cp)[-1].c_next->c_info);
+               return (cp);
+       }
+       return (0);
+}
+
+/*
+ * Remove the last character in the list and return it.
+ */
+unputc(p)
+register struct clist *p;
+{
+       register struct cblock *bp;
+       register int c, s;
+       struct cblock *obp;
+
+       s = spl6();
+       if (p->c_cc <= 0)
+               c = -1;
+       else {
+               c = *--p->c_cl;
+               if (--p->c_cc <= 0) {
+                       bp = (struct cblock *)p->c_cl;
+                       bp = (struct cblock *)((int)bp & ~CROUND);
+                       p->c_cl = p->c_cf = NULL;
+                       bp->c_next = cfreelist;
+                       cfreelist = bp;
+                       cfreecount += CBSIZE;
+               } else if (((int)p->c_cl & CROUND) == sizeof(bp->c_next)) {
+                       p->c_cl = (char *)((int)p->c_cl & ~CROUND);
+                       bp = (struct cblock *)p->c_cf;
+                       bp = (struct cblock *)((int)bp & ~CROUND);
+                       while (bp->c_next != (struct cblock *)p->c_cl)
+                               bp = bp->c_next;
+                       obp = bp;
+                       p->c_cl = (char *)(bp + 1);
+                       bp = bp->c_next;
+                       bp->c_next = cfreelist;
+                       cfreelist = bp;
+                       cfreecount += CBSIZE;
+                       obp->c_next = NULL;
+               }
+       }
+       splx(s);
+       return (c);
+}
+
+/*
+ * Put the chars in the from que
+ * on the end of the to que.
+ *
+ * SHOULD JUST USE q_to_b AND THEN b_to_q HERE.
+ */
+catq(from, to)
+struct clist *from, *to;
+{
+       register c;
+
+       while ((c = getc(from)) >= 0)
+               (void) putc(c, to);
+}
+
 /*
  * Initialize clist by freeing all character blocks, then count
  * number of character devices. (Once-only routine)
 /*
  * Initialize clist by freeing all character blocks, then count
  * number of character devices. (Once-only routine)
@@ -279,9 +519,10 @@ cinit()
 
        ccp = (int)cfree;
        ccp = (ccp+CROUND) & ~CROUND;
 
        ccp = (int)cfree;
        ccp = (ccp+CROUND) & ~CROUND;
-       for(cp=(struct cblock *)ccp; cp <= &cfree[NCLIST-1]; cp++) {
+       for(cp=(struct cblock *)ccp; cp < &cfree[NCLIST-1]; cp++) {
                cp->c_next = cfreelist;
                cfreelist = cp;
                cp->c_next = cfreelist;
                cfreelist = cp;
+               cfreecount += CBSIZE;
        }
        ccp = 0;
        for(cdp = cdevsw; cdp->d_open; cdp++)
        }
        ccp = 0;
        for(cdp = cdevsw; cdp->d_open; cdp++)
@@ -289,11 +530,11 @@ cinit()
        nchrdev = ccp;
 }
 
        nchrdev = ccp;
 }
 
+
 /*
  * integer (2-byte) get/put
  * using clists
  */
 /*
  * integer (2-byte) get/put
  * using clists
  */
-/*
 getw(p)
 register struct clist *p;
 {
 getw(p)
 register struct clist *p;
 {
@@ -304,7 +545,19 @@ register struct clist *p;
        s = getc(p);
        return(s | (getc(p)<<8));
 }
        s = getc(p);
        return(s | (getc(p)<<8));
 }
-*/
+
+#if HAVTR > 0
+trgetw(p)
+register struct clist *p;
+{
+       register int w;
+
+       if (p->c_cc <=1)
+               return(-1);
+       w = trgetc(p);
+       return(w | (trgetc(p)<<8));
+}
+#endif
 
 putw(c, p)
 register struct clist *p;
 
 putw(c, p)
 register struct clist *p;
@@ -316,8 +569,8 @@ register struct clist *p;
                splx(s);
                return(-1);
        }
                splx(s);
                return(-1);
        }
-       VOID putc(c, p);
-       VOID putc(c>>8, p);
+       (void) putc(c, p);
+       (void) putc(c>>8, p);
        splx(s);
        return(0);
 }
        splx(s);
        return(0);
 }