From 90ed03177682be32963d38e9ea56e9e2036bc8b5 Mon Sep 17 00:00:00 2001 From: dg Date: Fri, 27 May 1994 12:28:05 +0000 Subject: Completed version of my clist management code. Requires hooks in tty.c for adding and removing cblocks from the cfreelist queue (to give them back to malloc). I'll add those tomorrow. --- sys/kern/subr_clist.c | 320 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 249 insertions(+), 71 deletions(-) (limited to 'sys/kern/subr_clist.c') diff --git a/sys/kern/subr_clist.c b/sys/kern/subr_clist.c index acbb7f1..7ce49c4 100644 --- a/sys/kern/subr_clist.c +++ b/sys/kern/subr_clist.c @@ -15,30 +15,111 @@ #include #include -char cwaiting; struct cblock *cfreelist = 0; -int cfreecount, nclist = 256; +int cfreecount = 0; +#ifndef INITIAL_CBLOCKS +#define INITIAL_CBLOCKS 50 +#endif + +void cblock_alloc_cblocks __P((int)); + +#define MBUF_DIAG +#ifdef MBUF_DIAG +void +print_nblocks() +{ + printf("There are currently %d bytes in cblocks\n", cfreecount); +} +#endif + +/* + * Called from init_main.c + */ void clist_init() { + /* + * Allocate an initial base set of cblocks as a 'slush'. + * We allocate more with each ttyopen(). + */ + cblock_alloc_cblocks(INITIAL_CBLOCKS); + return; +} + +/* + * Remove a cblock from the cfreelist queue and return a pointer + * to it. + */ +static inline struct cblock * +cblock_alloc() +{ + struct cblock *cblockp; + + cblockp = cfreelist; + if (!cblockp) { + /* XXX should syslog a message that we're out! */ + return (0); + } + cfreelist = cblockp->c_next; + cblockp->c_next = NULL; + cfreecount -= CBSIZE; + return (cblockp); +} + +/* + * Add a cblock to the cfreelist queue. + */ +static inline void +cblock_free(cblockp) + struct cblock *cblockp; +{ + cblockp->c_next = cfreelist; + cfreelist = cblockp; + cfreecount += CBSIZE; + return; +} + +/* + * Allocate some cblocks for the cfreelist queue. + */ +void +cblock_alloc_cblocks(number) + int number; +{ int i; struct cblock *tmp; - for (i = 0; i < nclist; ++i) { + for (i = 0; i < number; ++i) { tmp = malloc(sizeof(struct cblock), M_TTYS, M_NOWAIT); if (!tmp) panic("clist_init: could not allocate cblock"); bzero((char *)tmp, sizeof(struct cblock)); - tmp->c_next = cfreelist; - cfreelist = tmp; - cfreecount += CBSIZE; + cblock_free(tmp); } return; } /* - * Get a character from head of clist. + * Free some cblocks from the cfreelist queue back to the + * system malloc pool. + */ +void +cblock_free_cblocks(number) + int number; +{ + int i; + struct cblock *tmp; + + for (i = 0; i < number; ++i) { + tmp = cblock_alloc(); + free(tmp, M_TTYS); + } +} + + +/* + * Get a character from the head of a clist. */ int getc(clistp) @@ -54,24 +135,32 @@ getc(clistp) if (clistp->c_cc) { cblockp = (struct cblock *)((long)clistp->c_cf & ~CROUND); chr = (u_char)*clistp->c_cf; -#if 0 + /* * If this char is quoted, set the flag. */ if (isset(cblockp->c_quote, clistp->c_cf - (char *)cblockp->c_info)) chr |= TTY_QUOTE; -#endif + + /* + * Advance to next character. + */ clistp->c_cf++; clistp->c_cc--; + /* + * If we have advanced the 'first' character pointer + * past the end of this cblock, advance to the next one. + * If there are no more characters, set the first and + * last pointers to NULL. In either case, free the + * current cblock. + */ if ((clistp->c_cf >= (char *)(cblockp+1)) || (clistp->c_cc == 0)) { if (clistp->c_cc > 0) { clistp->c_cf = cblockp->c_next->c_info; } else { clistp->c_cf = clistp->c_cl = NULL; } - cblockp->c_next = cfreelist; - cfreelist = cblockp; - cfreecount += CBSIZE; + cblock_free(cblockp); } } @@ -81,7 +170,8 @@ getc(clistp) /* * Copy 'amount' of chars, beginning at head of clist 'clistp' to - * destination linear buffer 'dest'. + * destination linear buffer 'dest'. Return number of characters + * actually copied. */ int q_to_b(clistp, dest, amount) @@ -107,15 +197,19 @@ q_to_b(clistp, dest, amount) clistp->c_cf += numc; clistp->c_cc -= numc; dest += numc; + /* + * If this cblock has been emptied, advance to the next + * one. If there are no more characters, set the first + * and last pointer to NULL. In either case, free the + * current cblock. + */ if ((clistp->c_cf >= (char *)cblockn) || (clistp->c_cc == 0)) { if (clistp->c_cc > 0) { clistp->c_cf = cblockp->c_next->c_info; } else { clistp->c_cf = clistp->c_cl = NULL; } - cblockp->c_next = cfreelist; - cfreelist = cblockp; - cfreecount += CBSIZE; + cblock_free(cblockp); } } @@ -146,15 +240,19 @@ ndflush(clistp, amount) amount -= numc; clistp->c_cf += numc; clistp->c_cc -= numc; + /* + * If this cblock has been emptied, advance to the next + * one. If there are no more characters, set the first + * and last pointer to NULL. In either case, free the + * current cblock. + */ if ((clistp->c_cf >= (char *)cblockn) || (clistp->c_cc == 0)) { if (clistp->c_cc > 0) { clistp->c_cf = cblockp->c_next->c_info; } else { clistp->c_cf = clistp->c_cl = NULL; } - cblockp->c_next = cfreelist; - cfreelist = cblockp; - cfreecount += CBSIZE; + cblock_free(cblockp); } } @@ -162,13 +260,16 @@ ndflush(clistp, amount) return; } +/* + * Add a character to the end of a clist. Return -1 is no + * more clists, or 0 for success. + */ int putc(chr, clistp) int chr; struct clist *clistp; { - struct cblock *cblockp; - struct cblock *bclockn; + struct cblock *cblockp, *bclockn; int s; s = spltty(); @@ -176,11 +277,8 @@ putc(chr, clistp) cblockp = (struct cblock *)((long)clistp->c_cl & ~CROUND); if (clistp->c_cl == NULL) { - if (cfreelist) { - cblockp = cfreelist; - cfreelist = cfreelist->c_next; - cfreecount -= CBSIZE; - cblockp->c_next = NULL; + cblockp = cblock_alloc(); + if (cblockp) { clistp->c_cf = clistp->c_cl = cblockp->c_info; clistp->c_cc = 0; } else { @@ -189,11 +287,10 @@ putc(chr, clistp) } } else { if (((long)clistp->c_cl & CROUND) == 0) { - if (cfreelist) { - cblockp = (cblockp-1)->c_next = cfreelist; - cfreelist = cfreelist->c_next; - cfreecount -= CBSIZE; - cblockp->c_next = NULL; + struct cblock *prev = (cblockp - 1); + cblockp = cblock_alloc(); + if (cblockp) { + prev->c_next = cblockp; clistp->c_cl = cblockp->c_info; } else { splx(s); @@ -202,10 +299,14 @@ putc(chr, clistp) } } -#if 0 + /* + * If this character is quoted, set the quote bit, if not, clear it. + */ if (chr & TTY_QUOTE) setbit(cblockp->c_quote, clistp->c_cl - (char *)cblockp->c_info); -#endif + else + clrbit(cblockp->c_quote, clistp->c_cl - (char *)cblockp->c_info); + *clistp->c_cl++ = chr; clistp->c_cc++; @@ -214,7 +315,8 @@ putc(chr, clistp) } /* - * Copy data from linear buffer to clist chain. + * Copy data from linear buffer to clist chain. Return the + * number of characters not copied. */ int b_to_q(src, amount, clistp) @@ -222,10 +324,11 @@ b_to_q(src, amount, clistp) int amount; struct clist *clistp; { - struct cblock *cblockp; - struct cblock *bclockn; + struct cblock *cblockp, *bclockn; + char *firstbyte, *lastbyte; + u_char startmask, endmask; + int startbit, endbit, num_between, numc; int s; - int numc; s = spltty(); @@ -234,11 +337,8 @@ b_to_q(src, amount, clistp) * then get one. */ if (clistp->c_cl == NULL) { - if (cfreelist) { - cblockp = cfreelist; - cfreelist = cfreelist->c_next; - cfreecount -= CBSIZE; - cblockp->c_next = NULL; + cblockp = cblock_alloc(); + if (cblockp) { clistp->c_cf = clistp->c_cl = cblockp->c_info; clistp->c_cc = 0; } else { @@ -254,11 +354,10 @@ b_to_q(src, amount, clistp) * Get another cblock if needed. */ if (((long)clistp->c_cl & CROUND) == 0) { - if (cfreelist) { - cblockp = (cblockp-1)->c_next = cfreelist; - cfreelist = cfreelist->c_next; - cfreecount -= CBSIZE; - cblockp->c_next = NULL; + struct cblock *prev = cblockp - 1; + cblockp = cblock_alloc(); + if (cblockp) { + prev->c_next = cblockp; clistp->c_cl = cblockp->c_info; } else { splx(s); @@ -270,13 +369,38 @@ b_to_q(src, amount, clistp) * Copy a chunk of the linear buffer up to the end * of this cblock. */ - cblockp += 1; - numc = min(amount, (char *)(cblockp) - clistp->c_cl); + numc = min(amount, (char *)(cblockp + 1) - clistp->c_cl); bcopy(src, clistp->c_cl, numc); /* - * Clear quote bits. + * Clear quote bits. The following could probably be made into + * a seperate "bitzero()" routine, but why bother? */ + startbit = clistp->c_cl - (char *)cblockp->c_info; + endbit = startbit + numc - 1; + + firstbyte = (u_char *)cblockp->c_quote + (startbit / NBBY); + lastbyte = (u_char *)cblockp->c_quote + (endbit / NBBY); + + /* + * Calculate mask of bits to preserve in first and + * last bytes. + */ + startmask = NBBY - (startbit % NBBY); + startmask = 0xff >> startmask; + endmask = (endbit % NBBY); + endmask = 0xff << (endmask + 1); + + if (firstbyte != lastbyte) { + *firstbyte &= startmask; + *lastbyte &= endmask; + + num_between = lastbyte - firstbyte - 1; + if (num_between) + bzero(firstbyte + 1, num_between); + } else { + *firstbyte &= (startmask | endmask); + } /* * ...and update pointer for the next chunk. @@ -285,12 +409,26 @@ b_to_q(src, amount, clistp) clistp->c_cl += numc; clistp->c_cc += numc; amount -= numc; + /* + * If we go through the loop again, it's always + * for data in the next cblock, so by adding one (cblock), + * (which makes the pointer 1 beyond the end of this + * cblock) we prepare for the assignment of 'prev' + * above. + */ + cblockp += 1; + } splx(s); return (amount); } +/* + * Get the next character in the clist. Store it at dst. Don't + * advance any clist pointers, but return a pointer to the next + * character position. + */ char * nextc(clistp, cp, dst) struct clist *clistp; @@ -300,20 +438,34 @@ nextc(clistp, cp, dst) struct cblock *cblockp; ++cp; + /* + * See if the next character is beyond the end of + * the clist. + */ if (clistp->c_cc && (cp != clistp->c_cl)) { + /* + * If the next character is beyond the end of this + * cblock, advance to the next cblock. + */ if (((long)cp & CROUND) == 0) cp = ((struct cblock *)cp - 1)->c_next->c_info; cblockp = (struct cblock *)((long)cp & ~CROUND); -#if 0 - *dst = *cp | (isset(cblockp->c_quote, cp - (char *)cblockp->c_info) ? TTY_QUOTE : 0); -#endif - *dst = (u_char)*cp; + + /* + * Get the character. Set the quote flag if this character + * is quoted. + */ + *dst = (u_char)*cp | (isset(cblockp->c_quote, cp - (char *)cblockp->c_info) ? TTY_QUOTE : 0); + return (cp); } return (NULL); } +/* + * "Unput" a character from a clist. + */ int unputc(clistp) struct clist *clistp; @@ -327,18 +479,21 @@ unputc(clistp) if (clistp->c_cc) { --clistp->c_cc; - chr = (u_char)*--clistp->c_cl; - /* - * Get the quote flag and 'unput' it, too. - */ + --clistp->c_cl; - /* XXX write me! */ + chr = (u_char)*clistp->c_cl; cblockp = (struct cblock *)((long)clistp->c_cl & ~CROUND); /* + * Set quote flag if this character was quoted. + */ + if (isset(cblockp->c_quote, (u_char *)clistp->c_cl - cblockp->c_info)) + chr |= TTY_QUOTE; + + /* * If all of the characters have been unput in this - * cblock, the find the previous one and free this + * cblock, then find the previous one and free this * one. */ if (clistp->c_cc && (clistp->c_cl <= (char *)cblockp->c_info)) { @@ -347,10 +502,12 @@ unputc(clistp) while (cbp->c_next != cblockp) cbp = cbp->c_next; + /* + * When the previous cblock is at the end, the 'last' + * pointer always points (invalidly) one past. + */ clistp->c_cl = (char *)(cbp+1); - cblockp->c_next = cfreelist; - cfreelist = cblockp; - cfreecount += CBSIZE; + cblock_free(cblockp); cbp->c_next = NULL; } } @@ -361,9 +518,7 @@ unputc(clistp) */ if ((clistp->c_cc == 0) && clistp->c_cl) { cblockp = (struct cblock *)((long)clistp->c_cl & ~CROUND); - cblockp->c_next = cfreelist; - cfreelist = cblockp; - cfreecount += CBSIZE; + cblock_free(cblockp); clistp->c_cf = clistp->c_cl = NULL; } @@ -371,17 +526,40 @@ unputc(clistp) return (chr); } +/* + * Move characters in source clist to destination clist, + * preserving quote bits. + */ void catq(src_clistp, dest_clistp) struct clist *src_clistp, *dest_clistp; { - char buffer[CBSIZE*2]; - int amount; + int chr, s; - while (src_clistp->c_cc) { - amount = q_to_b(src_clistp, buffer, sizeof(buffer)); - b_to_q(buffer, amount, dest_clistp); + s = spltty(); + /* + * If the destination clist is empty (has no cblocks atttached), + * then we simply assign the current clist to the destination. + */ + if (!dest_clistp->c_cf) { + dest_clistp->c_cf = src_clistp->c_cf; + dest_clistp->c_cl = src_clistp->c_cl; + src_clistp->c_cf = src_clistp->c_cl = NULL; + + dest_clistp->c_cc = src_clistp->c_cc; + src_clistp->c_cc = 0; + + splx(s); + return; } + splx(s); + + /* + * XXX This should probably be optimized to more than one + * character at a time. + */ + while ((chr = getc(src_clistp)) != -1) + putc(chr, dest_clistp); return; } -- cgit v1.1