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.
37 * Right now the tty_token must be held for all this.
41 * clist support routines
43 * NOTE on cblock->c_cf: This pointer may point at the base of a cblock,
44 * which is &cblock->c_info[0], but will never
45 * point at the end of a cblock (char *)(cblk + 1)
47 * NOTE on cblock->c_cl: This pointer will never point at the base of
48 * a block but may point at the end of one.
50 * These routines may be used by more then just ttys, so a critical section
51 * must be used to access the free list, and for general safety.
54 #include <sys/param.h>
55 #include <sys/kernel.h>
56 #include <sys/systm.h>
57 #include <sys/malloc.h>
59 #include <sys/clist.h>
60 #include <sys/thread2.h>
62 static void clist_init (void *);
63 SYSINIT(clist
, SI_SUB_CLIST
, SI_ORDER_FIRST
, clist_init
, NULL
);
65 static struct cblock
*cfreelist
= NULL
;
67 static int cslushcount
;
70 #ifndef INITIAL_CBLOCKS
71 #define INITIAL_CBLOCKS 50
74 static struct cblock
*cblock_alloc (void);
75 static void cblock_alloc_cblocks (int number
);
76 static void cblock_free (struct cblock
*cblockp
);
77 static void cblock_free_cblocks (int number
);
83 DB_SHOW_COMMAND(cbstat
, cbstat
)
88 "tot = %d (active = %d, free = %d (reserved = %d, slush = %d))\n",
89 ctotcount
* cbsize
, ctotcount
* cbsize
- cfreecount
, cfreecount
,
90 cfreecount
- cslushcount
* cbsize
, cslushcount
* cbsize
);
95 * Called from init_main.c
99 clist_init(void *dummy
)
102 * Allocate an initial base set of cblocks as a 'slush'.
103 * We allocate non-slush cblocks with each initial ttyopen() and
104 * deallocate them with each ttyclose().
105 * We should adjust the slush allocation. This can't be done in
106 * the i/o routines because they are sometimes called from
107 * interrupt handlers when it may be unsafe to call kmalloc().
109 lwkt_gettoken(&tty_token
);
110 cblock_alloc_cblocks(cslushcount
= INITIAL_CBLOCKS
);
111 lwkt_reltoken(&tty_token
);
112 KKASSERT(sizeof(struct cblock
) == CBLOCK
);
116 * Remove a cblock from the cfreelist queue and return a pointer
121 * NOTE: Must be called with tty_token held
123 static struct cblock
*
126 struct cblock
*cblockp
;
128 ASSERT_LWKT_TOKEN_HELD(&tty_token
);
132 panic("clist reservation botch");
133 KKASSERT(cblockp
->c_head
.ch_magic
== CLIST_MAGIC_FREE
);
134 cfreelist
= cblockp
->c_head
.ch_next
;
135 cblockp
->c_head
.ch_next
= NULL
;
136 cblockp
->c_head
.ch_magic
= CLIST_MAGIC_USED
;
137 cfreecount
-= CBSIZE
;
142 * Add a cblock to the cfreelist queue.
144 * May not block, must be called in a critical section
146 * NOTE: Must be called with tty_token held
149 cblock_free(struct cblock
*cblockp
)
151 ASSERT_LWKT_TOKEN_HELD(&tty_token
);
153 if (isset(cblockp
->c_quote
, CBQSIZE
* NBBY
- 1))
154 bzero(cblockp
->c_quote
, sizeof cblockp
->c_quote
);
155 KKASSERT(cblockp
->c_head
.ch_magic
== CLIST_MAGIC_USED
);
156 cblockp
->c_head
.ch_next
= cfreelist
;
157 cblockp
->c_head
.ch_magic
= CLIST_MAGIC_FREE
;
159 cfreecount
+= CBSIZE
;
163 * Allocate some cblocks for the cfreelist queue.
165 * This routine may block, but still must be called in a critical section
167 * NOTE: Must be called with tty_token held
170 cblock_alloc_cblocks(int number
)
175 ASSERT_LWKT_TOKEN_HELD(&tty_token
);
177 for (i
= 0; i
< number
; ++i
) {
178 cbp
= kmalloc(sizeof *cbp
, M_TTYS
, M_NOWAIT
);
181 "clist_alloc_cblocks: M_NOWAIT kmalloc failed, trying M_WAITOK\n");
182 cbp
= kmalloc(sizeof *cbp
, M_TTYS
, M_WAITOK
);
184 KKASSERT(((intptr_t)cbp
& CROUND
) == 0);
186 * Freed cblocks have zero quotes and garbage elsewhere.
187 * Set the may-have-quote bit to force zeroing the quotes.
189 setbit(cbp
->c_quote
, CBQSIZE
* NBBY
- 1);
190 cbp
->c_head
.ch_magic
= CLIST_MAGIC_USED
;
197 * Set the cblock allocation policy for a clist.
200 clist_alloc_cblocks(struct clist
*clistp
, int ccmax
, int ccreserved
)
205 * Allow for wasted space at the head.
210 ccreserved
+= CBSIZE
- 1;
213 lwkt_gettoken(&tty_token
);
214 clistp
->c_cbmax
= roundup(ccmax
, CBSIZE
) / CBSIZE
;
215 dcbr
= roundup(ccreserved
, CBSIZE
) / CBSIZE
- clistp
->c_cbreserved
;
217 clistp
->c_cbreserved
+= dcbr
; /* atomic w/c_cbmax */
218 cblock_alloc_cblocks(dcbr
); /* may block */
220 KKASSERT(clistp
->c_cbcount
<= clistp
->c_cbreserved
);
221 if (clistp
->c_cbreserved
+ dcbr
< clistp
->c_cbcount
)
222 dcbr
= clistp
->c_cbcount
- clistp
->c_cbreserved
;
223 clistp
->c_cbreserved
+= dcbr
; /* atomic w/c_cbmax */
224 cblock_free_cblocks(-dcbr
); /* may block */
226 KKASSERT(clistp
->c_cbreserved
>= 0);
227 lwkt_reltoken(&tty_token
);
232 * Free some cblocks from the cfreelist queue back to the
233 * system malloc pool.
235 * Must be called from within a critical section. May block.
238 cblock_free_cblocks(int number
)
242 lwkt_gettoken(&tty_token
);
243 for (i
= 0; i
< number
; ++i
)
244 kfree(cblock_alloc(), M_TTYS
);
246 lwkt_reltoken(&tty_token
);
250 * Free the cblocks reserved for a clist.
253 clist_free_cblocks(struct clist
*clistp
)
258 lwkt_gettoken(&tty_token
);
259 if (clistp
->c_cbcount
!= 0)
260 panic("freeing active clist cblocks");
261 cbreserved
= clistp
->c_cbreserved
;
263 clistp
->c_cbreserved
= 0;
264 cblock_free_cblocks(cbreserved
); /* may block */
265 lwkt_reltoken(&tty_token
);
270 * Get a character from the head of a clist.
273 clist_getc(struct clist
*clistp
)
276 struct cblock
*cblockp
;
279 lwkt_gettoken(&tty_token
);
281 KKASSERT(((intptr_t)clistp
->c_cf
& CROUND
) != 0);
282 cblockp
= (struct cblock
*)((intptr_t)clistp
->c_cf
& ~CROUND
);
283 chr
= (u_char
)*clistp
->c_cf
;
286 * If this char is quoted, set the flag.
288 if (isset(cblockp
->c_quote
, clistp
->c_cf
- (char *)cblockp
->c_info
))
292 * Advance to next character.
297 * If we have advanced the 'first' character pointer
298 * past the end of this cblock, advance to the next one.
299 * If there are no more characters, set the first and
300 * last pointers to NULL. In either case, free the
303 KKASSERT(clistp
->c_cf
<= (char *)(cblockp
+ 1));
304 if ((clistp
->c_cf
== (char *)(cblockp
+ 1)) ||
305 (clistp
->c_cc
== 0)) {
306 if (clistp
->c_cc
> 0) {
307 clistp
->c_cf
= cblockp
->c_head
.ch_next
->c_info
;
309 clistp
->c_cf
= clistp
->c_cl
= NULL
;
311 cblock_free(cblockp
);
312 if (--clistp
->c_cbcount
>= clistp
->c_cbreserved
)
316 lwkt_reltoken(&tty_token
);
322 * Copy 'amount' of chars, beginning at head of clist 'clistp' to
323 * destination linear buffer 'dest'. Return number of characters
327 q_to_b(struct clist
*clistp
, char *dest
, int amount
)
329 struct cblock
*cblockp
;
330 struct cblock
*cblockn
;
331 char *dest_orig
= dest
;
335 lwkt_gettoken(&tty_token
);
336 while (clistp
&& amount
&& (clistp
->c_cc
> 0)) {
337 KKASSERT(((intptr_t)clistp
->c_cf
& CROUND
) != 0);
338 cblockp
= (struct cblock
*)((intptr_t)clistp
->c_cf
& ~CROUND
);
339 cblockn
= cblockp
+ 1; /* pointer arithmetic! */
340 numc
= min(amount
, (char *)cblockn
- clistp
->c_cf
);
341 numc
= min(numc
, clistp
->c_cc
);
342 bcopy(clistp
->c_cf
, dest
, numc
);
344 clistp
->c_cf
+= numc
;
345 clistp
->c_cc
-= numc
;
348 * If this cblock has been emptied, advance to the next
349 * one. If there are no more characters, set the first
350 * and last pointer to NULL. In either case, free the
353 KKASSERT(clistp
->c_cf
<= (char *)cblockn
);
354 if ((clistp
->c_cf
== (char *)cblockn
) || (clistp
->c_cc
== 0)) {
355 if (clistp
->c_cc
> 0) {
356 KKASSERT(cblockp
->c_head
.ch_next
!= NULL
);
357 clistp
->c_cf
= cblockp
->c_head
.ch_next
->c_info
;
359 clistp
->c_cf
= clistp
->c_cl
= NULL
;
361 cblock_free(cblockp
);
362 if (--clistp
->c_cbcount
>= clistp
->c_cbreserved
)
366 lwkt_reltoken(&tty_token
);
368 return (dest
- dest_orig
);
372 * Flush 'amount' of chars, beginning at head of clist 'clistp'.
375 ndflush(struct clist
*clistp
, int amount
)
377 struct cblock
*cblockp
;
378 struct cblock
*cblockn
;
382 lwkt_gettoken(&tty_token
);
383 while (amount
&& (clistp
->c_cc
> 0)) {
384 KKASSERT(((intptr_t)clistp
->c_cf
& CROUND
) != 0);
385 cblockp
= (struct cblock
*)((intptr_t)clistp
->c_cf
& ~CROUND
);
386 cblockn
= cblockp
+ 1; /* pointer arithmetic! */
387 numc
= min(amount
, (char *)cblockn
- clistp
->c_cf
);
388 numc
= min(numc
, clistp
->c_cc
);
390 clistp
->c_cf
+= numc
;
391 clistp
->c_cc
-= numc
;
393 * If this cblock has been emptied, advance to the next
394 * one. If there are no more characters, set the first
395 * and last pointer to NULL. In either case, free the
398 KKASSERT(clistp
->c_cf
<= (char *)cblockn
);
399 if (clistp
->c_cf
== (char *)cblockn
|| clistp
->c_cc
== 0) {
400 if (clistp
->c_cc
> 0) {
401 KKASSERT(cblockp
->c_head
.ch_next
!= NULL
);
402 clistp
->c_cf
= cblockp
->c_head
.ch_next
->c_info
;
404 clistp
->c_cf
= clistp
->c_cl
= NULL
;
406 cblock_free(cblockp
);
407 if (--clistp
->c_cbcount
>= clistp
->c_cbreserved
)
411 lwkt_reltoken(&tty_token
);
416 * Add a character to the end of a clist. Return -1 is no
417 * more clists, or 0 for success.
420 clist_putc(int chr
, struct clist
*clistp
)
422 struct cblock
*cblockp
;
425 lwkt_gettoken(&tty_token
);
428 * Note: this section may point c_cl at the base of a cblock. This
429 * is a temporary violation of the requirements for c_cl, we
430 * increment it before returning.
432 if (clistp
->c_cl
== NULL
) {
433 if (clistp
->c_cbreserved
< 1) {
434 lwkt_reltoken(&tty_token
);
436 return (-1); /* nothing done */
438 cblockp
= cblock_alloc();
439 clistp
->c_cbcount
= 1;
440 clistp
->c_cf
= clistp
->c_cl
= cblockp
->c_info
;
443 cblockp
= (struct cblock
*)((intptr_t)clistp
->c_cl
& ~CROUND
);
444 if (((intptr_t)clistp
->c_cl
& CROUND
) == 0) {
445 struct cblock
*prev
= (cblockp
- 1);
447 if (clistp
->c_cbcount
>= clistp
->c_cbreserved
) {
448 if (clistp
->c_cbcount
>= clistp
->c_cbmax
449 || cslushcount
<= 0) {
450 lwkt_reltoken(&tty_token
);
456 cblockp
= cblock_alloc();
458 prev
->c_head
.ch_next
= cblockp
;
459 clistp
->c_cl
= cblockp
->c_info
;
464 * If this character is quoted, set the quote bit, if not, clear it.
466 if (chr
& TTY_QUOTE
) {
467 setbit(cblockp
->c_quote
, clistp
->c_cl
- (char *)cblockp
->c_info
);
469 * Use one of the spare quote bits to record that something
472 setbit(cblockp
->c_quote
, CBQSIZE
* NBBY
- 1);
474 clrbit(cblockp
->c_quote
, clistp
->c_cl
- (char *)cblockp
->c_info
);
477 *clistp
->c_cl
++ = chr
;
480 lwkt_reltoken(&tty_token
);
486 * Copy data from linear buffer to clist chain. Return the
487 * number of characters not copied.
490 b_to_q(char *src
, int amount
, struct clist
*clistp
)
492 struct cblock
*cblockp
;
493 char *firstbyte
, *lastbyte
;
494 u_char startmask
, endmask
;
495 int startbit
, endbit
, num_between
, numc
;
498 * Avoid allocating an initial cblock and then not using it.
499 * c_cc == 0 must imply c_cbount == 0.
505 lwkt_gettoken(&tty_token
);
508 * Note: this section may point c_cl at the base of a cblock. This
509 * is a temporary violation of the requirements for c_cl. Since
510 * amount is non-zero we will not return with it in that state.
512 if (clistp
->c_cl
== NULL
) {
513 if (clistp
->c_cbreserved
< 1) {
514 lwkt_reltoken(&tty_token
);
516 kprintf("b_to_q to a clist with no reserved cblocks.\n");
517 return (amount
); /* nothing done */
519 cblockp
= cblock_alloc();
520 clistp
->c_cbcount
= 1;
521 clistp
->c_cf
= clistp
->c_cl
= cblockp
->c_info
;
525 * c_cl may legally point past the end of the block, which
526 * falls through to the 'get another cblock' code below.
528 cblockp
= (struct cblock
*)((intptr_t)clistp
->c_cl
& ~CROUND
);
533 * Get another cblock if needed.
535 if (((intptr_t)clistp
->c_cl
& CROUND
) == 0) {
536 struct cblock
*prev
= cblockp
- 1;
538 if (clistp
->c_cbcount
>= clistp
->c_cbreserved
) {
539 if (clistp
->c_cbcount
>= clistp
->c_cbmax
540 || cslushcount
<= 0) {
541 lwkt_reltoken(&tty_token
);
547 cblockp
= cblock_alloc();
549 prev
->c_head
.ch_next
= cblockp
;
550 clistp
->c_cl
= cblockp
->c_info
;
554 * Copy a chunk of the linear buffer up to the end
557 numc
= min(amount
, (char *)(cblockp
+ 1) - clistp
->c_cl
);
558 bcopy(src
, clistp
->c_cl
, numc
);
561 * Clear quote bits if they aren't known to be clear.
562 * The following could probably be made into a separate
563 * "bitzero()" routine, but why bother?
565 if (isset(cblockp
->c_quote
, CBQSIZE
* NBBY
- 1)) {
566 startbit
= clistp
->c_cl
- (char *)cblockp
->c_info
;
567 endbit
= startbit
+ numc
- 1;
569 firstbyte
= (u_char
*)cblockp
->c_quote
+ (startbit
/ NBBY
);
570 lastbyte
= (u_char
*)cblockp
->c_quote
+ (endbit
/ NBBY
);
573 * Calculate mask of bits to preserve in first and
576 startmask
= NBBY
- (startbit
% NBBY
);
577 startmask
= 0xff >> startmask
;
578 endmask
= (endbit
% NBBY
);
579 endmask
= 0xff << (endmask
+ 1);
581 if (firstbyte
!= lastbyte
) {
582 *firstbyte
&= startmask
;
583 *lastbyte
&= endmask
;
585 num_between
= lastbyte
- firstbyte
- 1;
587 bzero(firstbyte
+ 1, num_between
);
589 *firstbyte
&= (startmask
| endmask
);
594 * ...and update pointer for the next chunk.
597 clistp
->c_cl
+= numc
;
598 clistp
->c_cc
+= numc
;
601 * If we go through the loop again, it's always
602 * for data in the next cblock, so by adding one (cblock),
603 * (which makes the pointer 1 beyond the end of this
604 * cblock) we prepare for the assignment of 'prev'
609 lwkt_reltoken(&tty_token
);
615 * Get the next character in the clist. Store it at dst. Don't
616 * advance any clist pointers, but return a pointer to the next
617 * character position.
619 * Must be called at spltty(). This routine may not run in a critical
620 * section and so may not call the cblock allocator/deallocator.
623 nextc(struct clist
*clistp
, char *cp
, int *dst
)
625 struct cblock
*cblockp
;
629 * See if the next character is beyond the end of
632 lwkt_gettoken(&tty_token
);
633 if (clistp
->c_cc
&& (cp
!= clistp
->c_cl
)) {
635 * If the next character is beyond the end of this
636 * cblock, advance to the next cblock.
638 if (((intptr_t)cp
& CROUND
) == 0)
639 cp
= ((struct cblock
*)cp
- 1)->c_head
.ch_next
->c_info
;
640 cblockp
= (struct cblock
*)((intptr_t)cp
& ~CROUND
);
643 * Get the character. Set the quote flag if this character
646 *dst
= (u_char
)*cp
| (isset(cblockp
->c_quote
, cp
- (char *)cblockp
->c_info
) ? TTY_QUOTE
: 0);
648 lwkt_reltoken(&tty_token
);
652 lwkt_reltoken(&tty_token
);
657 * "Unput" a character from a clist.
660 clist_unputc(struct clist
*clistp
)
662 struct cblock
*cblockp
= NULL
, *cbp
= NULL
;
666 lwkt_gettoken(&tty_token
);
670 * note that clistp->c_cl will never point at the base
671 * of a cblock (cblock->c_info) (see assert this later on),
672 * but it may point past the end of one. We temporarily
673 * violate this in the decrement below but then we fix it up.
678 chr
= (u_char
)*clistp
->c_cl
;
680 cblockp
= (struct cblock
*)((intptr_t)clistp
->c_cl
& ~CROUND
);
683 * Set quote flag if this character was quoted.
685 if (isset(cblockp
->c_quote
, (u_char
*)clistp
->c_cl
- cblockp
->c_info
))
689 * If all of the characters have been unput in this
690 * cblock, then find the previous one and free this
693 * if c_cc is 0 clistp->c_cl may end up pointing at
694 * cblockp->c_info, which is illegal, but the case will be
695 * taken care of near the end of the routine. Otherwise
696 * there *MUST* be another cblock, find it.
698 KKASSERT(clistp
->c_cl
>= (char *)cblockp
->c_info
);
699 if (clistp
->c_cc
&& (clistp
->c_cl
== (char *)cblockp
->c_info
)) {
700 cbp
= (struct cblock
*)((intptr_t)clistp
->c_cf
& ~CROUND
);
702 while (cbp
->c_head
.ch_next
!= cblockp
)
703 cbp
= cbp
->c_head
.ch_next
;
704 cbp
->c_head
.ch_next
= NULL
;
707 * When the previous cblock is at the end, the 'last'
708 * pointer always points (invalidly) one past.
710 clistp
->c_cl
= (char *)(cbp
+ 1);
711 cblock_free(cblockp
);
712 if (--clistp
->c_cbcount
>= clistp
->c_cbreserved
)
718 * If there are no more characters on the list, then
719 * free the last cblock. It should not be possible for c->cl
720 * to be pointing past the end of a block due to our decrement
723 if (clistp
->c_cc
== 0 && clistp
->c_cl
) {
724 KKASSERT(((intptr_t)clistp
->c_cl
& CROUND
) != 0);
725 cblockp
= (struct cblock
*)((intptr_t)clistp
->c_cl
& ~CROUND
);
726 cblock_free(cblockp
);
727 if (--clistp
->c_cbcount
>= clistp
->c_cbreserved
)
729 clistp
->c_cf
= clistp
->c_cl
= NULL
;
732 lwkt_reltoken(&tty_token
);
738 * Move characters in source clist to destination clist,
739 * preserving quote bits.
742 catq(struct clist
*src_clistp
, struct clist
*dest_clistp
)
746 lwkt_gettoken(&tty_token
);
749 * If the destination clist is empty (has no cblocks atttached),
750 * and there are no possible complications with the resource counters,
751 * then we simply assign the current clist to the destination.
753 if (!dest_clistp
->c_cf
754 && src_clistp
->c_cbcount
<= src_clistp
->c_cbmax
755 && src_clistp
->c_cbcount
<= dest_clistp
->c_cbmax
) {
756 dest_clistp
->c_cf
= src_clistp
->c_cf
;
757 dest_clistp
->c_cl
= src_clistp
->c_cl
;
758 src_clistp
->c_cf
= src_clistp
->c_cl
= NULL
;
760 dest_clistp
->c_cc
= src_clistp
->c_cc
;
761 src_clistp
->c_cc
= 0;
762 dest_clistp
->c_cbcount
= src_clistp
->c_cbcount
;
763 src_clistp
->c_cbcount
= 0;
766 lwkt_reltoken(&tty_token
);
772 * XXX This should probably be optimized to more than one
773 * character at a time.
775 while ((chr
= clist_getc(src_clistp
)) != -1)
776 clist_putc(chr
, dest_clistp
);
777 lwkt_reltoken(&tty_token
);