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 $
30 * $DragonFly: src/sys/kern/tty_subr.c,v 1.10 2006/12/23 00:35:04 swildner Exp $
35 * Most functions here could use a separate lock to deal with concurrent
36 * access to the cblocks and cblock_*_list.
38 * Right now the tty_token must be held for all this.
42 * clist support routines
44 * NOTE on cblock->c_cf: This pointer may point at the base of a cblock,
45 * which is &cblock->c_info[0], but will never
46 * point at the end of a cblock (char *)(cblk + 1)
48 * NOTE on cblock->c_cl: This pointer will never point at the base of
49 * a block but may point at the end of one.
51 * These routines may be used by more then just ttys, so a critical section
52 * must be used to access the free list, and for general safety.
55 #include <sys/param.h>
56 #include <sys/kernel.h>
57 #include <sys/systm.h>
58 #include <sys/malloc.h>
60 #include <sys/clist.h>
61 #include <sys/thread2.h>
63 static void clist_init (void *);
64 SYSINIT(clist, SI_SUB_CLIST, SI_ORDER_FIRST, clist_init, NULL)
66 static struct cblock *cfreelist = 0;
68 static int cslushcount;
71 #ifndef INITIAL_CBLOCKS
72 #define INITIAL_CBLOCKS 50
75 static struct cblock *cblock_alloc (void);
76 static void cblock_alloc_cblocks (int number);
77 static void cblock_free (struct cblock *cblockp);
78 static void cblock_free_cblocks (int number);
84 DB_SHOW_COMMAND(cbstat, cbstat)
89 "tot = %d (active = %d, free = %d (reserved = %d, slush = %d))\n",
90 ctotcount * cbsize, ctotcount * cbsize - cfreecount, cfreecount,
91 cfreecount - cslushcount * cbsize, cslushcount * cbsize);
96 * Called from init_main.c
100 clist_init(void *dummy)
103 * Allocate an initial base set of cblocks as a 'slush'.
104 * We allocate non-slush cblocks with each initial ttyopen() and
105 * deallocate them with each ttyclose().
106 * We should adjust the slush allocation. This can't be done in
107 * the i/o routines because they are sometimes called from
108 * interrupt handlers when it may be unsafe to call kmalloc().
110 lwkt_gettoken(&tty_token);
111 cblock_alloc_cblocks(cslushcount = INITIAL_CBLOCKS);
112 lwkt_reltoken(&tty_token);
113 KKASSERT(sizeof(struct cblock) == CBLOCK);
117 * Remove a cblock from the cfreelist queue and return a pointer
122 * NOTE: Must be called with tty_token held
124 static struct cblock *
127 struct cblock *cblockp;
129 ASSERT_LWKT_TOKEN_HELD(&tty_token);
133 panic("clist reservation botch");
134 KKASSERT(cblockp->c_head.ch_magic == CLIST_MAGIC_FREE);
135 cfreelist = cblockp->c_head.ch_next;
136 cblockp->c_head.ch_next = NULL;
137 cblockp->c_head.ch_magic = CLIST_MAGIC_USED;
138 cfreecount -= CBSIZE;
143 * Add a cblock to the cfreelist queue.
145 * May not block, must be called in a critical section
147 * NOTE: Must be called with tty_token held
150 cblock_free(struct cblock *cblockp)
152 ASSERT_LWKT_TOKEN_HELD(&tty_token);
154 if (isset(cblockp->c_quote, CBQSIZE * NBBY - 1))
155 bzero(cblockp->c_quote, sizeof cblockp->c_quote);
156 KKASSERT(cblockp->c_head.ch_magic == CLIST_MAGIC_USED);
157 cblockp->c_head.ch_next = cfreelist;
158 cblockp->c_head.ch_magic = CLIST_MAGIC_FREE;
160 cfreecount += CBSIZE;
164 * Allocate some cblocks for the cfreelist queue.
166 * This routine may block, but still must be called in a critical section
168 * NOTE: Must be called with tty_token held
171 cblock_alloc_cblocks(int number)
176 ASSERT_LWKT_TOKEN_HELD(&tty_token);
178 for (i = 0; i < number; ++i) {
179 cbp = kmalloc(sizeof *cbp, M_TTYS, M_NOWAIT);
182 "clist_alloc_cblocks: M_NOWAIT kmalloc failed, trying M_WAITOK\n");
183 cbp = kmalloc(sizeof *cbp, M_TTYS, M_WAITOK);
185 KKASSERT(((intptr_t)cbp & CROUND) == 0);
187 * Freed cblocks have zero quotes and garbage elsewhere.
188 * Set the may-have-quote bit to force zeroing the quotes.
190 setbit(cbp->c_quote, CBQSIZE * NBBY - 1);
191 cbp->c_head.ch_magic = CLIST_MAGIC_USED;
198 * Set the cblock allocation policy for a clist.
201 clist_alloc_cblocks(struct clist *clistp, int ccmax, int ccreserved)
206 * Allow for wasted space at the head.
211 ccreserved += CBSIZE - 1;
214 lwkt_gettoken(&tty_token);
215 clistp->c_cbmax = roundup(ccmax, CBSIZE) / CBSIZE;
216 dcbr = roundup(ccreserved, CBSIZE) / CBSIZE - clistp->c_cbreserved;
218 clistp->c_cbreserved += dcbr; /* atomic w/c_cbmax */
219 cblock_alloc_cblocks(dcbr); /* may block */
221 KKASSERT(clistp->c_cbcount <= clistp->c_cbreserved);
222 if (clistp->c_cbreserved + dcbr < clistp->c_cbcount)
223 dcbr = clistp->c_cbcount - clistp->c_cbreserved;
224 clistp->c_cbreserved += dcbr; /* atomic w/c_cbmax */
225 cblock_free_cblocks(-dcbr); /* may block */
227 KKASSERT(clistp->c_cbreserved >= 0);
228 lwkt_reltoken(&tty_token);
233 * Free some cblocks from the cfreelist queue back to the
234 * system malloc pool.
236 * Must be called from within a critical section. May block.
239 cblock_free_cblocks(int number)
243 lwkt_gettoken(&tty_token);
244 for (i = 0; i < number; ++i)
245 kfree(cblock_alloc(), M_TTYS);
247 lwkt_reltoken(&tty_token);
251 * Free the cblocks reserved for a clist.
254 clist_free_cblocks(struct clist *clistp)
259 lwkt_gettoken(&tty_token);
260 if (clistp->c_cbcount != 0)
261 panic("freeing active clist cblocks");
262 cbreserved = clistp->c_cbreserved;
264 clistp->c_cbreserved = 0;
265 cblock_free_cblocks(cbreserved); /* may block */
266 lwkt_reltoken(&tty_token);
271 * Get a character from the head of a clist.
274 clist_getc(struct clist *clistp)
277 struct cblock *cblockp;
280 lwkt_gettoken(&tty_token);
282 KKASSERT(((intptr_t)clistp->c_cf & CROUND) != 0);
283 cblockp = (struct cblock *)((intptr_t)clistp->c_cf & ~CROUND);
284 chr = (u_char)*clistp->c_cf;
287 * If this char is quoted, set the flag.
289 if (isset(cblockp->c_quote, clistp->c_cf - (char *)cblockp->c_info))
293 * Advance to next character.
298 * If we have advanced the 'first' character pointer
299 * past the end of this cblock, advance to the next one.
300 * If there are no more characters, set the first and
301 * last pointers to NULL. In either case, free the
304 KKASSERT(clistp->c_cf <= (char *)(cblockp + 1));
305 if ((clistp->c_cf == (char *)(cblockp + 1)) ||
306 (clistp->c_cc == 0)) {
307 if (clistp->c_cc > 0) {
308 clistp->c_cf = cblockp->c_head.ch_next->c_info;
310 clistp->c_cf = clistp->c_cl = NULL;
312 cblock_free(cblockp);
313 if (--clistp->c_cbcount >= clistp->c_cbreserved)
317 lwkt_reltoken(&tty_token);
323 * Copy 'amount' of chars, beginning at head of clist 'clistp' to
324 * destination linear buffer 'dest'. Return number of characters
328 q_to_b(struct clist *clistp, char *dest, int amount)
330 struct cblock *cblockp;
331 struct cblock *cblockn;
332 char *dest_orig = dest;
336 lwkt_gettoken(&tty_token);
337 while (clistp && amount && (clistp->c_cc > 0)) {
338 KKASSERT(((intptr_t)clistp->c_cf & CROUND) != 0);
339 cblockp = (struct cblock *)((intptr_t)clistp->c_cf & ~CROUND);
340 cblockn = cblockp + 1; /* pointer arithmetic! */
341 numc = min(amount, (char *)cblockn - clistp->c_cf);
342 numc = min(numc, clistp->c_cc);
343 bcopy(clistp->c_cf, dest, numc);
345 clistp->c_cf += numc;
346 clistp->c_cc -= numc;
349 * If this cblock has been emptied, advance to the next
350 * one. If there are no more characters, set the first
351 * and last pointer to NULL. In either case, free the
354 KKASSERT(clistp->c_cf <= (char *)cblockn);
355 if ((clistp->c_cf == (char *)cblockn) || (clistp->c_cc == 0)) {
356 if (clistp->c_cc > 0) {
357 KKASSERT(cblockp->c_head.ch_next != NULL);
358 clistp->c_cf = cblockp->c_head.ch_next->c_info;
360 clistp->c_cf = clistp->c_cl = NULL;
362 cblock_free(cblockp);
363 if (--clistp->c_cbcount >= clistp->c_cbreserved)
367 lwkt_reltoken(&tty_token);
369 return (dest - dest_orig);
373 * Flush 'amount' of chars, beginning at head of clist 'clistp'.
376 ndflush(struct clist *clistp, int amount)
378 struct cblock *cblockp;
379 struct cblock *cblockn;
383 lwkt_gettoken(&tty_token);
384 while (amount && (clistp->c_cc > 0)) {
385 KKASSERT(((intptr_t)clistp->c_cf & CROUND) != 0);
386 cblockp = (struct cblock *)((intptr_t)clistp->c_cf & ~CROUND);
387 cblockn = cblockp + 1; /* pointer arithmetic! */
388 numc = min(amount, (char *)cblockn - clistp->c_cf);
389 numc = min(numc, clistp->c_cc);
391 clistp->c_cf += numc;
392 clistp->c_cc -= numc;
394 * If this cblock has been emptied, advance to the next
395 * one. If there are no more characters, set the first
396 * and last pointer to NULL. In either case, free the
399 KKASSERT(clistp->c_cf <= (char *)cblockn);
400 if (clistp->c_cf == (char *)cblockn || clistp->c_cc == 0) {
401 if (clistp->c_cc > 0) {
402 KKASSERT(cblockp->c_head.ch_next != NULL);
403 clistp->c_cf = cblockp->c_head.ch_next->c_info;
405 clistp->c_cf = clistp->c_cl = NULL;
407 cblock_free(cblockp);
408 if (--clistp->c_cbcount >= clistp->c_cbreserved)
412 lwkt_reltoken(&tty_token);
417 * Add a character to the end of a clist. Return -1 is no
418 * more clists, or 0 for success.
421 clist_putc(int chr, struct clist *clistp)
423 struct cblock *cblockp;
426 lwkt_gettoken(&tty_token);
429 * Note: this section may point c_cl at the base of a cblock. This
430 * is a temporary violation of the requirements for c_cl, we
431 * increment it before returning.
433 if (clistp->c_cl == NULL) {
434 if (clistp->c_cbreserved < 1) {
435 lwkt_reltoken(&tty_token);
437 kprintf("putc to a clist with no reserved cblocks\n");
438 return (-1); /* nothing done */
440 cblockp = cblock_alloc();
441 clistp->c_cbcount = 1;
442 clistp->c_cf = clistp->c_cl = cblockp->c_info;
445 cblockp = (struct cblock *)((intptr_t)clistp->c_cl & ~CROUND);
446 if (((intptr_t)clistp->c_cl & CROUND) == 0) {
447 struct cblock *prev = (cblockp - 1);
449 if (clistp->c_cbcount >= clistp->c_cbreserved) {
450 if (clistp->c_cbcount >= clistp->c_cbmax
451 || cslushcount <= 0) {
452 lwkt_reltoken(&tty_token);
458 cblockp = cblock_alloc();
460 prev->c_head.ch_next = cblockp;
461 clistp->c_cl = cblockp->c_info;
466 * If this character is quoted, set the quote bit, if not, clear it.
468 if (chr & TTY_QUOTE) {
469 setbit(cblockp->c_quote, clistp->c_cl - (char *)cblockp->c_info);
471 * Use one of the spare quote bits to record that something
474 setbit(cblockp->c_quote, CBQSIZE * NBBY - 1);
476 clrbit(cblockp->c_quote, clistp->c_cl - (char *)cblockp->c_info);
479 *clistp->c_cl++ = chr;
482 lwkt_reltoken(&tty_token);
488 * Copy data from linear buffer to clist chain. Return the
489 * number of characters not copied.
492 b_to_q(char *src, int amount, struct clist *clistp)
494 struct cblock *cblockp;
495 char *firstbyte, *lastbyte;
496 u_char startmask, endmask;
497 int startbit, endbit, num_between, numc;
500 * Avoid allocating an initial cblock and then not using it.
501 * c_cc == 0 must imply c_cbount == 0.
507 lwkt_gettoken(&tty_token);
510 * Note: this section may point c_cl at the base of a cblock. This
511 * is a temporary violation of the requirements for c_cl. Since
512 * amount is non-zero we will not return with it in that state.
514 if (clistp->c_cl == NULL) {
515 if (clistp->c_cbreserved < 1) {
516 lwkt_reltoken(&tty_token);
518 kprintf("b_to_q to a clist with no reserved cblocks.\n");
519 return (amount); /* nothing done */
521 cblockp = cblock_alloc();
522 clistp->c_cbcount = 1;
523 clistp->c_cf = clistp->c_cl = cblockp->c_info;
527 * c_cl may legally point past the end of the block, which
528 * falls through to the 'get another cblock' code below.
530 cblockp = (struct cblock *)((intptr_t)clistp->c_cl & ~CROUND);
535 * Get another cblock if needed.
537 if (((intptr_t)clistp->c_cl & CROUND) == 0) {
538 struct cblock *prev = cblockp - 1;
540 if (clistp->c_cbcount >= clistp->c_cbreserved) {
541 if (clistp->c_cbcount >= clistp->c_cbmax
542 || cslushcount <= 0) {
543 lwkt_reltoken(&tty_token);
549 cblockp = cblock_alloc();
551 prev->c_head.ch_next = cblockp;
552 clistp->c_cl = cblockp->c_info;
556 * Copy a chunk of the linear buffer up to the end
559 numc = min(amount, (char *)(cblockp + 1) - clistp->c_cl);
560 bcopy(src, clistp->c_cl, numc);
563 * Clear quote bits if they aren't known to be clear.
564 * The following could probably be made into a separate
565 * "bitzero()" routine, but why bother?
567 if (isset(cblockp->c_quote, CBQSIZE * NBBY - 1)) {
568 startbit = clistp->c_cl - (char *)cblockp->c_info;
569 endbit = startbit + numc - 1;
571 firstbyte = (u_char *)cblockp->c_quote + (startbit / NBBY);
572 lastbyte = (u_char *)cblockp->c_quote + (endbit / NBBY);
575 * Calculate mask of bits to preserve in first and
578 startmask = NBBY - (startbit % NBBY);
579 startmask = 0xff >> startmask;
580 endmask = (endbit % NBBY);
581 endmask = 0xff << (endmask + 1);
583 if (firstbyte != lastbyte) {
584 *firstbyte &= startmask;
585 *lastbyte &= endmask;
587 num_between = lastbyte - firstbyte - 1;
589 bzero(firstbyte + 1, num_between);
591 *firstbyte &= (startmask | endmask);
596 * ...and update pointer for the next chunk.
599 clistp->c_cl += numc;
600 clistp->c_cc += numc;
603 * If we go through the loop again, it's always
604 * for data in the next cblock, so by adding one (cblock),
605 * (which makes the pointer 1 beyond the end of this
606 * cblock) we prepare for the assignment of 'prev'
611 lwkt_reltoken(&tty_token);
617 * Get the next character in the clist. Store it at dst. Don't
618 * advance any clist pointers, but return a pointer to the next
619 * character position.
621 * Must be called at spltty(). This routine may not run in a critical
622 * section and so may not call the cblock allocator/deallocator.
625 nextc(struct clist *clistp, char *cp, int *dst)
627 struct cblock *cblockp;
631 * See if the next character is beyond the end of
634 lwkt_gettoken(&tty_token);
635 if (clistp->c_cc && (cp != clistp->c_cl)) {
637 * If the next character is beyond the end of this
638 * cblock, advance to the next cblock.
640 if (((intptr_t)cp & CROUND) == 0)
641 cp = ((struct cblock *)cp - 1)->c_head.ch_next->c_info;
642 cblockp = (struct cblock *)((intptr_t)cp & ~CROUND);
645 * Get the character. Set the quote flag if this character
648 *dst = (u_char)*cp | (isset(cblockp->c_quote, cp - (char *)cblockp->c_info) ? TTY_QUOTE : 0);
650 lwkt_reltoken(&tty_token);
654 lwkt_reltoken(&tty_token);
659 * "Unput" a character from a clist.
662 clist_unputc(struct clist *clistp)
664 struct cblock *cblockp = 0, *cbp = 0;
668 lwkt_gettoken(&tty_token);
672 * note that clistp->c_cl will never point at the base
673 * of a cblock (cblock->c_info) (see assert this later on),
674 * but it may point past the end of one. We temporarily
675 * violate this in the decrement below but then we fix it up.
680 chr = (u_char)*clistp->c_cl;
682 cblockp = (struct cblock *)((intptr_t)clistp->c_cl & ~CROUND);
685 * Set quote flag if this character was quoted.
687 if (isset(cblockp->c_quote, (u_char *)clistp->c_cl - cblockp->c_info))
691 * If all of the characters have been unput in this
692 * cblock, then find the previous one and free this
695 * if c_cc is 0 clistp->c_cl may end up pointing at
696 * cblockp->c_info, which is illegal, but the case will be
697 * taken care of near the end of the routine. Otherwise
698 * there *MUST* be another cblock, find it.
700 KKASSERT(clistp->c_cl >= (char *)cblockp->c_info);
701 if (clistp->c_cc && (clistp->c_cl == (char *)cblockp->c_info)) {
702 cbp = (struct cblock *)((intptr_t)clistp->c_cf & ~CROUND);
704 while (cbp->c_head.ch_next != cblockp)
705 cbp = cbp->c_head.ch_next;
706 cbp->c_head.ch_next = NULL;
709 * When the previous cblock is at the end, the 'last'
710 * pointer always points (invalidly) one past.
712 clistp->c_cl = (char *)(cbp + 1);
713 cblock_free(cblockp);
714 if (--clistp->c_cbcount >= clistp->c_cbreserved)
720 * If there are no more characters on the list, then
721 * free the last cblock. It should not be possible for c->cl
722 * to be pointing past the end of a block due to our decrement
725 if (clistp->c_cc == 0 && clistp->c_cl) {
726 KKASSERT(((intptr_t)clistp->c_cl & CROUND) != 0);
727 cblockp = (struct cblock *)((intptr_t)clistp->c_cl & ~CROUND);
728 cblock_free(cblockp);
729 if (--clistp->c_cbcount >= clistp->c_cbreserved)
731 clistp->c_cf = clistp->c_cl = NULL;
734 lwkt_reltoken(&tty_token);
740 * Move characters in source clist to destination clist,
741 * preserving quote bits.
744 catq(struct clist *src_clistp, struct clist *dest_clistp)
748 lwkt_gettoken(&tty_token);
751 * If the destination clist is empty (has no cblocks atttached),
752 * and there are no possible complications with the resource counters,
753 * then we simply assign the current clist to the destination.
755 if (!dest_clistp->c_cf
756 && src_clistp->c_cbcount <= src_clistp->c_cbmax
757 && src_clistp->c_cbcount <= dest_clistp->c_cbmax) {
758 dest_clistp->c_cf = src_clistp->c_cf;
759 dest_clistp->c_cl = src_clistp->c_cl;
760 src_clistp->c_cf = src_clistp->c_cl = NULL;
762 dest_clistp->c_cc = src_clistp->c_cc;
763 src_clistp->c_cc = 0;
764 dest_clistp->c_cbcount = src_clistp->c_cbcount;
765 src_clistp->c_cbcount = 0;
768 lwkt_reltoken(&tty_token);
774 * XXX This should probably be optimized to more than one
775 * character at a time.
777 while ((chr = clist_getc(src_clistp)) != -1)
778 clist_putc(chr, dest_clistp);
779 lwkt_reltoken(&tty_token);