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