kernel: Move semicolon from the definition of SYSINIT() to its invocations.
[dragonfly.git] / sys / kern / tty_subr.c
1 /*
2  * (MPSAFE)
3  *
4  * Copyright (c) 1994, David Greenman
5  * All rights reserved.
6  *
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.
16  *
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.
28  *
29  * $FreeBSD: src/sys/kern/tty_subr.c,v 1.32 1999/08/28 00:46:21 peter Exp $
30  */
31
32 /*
33  * MPSAFE NOTE: 
34  * Most functions here could use a separate lock to deal with concurrent
35  * access to the cblocks and cblock_*_list.
36  *
37  * Right now the tty_token must be held for all this.
38  */
39
40 /*
41  * clist support routines
42  *
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)
46  *                              
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.
49  *
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.
52  */
53
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>
61
62 static void clist_init (void *);
63 SYSINIT(clist, SI_SUB_CLIST, SI_ORDER_FIRST, clist_init, NULL);
64
65 static struct cblock *cfreelist = NULL;
66 int cfreecount = 0;
67 static int cslushcount;
68 static int ctotcount;
69
70 #ifndef INITIAL_CBLOCKS
71 #define INITIAL_CBLOCKS 50
72 #endif
73
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);
78
79 #include "opt_ddb.h"
80 #ifdef DDB
81 #include <ddb/ddb.h>
82
83 DB_SHOW_COMMAND(cbstat, cbstat)
84 {
85         int cbsize = CBSIZE;
86
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);
91 }
92 #endif /* DDB */
93
94 /*
95  * Called from init_main.c
96  */
97 /* ARGSUSED*/
98 static void
99 clist_init(void *dummy)
100 {
101         /*
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().
108          */
109         lwkt_gettoken(&tty_token);
110         cblock_alloc_cblocks(cslushcount = INITIAL_CBLOCKS);
111         lwkt_reltoken(&tty_token);
112         KKASSERT(sizeof(struct cblock) == CBLOCK);
113 }
114
115 /*
116  * Remove a cblock from the cfreelist queue and return a pointer
117  * to it.
118  *
119  * May not block.
120  *
121  * NOTE: Must be called with tty_token held
122  */
123 static struct cblock *
124 cblock_alloc(void)
125 {
126         struct cblock *cblockp;
127
128         ASSERT_LWKT_TOKEN_HELD(&tty_token);
129
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);
139 }
140
141 /*
142  * Add a cblock to the cfreelist queue.
143  *
144  * May not block, must be called in a critical section
145  *
146  * NOTE: Must be called with tty_token held
147  */
148 static void
149 cblock_free(struct cblock *cblockp)
150 {
151         ASSERT_LWKT_TOKEN_HELD(&tty_token);
152
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;
160 }
161
162 /*
163  * Allocate some cblocks for the cfreelist queue.
164  *
165  * This routine may block, but still must be called in a critical section
166  *
167  * NOTE: Must be called with tty_token held
168  */
169 static void
170 cblock_alloc_cblocks(int number)
171 {
172         int i;
173         struct cblock *cbp;
174
175         ASSERT_LWKT_TOKEN_HELD(&tty_token);
176
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);
183                 }
184                 KKASSERT(((intptr_t)cbp & CROUND) == 0);
185                 /*
186                  * Freed cblocks have zero quotes and garbage elsewhere.
187                  * Set the may-have-quote bit to force zeroing the quotes.
188                  */
189                 setbit(cbp->c_quote, CBQSIZE * NBBY - 1);
190                 cbp->c_head.ch_magic = CLIST_MAGIC_USED;
191                 cblock_free(cbp);
192         }
193         ctotcount += number;
194 }
195
196 /*
197  * Set the cblock allocation policy for a clist.
198  */
199 void
200 clist_alloc_cblocks(struct clist *clistp, int ccmax, int ccreserved)
201 {
202         int dcbr;
203
204         /*
205          * Allow for wasted space at the head.
206          */
207         if (ccmax != 0)
208                 ccmax += CBSIZE - 1;
209         if (ccreserved != 0)
210                 ccreserved += CBSIZE - 1;
211
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 */
225         }
226         KKASSERT(clistp->c_cbreserved >= 0);
227         lwkt_reltoken(&tty_token);
228         crit_exit();
229 }
230
231 /*
232  * Free some cblocks from the cfreelist queue back to the
233  * system malloc pool.
234  *
235  * Must be called from within a critical section.  May block.
236  */
237 static void
238 cblock_free_cblocks(int number)
239 {
240         int i;
241
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);
247 }
248
249 /*
250  * Free the cblocks reserved for a clist.
251  */
252 void
253 clist_free_cblocks(struct clist *clistp)
254 {
255         int cbreserved;
256
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();
267 }
268
269 /*
270  * Get a character from the head of a clist.
271  */
272 int
273 clist_getc(struct clist *clistp)
274 {
275         int chr = -1;
276         struct cblock *cblockp;
277
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;
284
285                 /*
286                  * If this char is quoted, set the flag.
287                  */
288                 if (isset(cblockp->c_quote, clistp->c_cf - (char *)cblockp->c_info))
289                         chr |= TTY_QUOTE;
290
291                 /*
292                  * Advance to next character.
293                  */
294                 clistp->c_cf++;
295                 clistp->c_cc--;
296                 /*
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.
302                  */
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;
310                         }
311                         cblock_free(cblockp);
312                         if (--clistp->c_cbcount >= clistp->c_cbreserved)
313                                 ++cslushcount;
314                 }
315         }
316         lwkt_reltoken(&tty_token);
317         crit_exit();
318         return (chr);
319 }
320
321 /*
322  * Copy 'amount' of chars, beginning at head of clist 'clistp' to
323  * destination linear buffer 'dest'. Return number of characters
324  * actually copied.
325  */
326 int
327 q_to_b(struct clist *clistp, char *dest, int amount)
328 {
329         struct cblock *cblockp;
330         struct cblock *cblockn;
331         char *dest_orig = dest;
332         int numc;
333
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;
347                 /*
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.
352                  */
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;
360                         }
361                         cblock_free(cblockp);
362                         if (--clistp->c_cbcount >= clistp->c_cbreserved)
363                                 ++cslushcount;
364                 }
365         }
366         lwkt_reltoken(&tty_token);
367         crit_exit();
368         return (dest - dest_orig);
369 }
370
371 /*
372  * Flush 'amount' of chars, beginning at head of clist 'clistp'.
373  */
374 void
375 ndflush(struct clist *clistp, int amount)
376 {
377         struct cblock *cblockp;
378         struct cblock *cblockn;
379         int numc;
380
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;
392                 /*
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.
397                  */
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;
405                         }
406                         cblock_free(cblockp);
407                         if (--clistp->c_cbcount >= clistp->c_cbreserved)
408                                 ++cslushcount;
409                 }
410         }
411         lwkt_reltoken(&tty_token);
412         crit_exit();
413 }
414
415 /*
416  * Add a character to the end of a clist. Return -1 is no
417  * more clists, or 0 for success.
418  */
419 int
420 clist_putc(int chr, struct clist *clistp)
421 {
422         struct cblock *cblockp;
423
424         crit_enter();
425         lwkt_gettoken(&tty_token);
426
427         /*
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.
431          */
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 */
437                 }
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);
446
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);
453                                 }
454                                 --cslushcount;
455                         }
456                         cblockp = cblock_alloc();
457                         clistp->c_cbcount++;
458                         prev->c_head.ch_next = cblockp;
459                         clistp->c_cl = cblockp->c_info;
460                 }
461         }
462
463         /*
464          * If this character is quoted, set the quote bit, if not, clear it.
465          */
466         if (chr & TTY_QUOTE) {
467                 setbit(cblockp->c_quote, clistp->c_cl - (char *)cblockp->c_info);
468                 /*
469                  * Use one of the spare quote bits to record that something
470                  * may be quoted.
471                  */
472                 setbit(cblockp->c_quote, CBQSIZE * NBBY - 1);
473         } else {
474                 clrbit(cblockp->c_quote, clistp->c_cl - (char *)cblockp->c_info);
475         }
476
477         *clistp->c_cl++ = chr;
478         clistp->c_cc++;
479
480         lwkt_reltoken(&tty_token);
481         crit_exit();
482         return (0);
483 }
484
485 /*
486  * Copy data from linear buffer to clist chain. Return the
487  * number of characters not copied.
488  */
489 int
490 b_to_q(char *src, int amount, struct clist *clistp)
491 {
492         struct cblock *cblockp;
493         char *firstbyte, *lastbyte;
494         u_char startmask, endmask;
495         int startbit, endbit, num_between, numc;
496
497         /*
498          * Avoid allocating an initial cblock and then not using it.
499          * c_cc == 0 must imply c_cbount == 0.
500          */
501         if (amount <= 0)
502                 return (amount);
503
504         crit_enter();
505         lwkt_gettoken(&tty_token);
506
507         /*
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.
511          */
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 */
518                 }
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 {
524                 /*
525                  * c_cl may legally point past the end of the block, which
526                  * falls through to the 'get another cblock' code below.
527                  */
528                 cblockp = (struct cblock *)((intptr_t)clistp->c_cl & ~CROUND);
529         }
530
531         while (amount) {
532                 /*
533                  * Get another cblock if needed.
534                  */
535                 if (((intptr_t)clistp->c_cl & CROUND) == 0) {
536                         struct cblock *prev = cblockp - 1;
537
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);
544                                 }
545                                 --cslushcount;
546                         }
547                         cblockp = cblock_alloc();
548                         clistp->c_cbcount++;
549                         prev->c_head.ch_next = cblockp;
550                         clistp->c_cl = cblockp->c_info;
551                 }
552
553                 /*
554                  * Copy a chunk of the linear buffer up to the end
555                  * of this cblock.
556                  */
557                 numc = min(amount, (char *)(cblockp + 1) - clistp->c_cl);
558                 bcopy(src, clistp->c_cl, numc);
559
560                 /*
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?
564                  */
565                 if (isset(cblockp->c_quote, CBQSIZE * NBBY - 1)) {
566                         startbit = clistp->c_cl - (char *)cblockp->c_info;
567                         endbit = startbit + numc - 1;
568
569                         firstbyte = (u_char *)cblockp->c_quote + (startbit / NBBY);
570                         lastbyte = (u_char *)cblockp->c_quote + (endbit / NBBY);
571
572                         /*
573                          * Calculate mask of bits to preserve in first and
574                          * last bytes.
575                          */
576                         startmask = NBBY - (startbit % NBBY);
577                         startmask = 0xff >> startmask;
578                         endmask = (endbit % NBBY);
579                         endmask = 0xff << (endmask + 1);
580
581                         if (firstbyte != lastbyte) {
582                                 *firstbyte &= startmask;
583                                 *lastbyte &= endmask;
584
585                                 num_between = lastbyte - firstbyte - 1;
586                                 if (num_between)
587                                         bzero(firstbyte + 1, num_between);
588                         } else {
589                                 *firstbyte &= (startmask | endmask);
590                         }
591                 }
592
593                 /*
594                  * ...and update pointer for the next chunk.
595                  */
596                 src += numc;
597                 clistp->c_cl += numc;
598                 clistp->c_cc += numc;
599                 amount -= numc;
600                 /*
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.
606                  */
607                 ++cblockp;
608         }
609         lwkt_reltoken(&tty_token);
610         crit_exit();
611         return (amount);
612 }
613
614 /*
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.
618  *
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.
621  */
622 char *
623 nextc(struct clist *clistp, char *cp, int *dst)
624 {
625         struct cblock *cblockp;
626
627         ++cp;
628         /*
629          * See if the next character is beyond the end of
630          * the clist.
631          */
632         lwkt_gettoken(&tty_token);
633         if (clistp->c_cc && (cp != clistp->c_cl)) {
634                 /*
635                  * If the next character is beyond the end of this
636                  * cblock, advance to the next cblock.
637                  */
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);
641
642                 /*
643                  * Get the character. Set the quote flag if this character
644                  * is quoted.
645                  */
646                 *dst = (u_char)*cp | (isset(cblockp->c_quote, cp - (char *)cblockp->c_info) ? TTY_QUOTE : 0);
647
648                 lwkt_reltoken(&tty_token);
649                 return (cp);
650         }
651
652         lwkt_reltoken(&tty_token);
653         return (NULL);
654 }
655
656 /*
657  * "Unput" a character from a clist.
658  */
659 int
660 clist_unputc(struct clist *clistp)
661 {
662         struct cblock *cblockp = NULL, *cbp = NULL;
663         int chr = -1;
664
665         crit_enter();
666         lwkt_gettoken(&tty_token);
667
668         if (clistp->c_cc) {
669                 /*
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.
674                  */
675                 --clistp->c_cc;
676                 --clistp->c_cl;
677
678                 chr = (u_char)*clistp->c_cl;
679
680                 cblockp = (struct cblock *)((intptr_t)clistp->c_cl & ~CROUND);
681
682                 /*
683                  * Set quote flag if this character was quoted.
684                  */
685                 if (isset(cblockp->c_quote, (u_char *)clistp->c_cl - cblockp->c_info))
686                         chr |= TTY_QUOTE;
687
688                 /*
689                  * If all of the characters have been unput in this
690                  * cblock, then find the previous one and free this
691                  * one.
692                  *
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.
697                  */
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);
701
702                         while (cbp->c_head.ch_next != cblockp)
703                                 cbp = cbp->c_head.ch_next;
704                         cbp->c_head.ch_next = NULL;
705
706                         /*
707                          * When the previous cblock is at the end, the 'last'
708                          * pointer always points (invalidly) one past.
709                          */
710                         clistp->c_cl = (char *)(cbp + 1);
711                         cblock_free(cblockp);
712                         if (--clistp->c_cbcount >= clistp->c_cbreserved)
713                                 ++cslushcount;
714                 }
715         }
716
717         /*
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.
722          */
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;
730         }
731
732         lwkt_reltoken(&tty_token);
733         crit_exit();
734         return (chr);
735 }
736
737 /*
738  * Move characters in source clist to destination clist,
739  * preserving quote bits.
740  */
741 void
742 catq(struct clist *src_clistp, struct clist *dest_clistp)
743 {
744         int chr;
745
746         lwkt_gettoken(&tty_token);
747         crit_enter();
748         /*
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.
752          */
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;
759
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;
764
765                 crit_exit();
766                 lwkt_reltoken(&tty_token);
767                 return;
768         }
769         crit_exit();
770
771         /*
772          * XXX  This should probably be optimized to more than one
773          * character at a time.
774          */
775         while ((chr = clist_getc(src_clistp)) != -1)
776                 clist_putc(chr, dest_clistp);
777         lwkt_reltoken(&tty_token);
778 }