FreeBSD/Linux Kernel Cross Reference
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 }
Cache object: 982ebafb6d127aa6a56852f6fb24d0cf
|