4 * Copyright (c) 1994, David Greenman
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice unmodified, this list of conditions, and the following
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * $FreeBSD: src/sys/kern/tty_subr.c,v 1.32 1999/08/28 00:46:21 peter Exp $
34 * Most functions here could use a separate lock to deal with concurrent
35 * access to the cblocks and cblock_*_list.
39 * clist support routines
41 * NOTE on cblock->c_cf: This pointer may point at the base of a cblock,
42 * which is &cblock->c_info[0], but will never
43 * point at the end of a cblock (char *)(cblk + 1)
45 * NOTE on cblock->c_cl: This pointer will never point at the base of
46 * a block but may point at the end of one.
48 * These routines may be used by more then just ttys, so a critical section
49 * must be used to access the free list, and for general safety.
52 #include <sys/param.h>
53 #include <sys/kernel.h>
54 #include <sys/systm.h>
55 #include <sys/malloc.h>
57 #include <sys/clist.h>
58 #include <sys/thread2.h>
60 static void clist_init (void *);
61 SYSINIT(clist, SI_SUB_CLIST, SI_ORDER_FIRST, clist_init, NULL);
63 static struct cblock *cfreelist = NULL;
65 static int cslushcount;
68 #ifndef INITIAL_CBLOCKS
69 #define INITIAL_CBLOCKS 50
72 static struct cblock *cblock_alloc (void);
73 static void cblock_alloc_cblocks (int number);
74 static void cblock_free (struct cblock *cblockp);
75 static void cblock_free_cblocks (int number);
81 DB_SHOW_COMMAND(cbstat, cbstat)
86 "tot = %d (active = %d, free = %d (reserved = %d, slush = %d))\n",
87 ctotcount * cbsize, ctotcount * cbsize - cfreecount, cfreecount,
88 cfreecount - cslushcount * cbsize, cslushcount * cbsize);
93 * Called from init_main.c
97 clist_init(void *dummy)
100 * Allocate an initial base set of cblocks as a 'slush'.
101 * We allocate non-slush cblocks with each initial ttyopen() and
102 * deallocate them with each ttyclose().
103 * We should adjust the slush allocation. This can't be done in
104 * the i/o routines because they are sometimes called from
105 * interrupt handlers when it may be unsafe to call kmalloc().
107 cblock_alloc_cblocks(cslushcount = INITIAL_CBLOCKS);
108 KKASSERT(sizeof(struct cblock) == CBLOCK);
112 * Remove a cblock from the cfreelist queue and return a pointer
117 * NOTE: Must be called with the related tp->t_token held
119 static struct cblock *
122 struct cblock *cblockp;
126 panic("clist reservation botch");
127 KKASSERT(cblockp->c_head.ch_magic == CLIST_MAGIC_FREE);
128 cfreelist = cblockp->c_head.ch_next;
129 cblockp->c_head.ch_next = NULL;
130 cblockp->c_head.ch_magic = CLIST_MAGIC_USED;
131 cfreecount -= CBSIZE;
136 * Add a cblock to the cfreelist queue.
138 * May not block, must be called in a critical section
140 * NOTE: Must be called with the related tp->t_token held.
143 cblock_free(struct cblock *cblockp)
145 if (isset(cblockp->c_quote, CBQSIZE * NBBY - 1))
146 bzero(cblockp->c_quote, sizeof cblockp->c_quote);
147 KKASSERT(cblockp->c_head.ch_magic == CLIST_MAGIC_USED);
148 cblockp->c_head.ch_next = cfreelist;
149 cblockp->c_head.ch_magic = CLIST_MAGIC_FREE;
151 cfreecount += CBSIZE;
155 * Allocate some cblocks for the cfreelist queue.
157 * This routine may block, but still must be called in a critical section
159 * NOTE: Must be called with the related tp->t_token held.
162 cblock_alloc_cblocks(int number)
167 for (i = 0; i < number; ++i) {
168 cbp = kmalloc(sizeof *cbp, M_TTYS, M_NOWAIT);
170 kprintf("clist_alloc_cblocks: M_NOWAIT "
171 "kmalloc failed, trying M_WAITOK\n");
172 cbp = kmalloc(sizeof *cbp, M_TTYS, M_WAITOK);
174 KKASSERT(((intptr_t)cbp & CROUND) == 0);
176 * Freed cblocks have zero quotes and garbage elsewhere.
177 * Set the may-have-quote bit to force zeroing the quotes.
179 setbit(cbp->c_quote, CBQSIZE * NBBY - 1);
180 cbp->c_head.ch_magic = CLIST_MAGIC_USED;
187 * Set the cblock allocation policy for a clist.
189 * NOTE: Must be called with the related tp->t_token held.
192 clist_alloc_cblocks(struct clist *clistp, int ccmax, int ccreserved)
197 * Allow for wasted space at the head.
202 ccreserved += CBSIZE - 1;
204 clistp->c_cbmax = roundup(ccmax, CBSIZE) / CBSIZE;
205 dcbr = roundup(ccreserved, CBSIZE) / CBSIZE - clistp->c_cbreserved;
207 clistp->c_cbreserved += dcbr; /* atomic w/c_cbmax */
208 cblock_alloc_cblocks(dcbr); /* may block */
210 KKASSERT(clistp->c_cbcount <= clistp->c_cbreserved);
211 if (clistp->c_cbreserved + dcbr < clistp->c_cbcount)
212 dcbr = clistp->c_cbcount - clistp->c_cbreserved;
213 clistp->c_cbreserved += dcbr; /* atomic w/c_cbmax */
214 cblock_free_cblocks(-dcbr); /* may block */
216 KKASSERT(clistp->c_cbreserved >= 0);
220 * Free some cblocks from the cfreelist queue back to the
221 * system malloc pool.
223 * NOTE: Must be called with the related tp->t_token held.
226 cblock_free_cblocks(int number)
230 for (i = 0; i < number; ++i)
231 kfree(cblock_alloc(), M_TTYS);
236 * Free the cblocks reserved for a clist.
238 * NOTE: Must be called with the related tp->t_token held.
241 clist_free_cblocks(struct clist *clistp)
245 if (clistp->c_cbcount != 0)
246 panic("freeing active clist cblocks");
247 cbreserved = clistp->c_cbreserved;
249 clistp->c_cbreserved = 0;
250 cblock_free_cblocks(cbreserved); /* may block */
254 * Get a character from the head of a clist.
256 * NOTE: Must be called with the related tp->t_token held.
259 clist_getc(struct clist *clistp)
262 struct cblock *cblockp;
265 KKASSERT(((intptr_t)clistp->c_cf & CROUND) != 0);
266 cblockp = (struct cblock *)((intptr_t)clistp->c_cf & ~CROUND);
267 chr = (u_char)*clistp->c_cf;
270 * If this char is quoted, set the flag.
272 if (isset(cblockp->c_quote,
273 clistp->c_cf - (char *)cblockp->c_info)) {
278 * Advance to next character.
283 * If we have advanced the 'first' character pointer
284 * past the end of this cblock, advance to the next one.
285 * If there are no more characters, set the first and
286 * last pointers to NULL. In either case, free the
289 KKASSERT(clistp->c_cf <= (char *)(cblockp + 1));
290 if ((clistp->c_cf == (char *)(cblockp + 1)) ||
291 (clistp->c_cc == 0)) {
292 if (clistp->c_cc > 0) {
293 clistp->c_cf = cblockp->c_head.ch_next->c_info;
295 clistp->c_cf = clistp->c_cl = NULL;
297 cblock_free(cblockp);
298 if (--clistp->c_cbcount >= clistp->c_cbreserved)
306 * Copy 'amount' of chars, beginning at head of clist 'clistp' to
307 * destination linear buffer 'dest'. Return number of characters
310 * Caller must hold related tp->t_token
313 q_to_b(struct clist *clistp, char *dest, int amount)
315 struct cblock *cblockp;
316 struct cblock *cblockn;
317 char *dest_orig = dest;
320 while (clistp && amount && (clistp->c_cc > 0)) {
321 KKASSERT(((intptr_t)clistp->c_cf & CROUND) != 0);
322 cblockp = (struct cblock *)((intptr_t)clistp->c_cf & ~CROUND);
323 cblockn = cblockp + 1; /* pointer arithmetic! */
324 numc = min(amount, (char *)cblockn - clistp->c_cf);
325 numc = min(numc, clistp->c_cc);
326 bcopy(clistp->c_cf, dest, numc);
328 clistp->c_cf += numc;
329 clistp->c_cc -= numc;
332 * If this cblock has been emptied, advance to the next
333 * one. If there are no more characters, set the first
334 * and last pointer to NULL. In either case, free the
337 KKASSERT(clistp->c_cf <= (char *)cblockn);
338 if ((clistp->c_cf == (char *)cblockn) || (clistp->c_cc == 0)) {
339 if (clistp->c_cc > 0) {
340 KKASSERT(cblockp->c_head.ch_next != NULL);
341 clistp->c_cf = cblockp->c_head.ch_next->c_info;
343 clistp->c_cf = clistp->c_cl = NULL;
345 cblock_free(cblockp);
346 if (--clistp->c_cbcount >= clistp->c_cbreserved)
350 return (dest - dest_orig);
354 * Flush 'amount' of chars, beginning at head of clist 'clistp'.
356 * Caller must hold related tp->t_token
359 ndflush(struct clist *clistp, int amount)
361 struct cblock *cblockp;
362 struct cblock *cblockn;
365 while (amount && (clistp->c_cc > 0)) {
366 KKASSERT(((intptr_t)clistp->c_cf & CROUND) != 0);
367 cblockp = (struct cblock *)((intptr_t)clistp->c_cf & ~CROUND);
368 cblockn = cblockp + 1; /* pointer arithmetic! */
369 numc = min(amount, (char *)cblockn - clistp->c_cf);
370 numc = min(numc, clistp->c_cc);
372 clistp->c_cf += numc;
373 clistp->c_cc -= numc;
375 * If this cblock has been emptied, advance to the next
376 * one. If there are no more characters, set the first
377 * and last pointer to NULL. In either case, free the
380 KKASSERT(clistp->c_cf <= (char *)cblockn);
381 if (clistp->c_cf == (char *)cblockn || clistp->c_cc == 0) {
382 if (clistp->c_cc > 0) {
383 KKASSERT(cblockp->c_head.ch_next != NULL);
384 clistp->c_cf = cblockp->c_head.ch_next->c_info;
386 clistp->c_cf = clistp->c_cl = NULL;
388 cblock_free(cblockp);
389 if (--clistp->c_cbcount >= clistp->c_cbreserved)
396 * Add a character to the end of a clist. Return -1 is no
397 * more clists, or 0 for success.
399 * Caller must hold related tp->t_token
402 clist_putc(int chr, struct clist *clistp)
404 struct cblock *cblockp;
407 * Note: this section may point c_cl at the base of a cblock. This
408 * is a temporary violation of the requirements for c_cl, we
409 * increment it before returning.
411 if (clistp->c_cl == NULL) {
412 if (clistp->c_cbreserved < 1) {
413 return (-1); /* nothing done */
415 cblockp = cblock_alloc();
416 clistp->c_cbcount = 1;
417 clistp->c_cf = clistp->c_cl = cblockp->c_info;
420 cblockp = (struct cblock *)((intptr_t)clistp->c_cl & ~CROUND);
421 if (((intptr_t)clistp->c_cl & CROUND) == 0) {
422 struct cblock *prev = (cblockp - 1);
424 if (clistp->c_cbcount >= clistp->c_cbreserved) {
425 if (clistp->c_cbcount >= clistp->c_cbmax
426 || cslushcount <= 0) {
431 cblockp = cblock_alloc();
433 prev->c_head.ch_next = cblockp;
434 clistp->c_cl = cblockp->c_info;
439 * If this character is quoted, set the quote bit, if not, clear it.
441 if (chr & TTY_QUOTE) {
442 setbit(cblockp->c_quote, clistp->c_cl - (char *)cblockp->c_info);
444 * Use one of the spare quote bits to record that something
447 setbit(cblockp->c_quote, CBQSIZE * NBBY - 1);
449 clrbit(cblockp->c_quote, clistp->c_cl - (char *)cblockp->c_info);
452 *clistp->c_cl++ = chr;
459 * Copy data from linear buffer to clist chain. Return the
460 * number of characters not copied.
462 * Caller must hold related tp->t_token
465 b_to_q(char *src, int amount, struct clist *clistp)
467 struct cblock *cblockp;
468 char *firstbyte, *lastbyte;
469 u_char startmask, endmask;
470 int startbit, endbit, num_between, numc;
473 * Avoid allocating an initial cblock and then not using it.
474 * c_cc == 0 must imply c_cbount == 0.
480 * Note: this section may point c_cl at the base of a cblock. This
481 * is a temporary violation of the requirements for c_cl. Since
482 * amount is non-zero we will not return with it in that state.
484 if (clistp->c_cl == NULL) {
485 if (clistp->c_cbreserved < 1) {
486 kprintf("b_to_q to a clist with no "
487 "reserved cblocks.\n");
488 return (amount); /* nothing done */
490 cblockp = cblock_alloc();
491 clistp->c_cbcount = 1;
492 clistp->c_cf = clistp->c_cl = cblockp->c_info;
496 * c_cl may legally point past the end of the block, which
497 * falls through to the 'get another cblock' code below.
499 cblockp = (struct cblock *)((intptr_t)clistp->c_cl & ~CROUND);
504 * Get another cblock if needed.
506 if (((intptr_t)clistp->c_cl & CROUND) == 0) {
507 struct cblock *prev = cblockp - 1;
509 if (clistp->c_cbcount >= clistp->c_cbreserved) {
510 if (clistp->c_cbcount >= clistp->c_cbmax
511 || cslushcount <= 0) {
516 cblockp = cblock_alloc();
518 prev->c_head.ch_next = cblockp;
519 clistp->c_cl = cblockp->c_info;
523 * Copy a chunk of the linear buffer up to the end
526 numc = min(amount, (char *)(cblockp + 1) - clistp->c_cl);
527 bcopy(src, clistp->c_cl, numc);
530 * Clear quote bits if they aren't known to be clear.
531 * The following could probably be made into a separate
532 * "bitzero()" routine, but why bother?
534 if (isset(cblockp->c_quote, CBQSIZE * NBBY - 1)) {
535 startbit = clistp->c_cl - (char *)cblockp->c_info;
536 endbit = startbit + numc - 1;
538 firstbyte = (u_char *)cblockp->c_quote + (startbit / NBBY);
539 lastbyte = (u_char *)cblockp->c_quote + (endbit / NBBY);
542 * Calculate mask of bits to preserve in first and
545 startmask = NBBY - (startbit % NBBY);
546 startmask = 0xff >> startmask;
547 endmask = (endbit % NBBY);
548 endmask = 0xff << (endmask + 1);
550 if (firstbyte != lastbyte) {
551 *firstbyte &= startmask;
552 *lastbyte &= endmask;
554 num_between = lastbyte - firstbyte - 1;
556 bzero(firstbyte + 1, num_between);
558 *firstbyte &= (startmask | endmask);
563 * ...and update pointer for the next chunk.
566 clistp->c_cl += numc;
567 clistp->c_cc += numc;
570 * If we go through the loop again, it's always
571 * for data in the next cblock, so by adding one (cblock),
572 * (which makes the pointer 1 beyond the end of this
573 * cblock) we prepare for the assignment of 'prev'
582 * Get the next character in the clist. Store it at dst. Don't
583 * advance any clist pointers, but return a pointer to the next
584 * character position.
586 * Caller must hold related tp->t_token
589 nextc(struct clist *clistp, char *cp, int *dst)
591 struct cblock *cblockp;
594 * See if the next character is beyond the end of
598 if (clistp->c_cc && (cp != clistp->c_cl)) {
600 * If the next character is beyond the end of this
601 * cblock, advance to the next cblock.
603 if (((intptr_t)cp & CROUND) == 0)
604 cp = ((struct cblock *)cp - 1)->c_head.ch_next->c_info;
605 cblockp = (struct cblock *)((intptr_t)cp & ~CROUND);
608 * Get the character. Set the quote flag if this character
612 (isset(cblockp->c_quote, cp - (char *)cblockp->c_info) ?
621 * "Unput" a character from a clist.
623 * Caller must hold related tp->t_token
626 clist_unputc(struct clist *clistp)
628 struct cblock *cblockp = NULL, *cbp = NULL;
633 * note that clistp->c_cl will never point at the base
634 * of a cblock (cblock->c_info) (see assert this later on),
635 * but it may point past the end of one. We temporarily
636 * violate this in the decrement below but then we fix it up.
641 chr = (u_char)*clistp->c_cl;
643 cblockp = (struct cblock *)((intptr_t)clistp->c_cl & ~CROUND);
646 * Set quote flag if this character was quoted.
648 if (isset(cblockp->c_quote, (u_char *)clistp->c_cl - cblockp->c_info))
652 * If all of the characters have been unput in this
653 * cblock, then find the previous one and free this
656 * if c_cc is 0 clistp->c_cl may end up pointing at
657 * cblockp->c_info, which is illegal, but the case will be
658 * taken care of near the end of the routine. Otherwise
659 * there *MUST* be another cblock, find it.
661 KKASSERT(clistp->c_cl >= (char *)cblockp->c_info);
662 if (clistp->c_cc && (clistp->c_cl == (char *)cblockp->c_info)) {
663 cbp = (struct cblock *)((intptr_t)clistp->c_cf &
666 while (cbp->c_head.ch_next != cblockp)
667 cbp = cbp->c_head.ch_next;
668 cbp->c_head.ch_next = NULL;
671 * When the previous cblock is at the end, the 'last'
672 * pointer always points (invalidly) one past.
674 clistp->c_cl = (char *)(cbp + 1);
675 cblock_free(cblockp);
676 if (--clistp->c_cbcount >= clistp->c_cbreserved)
682 * If there are no more characters on the list, then
683 * free the last cblock. It should not be possible for c->cl
684 * to be pointing past the end of a block due to our decrement
687 if (clistp->c_cc == 0 && clistp->c_cl) {
688 KKASSERT(((intptr_t)clistp->c_cl & CROUND) != 0);
689 cblockp = (struct cblock *)((intptr_t)clistp->c_cl & ~CROUND);
690 cblock_free(cblockp);
691 if (--clistp->c_cbcount >= clistp->c_cbreserved)
693 clistp->c_cf = clistp->c_cl = NULL;
699 * Move characters in source clist to destination clist,
700 * preserving quote bits.
703 catq(struct clist *src_clistp, struct clist *dest_clistp)
708 * If the destination clist is empty (has no cblocks atttached),
709 * and there are no possible complications with the resource counters,
710 * then we simply assign the current clist to the destination.
712 if (!dest_clistp->c_cf
713 && src_clistp->c_cbcount <= src_clistp->c_cbmax
714 && src_clistp->c_cbcount <= dest_clistp->c_cbmax) {
715 dest_clistp->c_cf = src_clistp->c_cf;
716 dest_clistp->c_cl = src_clistp->c_cl;
717 src_clistp->c_cf = src_clistp->c_cl = NULL;
719 dest_clistp->c_cc = src_clistp->c_cc;
720 src_clistp->c_cc = 0;
721 dest_clistp->c_cbcount = src_clistp->c_cbcount;
722 src_clistp->c_cbcount = 0;
728 * XXX This should probably be optimized to more than one
729 * character at a time.
731 while ((chr = clist_getc(src_clistp)) != -1)
732 clist_putc(chr, dest_clistp);