The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/tty_subr.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.