xref: /dragonfly/sys/kern/tty_subr.c (revision 0db87cb7)
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 }
779