kernel - Revert part of the contig allocation work
[dragonfly.git] / sys / kern / tty_subr.c
blobbefd32d07c0dc91649952ec7be8ee7194c1d2901
1 /*
2 * (MPSAFE)
4 * Copyright (c) 1994, David Greenman
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice unmodified, this list of conditions, and the following
12 * disclaimer.
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
27 * SUCH DAMAGE.
29 * $FreeBSD: src/sys/kern/tty_subr.c,v 1.32 1999/08/28 00:46:21 peter Exp $
33 * MPSAFE NOTE:
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>
58 #include <sys/tty.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;
66 int cfreecount = 0;
67 static int cslushcount;
68 static int ctotcount;
70 #ifndef INITIAL_CBLOCKS
71 #define INITIAL_CBLOCKS 50
72 #endif
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);
79 #include "opt_ddb.h"
80 #ifdef DDB
81 #include <ddb/ddb.h>
83 DB_SHOW_COMMAND(cbstat, cbstat)
85 int cbsize = CBSIZE;
87 kprintf(
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);
92 #endif /* DDB */
95 * Called from init_main.c
97 /* ARGSUSED*/
98 static void
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
117 * to it.
119 * May not block.
121 * NOTE: Must be called with tty_token held
123 static struct cblock *
124 cblock_alloc(void)
126 struct cblock *cblockp;
128 ASSERT_LWKT_TOKEN_HELD(&tty_token);
130 cblockp = cfreelist;
131 if (cblockp == NULL)
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;
138 return (cblockp);
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
148 static void
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;
158 cfreelist = cblockp;
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
169 static void
170 cblock_alloc_cblocks(int number)
172 int i;
173 struct cblock *cbp;
175 ASSERT_LWKT_TOKEN_HELD(&tty_token);
177 for (i = 0; i < number; ++i) {
178 cbp = kmalloc(sizeof *cbp, M_TTYS, M_NOWAIT);
179 if (cbp == NULL) {
180 kprintf(
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;
191 cblock_free(cbp);
193 ctotcount += number;
197 * Set the cblock allocation policy for a clist.
199 void
200 clist_alloc_cblocks(struct clist *clistp, int ccmax, int ccreserved)
202 int dcbr;
205 * Allow for wasted space at the head.
207 if (ccmax != 0)
208 ccmax += CBSIZE - 1;
209 if (ccreserved != 0)
210 ccreserved += CBSIZE - 1;
212 crit_enter();
213 lwkt_gettoken(&tty_token);
214 clistp->c_cbmax = roundup(ccmax, CBSIZE) / CBSIZE;
215 dcbr = roundup(ccreserved, CBSIZE) / CBSIZE - clistp->c_cbreserved;
216 if (dcbr >= 0) {
217 clistp->c_cbreserved += dcbr; /* atomic w/c_cbmax */
218 cblock_alloc_cblocks(dcbr); /* may block */
219 } else {
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);
228 crit_exit();
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.
237 static void
238 cblock_free_cblocks(int number)
240 int i;
242 lwkt_gettoken(&tty_token);
243 for (i = 0; i < number; ++i)
244 kfree(cblock_alloc(), M_TTYS);
245 ctotcount -= number;
246 lwkt_reltoken(&tty_token);
250 * Free the cblocks reserved for a clist.
252 void
253 clist_free_cblocks(struct clist *clistp)
255 int cbreserved;
257 crit_enter();
258 lwkt_gettoken(&tty_token);
259 if (clistp->c_cbcount != 0)
260 panic("freeing active clist cblocks");
261 cbreserved = clistp->c_cbreserved;
262 clistp->c_cbmax = 0;
263 clistp->c_cbreserved = 0;
264 cblock_free_cblocks(cbreserved); /* may block */
265 lwkt_reltoken(&tty_token);
266 crit_exit();
270 * Get a character from the head of a clist.
273 clist_getc(struct clist *clistp)
275 int chr = -1;
276 struct cblock *cblockp;
278 crit_enter();
279 lwkt_gettoken(&tty_token);
280 if (clistp->c_cc) {
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))
289 chr |= TTY_QUOTE;
292 * Advance to next character.
294 clistp->c_cf++;
295 clistp->c_cc--;
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
301 * current cblock.
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;
308 } else {
309 clistp->c_cf = clistp->c_cl = NULL;
311 cblock_free(cblockp);
312 if (--clistp->c_cbcount >= clistp->c_cbreserved)
313 ++cslushcount;
316 lwkt_reltoken(&tty_token);
317 crit_exit();
318 return (chr);
322 * Copy 'amount' of chars, beginning at head of clist 'clistp' to
323 * destination linear buffer 'dest'. Return number of characters
324 * actually copied.
327 q_to_b(struct clist *clistp, char *dest, int amount)
329 struct cblock *cblockp;
330 struct cblock *cblockn;
331 char *dest_orig = dest;
332 int numc;
334 crit_enter();
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);
343 amount -= numc;
344 clistp->c_cf += numc;
345 clistp->c_cc -= numc;
346 dest += 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
351 * current cblock.
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;
358 } else {
359 clistp->c_cf = clistp->c_cl = NULL;
361 cblock_free(cblockp);
362 if (--clistp->c_cbcount >= clistp->c_cbreserved)
363 ++cslushcount;
366 lwkt_reltoken(&tty_token);
367 crit_exit();
368 return (dest - dest_orig);
372 * Flush 'amount' of chars, beginning at head of clist 'clistp'.
374 void
375 ndflush(struct clist *clistp, int amount)
377 struct cblock *cblockp;
378 struct cblock *cblockn;
379 int numc;
381 crit_enter();
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);
389 amount -= numc;
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
396 * current cblock.
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;
403 } else {
404 clistp->c_cf = clistp->c_cl = NULL;
406 cblock_free(cblockp);
407 if (--clistp->c_cbcount >= clistp->c_cbreserved)
408 ++cslushcount;
411 lwkt_reltoken(&tty_token);
412 crit_exit();
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;
424 crit_enter();
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);
435 crit_exit();
436 return (-1); /* nothing done */
438 cblockp = cblock_alloc();
439 clistp->c_cbcount = 1;
440 clistp->c_cf = clistp->c_cl = cblockp->c_info;
441 clistp->c_cc = 0;
442 } else {
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);
451 crit_exit();
452 return (-1);
454 --cslushcount;
456 cblockp = cblock_alloc();
457 clistp->c_cbcount++;
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
470 * may be quoted.
472 setbit(cblockp->c_quote, CBQSIZE * NBBY - 1);
473 } else {
474 clrbit(cblockp->c_quote, clistp->c_cl - (char *)cblockp->c_info);
477 *clistp->c_cl++ = chr;
478 clistp->c_cc++;
480 lwkt_reltoken(&tty_token);
481 crit_exit();
482 return (0);
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.
501 if (amount <= 0)
502 return (amount);
504 crit_enter();
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);
515 crit_exit();
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;
522 clistp->c_cc = 0;
523 } else {
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);
531 while (amount) {
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);
542 crit_exit();
543 return (amount);
545 --cslushcount;
547 cblockp = cblock_alloc();
548 clistp->c_cbcount++;
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
555 * of this cblock.
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
574 * last bytes.
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;
586 if (num_between)
587 bzero(firstbyte + 1, num_between);
588 } else {
589 *firstbyte &= (startmask | endmask);
594 * ...and update pointer for the next chunk.
596 src += numc;
597 clistp->c_cl += numc;
598 clistp->c_cc += numc;
599 amount -= 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'
605 * above.
607 ++cblockp;
609 lwkt_reltoken(&tty_token);
610 crit_exit();
611 return (amount);
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.
622 char *
623 nextc(struct clist *clistp, char *cp, int *dst)
625 struct cblock *cblockp;
627 ++cp;
629 * See if the next character is beyond the end of
630 * the clist.
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
644 * is quoted.
646 *dst = (u_char)*cp | (isset(cblockp->c_quote, cp - (char *)cblockp->c_info) ? TTY_QUOTE : 0);
648 lwkt_reltoken(&tty_token);
649 return (cp);
652 lwkt_reltoken(&tty_token);
653 return (NULL);
657 * "Unput" a character from a clist.
660 clist_unputc(struct clist *clistp)
662 struct cblock *cblockp = NULL, *cbp = NULL;
663 int chr = -1;
665 crit_enter();
666 lwkt_gettoken(&tty_token);
668 if (clistp->c_cc) {
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.
675 --clistp->c_cc;
676 --clistp->c_cl;
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))
686 chr |= TTY_QUOTE;
689 * If all of the characters have been unput in this
690 * cblock, then find the previous one and free this
691 * one.
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)
713 ++cslushcount;
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
721 * of it way above.
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)
728 ++cslushcount;
729 clistp->c_cf = clistp->c_cl = NULL;
732 lwkt_reltoken(&tty_token);
733 crit_exit();
734 return (chr);
738 * Move characters in source clist to destination clist,
739 * preserving quote bits.
741 void
742 catq(struct clist *src_clistp, struct clist *dest_clistp)
744 int chr;
746 lwkt_gettoken(&tty_token);
747 crit_enter();
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;
765 crit_exit();
766 lwkt_reltoken(&tty_token);
767 return;
769 crit_exit();
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);