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/subr_msgbuf.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  * Copyright (c) 2003 Ian Dowse.  All rights reserved.
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions
    6  * are met:
    7  * 1. Redistributions of source code must retain the above copyright
    8  *    notice, this list of conditions and the following disclaimer.
    9  * 2. Redistributions in binary form must reproduce the above copyright
   10  *    notice, this list of conditions and the following disclaimer in the
   11  *    documentation and/or other materials provided with the distribution.
   12  *
   13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   23  * SUCH DAMAGE.
   24  *
   25  * $FreeBSD: releng/9.0/sys/kern/subr_msgbuf.c 222550 2011-05-31 22:39:32Z ken $
   26  */
   27 
   28 /*
   29  * Generic message buffer support routines.
   30  */
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/lock.h>
   35 #include <sys/mutex.h>
   36 #include <sys/msgbuf.h>
   37 
   38 /*
   39  * Maximum number conversion buffer length: uintmax_t in base 2, plus <>
   40  * around the priority, and a terminating NUL.
   41  */
   42 #define MAXPRIBUF       (sizeof(intmax_t) * NBBY + 3)
   43 
   44 /* Read/write sequence numbers are modulo a multiple of the buffer size. */
   45 #define SEQMOD(size) ((size) * 16)
   46 
   47 static u_int msgbuf_cksum(struct msgbuf *mbp);
   48 
   49 /*
   50  * Initialize a message buffer of the specified size at the specified
   51  * location. This also zeros the buffer area.
   52  */
   53 void
   54 msgbuf_init(struct msgbuf *mbp, void *ptr, int size)
   55 {
   56 
   57         mbp->msg_ptr = ptr;
   58         mbp->msg_size = size;
   59         mbp->msg_seqmod = SEQMOD(size);
   60         msgbuf_clear(mbp);
   61         mbp->msg_magic = MSG_MAGIC;
   62         mbp->msg_lastpri = -1;
   63         mbp->msg_needsnl = 0;
   64         bzero(&mbp->msg_lock, sizeof(mbp->msg_lock));
   65         mtx_init(&mbp->msg_lock, "msgbuf", NULL, MTX_SPIN);
   66 }
   67 
   68 /*
   69  * Reinitialize a message buffer, retaining its previous contents if
   70  * the size and checksum are correct. If the old contents cannot be
   71  * recovered, the message buffer is cleared.
   72  */
   73 void
   74 msgbuf_reinit(struct msgbuf *mbp, void *ptr, int size)
   75 {
   76         u_int cksum;
   77 
   78         if (mbp->msg_magic != MSG_MAGIC || mbp->msg_size != size) {
   79                 msgbuf_init(mbp, ptr, size);
   80                 return;
   81         }
   82         mbp->msg_seqmod = SEQMOD(size);
   83         mbp->msg_wseq = MSGBUF_SEQNORM(mbp, mbp->msg_wseq);
   84         mbp->msg_rseq = MSGBUF_SEQNORM(mbp, mbp->msg_rseq);
   85         mbp->msg_ptr = ptr;
   86         cksum = msgbuf_cksum(mbp);
   87         if (cksum != mbp->msg_cksum) {
   88                 if (bootverbose) {
   89                         printf("msgbuf cksum mismatch (read %x, calc %x)\n",
   90                             mbp->msg_cksum, cksum);
   91                         printf("Old msgbuf not recovered\n");
   92                 }
   93                 msgbuf_clear(mbp);
   94         }
   95 
   96         mbp->msg_lastpri = -1;
   97         /* Assume that the old message buffer didn't end in a newline. */
   98         mbp->msg_needsnl = 1;
   99         bzero(&mbp->msg_lock, sizeof(mbp->msg_lock));
  100         mtx_init(&mbp->msg_lock, "msgbuf", NULL, MTX_SPIN);
  101 }
  102 
  103 /*
  104  * Clear the message buffer.
  105  */
  106 void
  107 msgbuf_clear(struct msgbuf *mbp)
  108 {
  109 
  110         bzero(mbp->msg_ptr, mbp->msg_size);
  111         mbp->msg_wseq = 0;
  112         mbp->msg_rseq = 0;
  113         mbp->msg_cksum = 0;
  114 }
  115 
  116 /*
  117  * Get a count of the number of unread characters in the message buffer.
  118  */
  119 int
  120 msgbuf_getcount(struct msgbuf *mbp)
  121 {
  122         u_int len;
  123 
  124         len = MSGBUF_SEQSUB(mbp, mbp->msg_wseq, mbp->msg_rseq);
  125         if (len > mbp->msg_size)
  126                 len = mbp->msg_size;
  127         return (len);
  128 }
  129 
  130 /*
  131  * Add a character into the message buffer, and update the checksum and
  132  * sequence number.
  133  *
  134  * The caller should hold the message buffer spinlock.
  135  */
  136 static inline void
  137 msgbuf_do_addchar(struct msgbuf *mbp, u_int *seq, int c)
  138 {
  139         u_int pos;
  140 
  141         /* Make sure we properly wrap the sequence number. */
  142         pos = MSGBUF_SEQ_TO_POS(mbp, *seq);
  143 
  144         mbp->msg_cksum += (u_int)c -
  145             (u_int)(u_char)mbp->msg_ptr[pos];
  146 
  147         mbp->msg_ptr[pos] = c;
  148 
  149         *seq = MSGBUF_SEQNORM(mbp, *seq + 1);
  150 }
  151 
  152 /*
  153  * Append a character to a message buffer.
  154  */
  155 void
  156 msgbuf_addchar(struct msgbuf *mbp, int c)
  157 {
  158         mtx_lock_spin(&mbp->msg_lock);
  159 
  160         msgbuf_do_addchar(mbp, &mbp->msg_wseq, c);
  161 
  162         mtx_unlock_spin(&mbp->msg_lock);
  163 }
  164 
  165 /*
  166  * Append a NUL-terminated string with a priority to a message buffer.
  167  * Filter carriage returns if the caller requests it.
  168  *
  169  * XXX The carriage return filtering behavior is present in the
  170  * msglogchar() API, however testing has shown that we don't seem to send
  171  * carriage returns down this path.  So do we still need it?
  172  */
  173 void
  174 msgbuf_addstr(struct msgbuf *mbp, int pri, char *str, int filter_cr)
  175 {
  176         u_int seq;
  177         size_t len, prefix_len;
  178         char prefix[MAXPRIBUF];
  179         int nl, i;
  180 
  181         len = strlen(str);
  182         prefix_len = 0;
  183         nl = 0;
  184 
  185         /* If we have a zero-length string, no need to do anything. */
  186         if (len == 0)
  187                 return;
  188 
  189         mtx_lock_spin(&mbp->msg_lock);
  190 
  191         /*
  192          * If this is true, we may need to insert a new priority sequence,
  193          * so prepare the prefix.
  194          */
  195         if (pri != -1)
  196                 prefix_len = sprintf(prefix, "<%d>", pri);
  197 
  198         /*
  199          * Starting write sequence number.
  200          */
  201         seq = mbp->msg_wseq;
  202 
  203         /*
  204          * Whenever there is a change in priority, we have to insert a
  205          * newline, and a priority prefix if the priority is not -1.  Here
  206          * we detect whether there was a priority change, and whether we
  207          * did not end with a newline.  If that is the case, we need to
  208          * insert a newline before this string.
  209          */
  210         if (mbp->msg_lastpri != pri && mbp->msg_needsnl != 0) {
  211 
  212                 msgbuf_do_addchar(mbp, &seq, '\n');
  213                 mbp->msg_needsnl = 0;
  214         }
  215 
  216         for (i = 0; i < len; i++) {
  217                 /*
  218                  * If we just had a newline, and the priority is not -1
  219                  * (and therefore prefix_len != 0), then we need a priority
  220                  * prefix for this line.
  221                  */
  222                 if (mbp->msg_needsnl == 0 && prefix_len != 0) {
  223                         int j;
  224 
  225                         for (j = 0; j < prefix_len; j++)
  226                                 msgbuf_do_addchar(mbp, &seq, prefix[j]);
  227                 }
  228 
  229                 /*
  230                  * Don't copy carriage returns if the caller requested
  231                  * filtering.
  232                  * 
  233                  * XXX This matches the behavior of msglogchar(), but is it
  234                  * necessary?  Testing has shown that we don't seem to get
  235                  * carriage returns here.
  236                  */
  237                 if ((filter_cr != 0) && (str[i] == '\r'))
  238                         continue;
  239 
  240                 /*
  241                  * Clear this flag if we see a newline.  This affects whether
  242                  * we need to insert a new prefix or insert a newline later.
  243                  */
  244                 if (str[i] == '\n')
  245                         mbp->msg_needsnl = 0;
  246                 else
  247                         mbp->msg_needsnl = 1;
  248 
  249                 msgbuf_do_addchar(mbp, &seq, str[i]);
  250         }
  251         /*
  252          * Update the write sequence number for the actual number of
  253          * characters we put in the message buffer.  (Depends on whether
  254          * carriage returns are filtered.)
  255          */
  256         mbp->msg_wseq = seq;
  257 
  258         /*
  259          * Set the last priority.
  260          */
  261         mbp->msg_lastpri = pri;
  262 
  263         mtx_unlock_spin(&mbp->msg_lock);
  264 
  265 }
  266 
  267 /*
  268  * Read and mark as read a character from a message buffer.
  269  * Returns the character, or -1 if no characters are available.
  270  */
  271 int
  272 msgbuf_getchar(struct msgbuf *mbp)
  273 {
  274         u_int len, wseq;
  275         int c;
  276 
  277         mtx_lock_spin(&mbp->msg_lock);
  278 
  279         wseq = mbp->msg_wseq;
  280         len = MSGBUF_SEQSUB(mbp, wseq, mbp->msg_rseq);
  281         if (len == 0) {
  282                 mtx_unlock_spin(&mbp->msg_lock);
  283                 return (-1);
  284         }
  285         if (len > mbp->msg_size)
  286                 mbp->msg_rseq = MSGBUF_SEQNORM(mbp, wseq - mbp->msg_size);
  287         c = (u_char)mbp->msg_ptr[MSGBUF_SEQ_TO_POS(mbp, mbp->msg_rseq)];
  288         mbp->msg_rseq = MSGBUF_SEQNORM(mbp, mbp->msg_rseq + 1);
  289 
  290         mtx_unlock_spin(&mbp->msg_lock);
  291 
  292         return (c);
  293 }
  294 
  295 /*
  296  * Read and mark as read a number of characters from a message buffer.
  297  * Returns the number of characters that were placed in `buf'.
  298  */
  299 int
  300 msgbuf_getbytes(struct msgbuf *mbp, char *buf, int buflen)
  301 {
  302         u_int len, pos, wseq;
  303 
  304         mtx_lock_spin(&mbp->msg_lock);
  305 
  306         wseq = mbp->msg_wseq;
  307         len = MSGBUF_SEQSUB(mbp, wseq, mbp->msg_rseq);
  308         if (len == 0) {
  309                 mtx_unlock_spin(&mbp->msg_lock);
  310                 return (0);
  311         }
  312         if (len > mbp->msg_size) {
  313                 mbp->msg_rseq = MSGBUF_SEQNORM(mbp, wseq - mbp->msg_size);
  314                 len = mbp->msg_size;
  315         }
  316         pos = MSGBUF_SEQ_TO_POS(mbp, mbp->msg_rseq);
  317         len = min(len, mbp->msg_size - pos);
  318         len = min(len, (u_int)buflen);
  319 
  320         bcopy(&mbp->msg_ptr[pos], buf, len);
  321         mbp->msg_rseq = MSGBUF_SEQNORM(mbp, mbp->msg_rseq + len);
  322 
  323         mtx_unlock_spin(&mbp->msg_lock);
  324 
  325         return (len);
  326 }
  327 
  328 /*
  329  * Peek at the full contents of a message buffer without marking any
  330  * data as read. `seqp' should point to an unsigned integer that
  331  * msgbuf_peekbytes() can use to retain state between calls so that
  332  * the whole message buffer can be read in multiple short reads.
  333  * To initialise this variable to the start of the message buffer,
  334  * call msgbuf_peekbytes() with a NULL `buf' parameter.
  335  *
  336  * Returns the number of characters that were placed in `buf'.
  337  */
  338 int
  339 msgbuf_peekbytes(struct msgbuf *mbp, char *buf, int buflen, u_int *seqp)
  340 {
  341         u_int len, pos, wseq;
  342 
  343         mtx_lock_spin(&mbp->msg_lock);
  344 
  345         if (buf == NULL) {
  346                 /* Just initialise *seqp. */
  347                 *seqp = MSGBUF_SEQNORM(mbp, mbp->msg_wseq - mbp->msg_size);
  348                 mtx_unlock_spin(&mbp->msg_lock);
  349                 return (0);
  350         }
  351 
  352         wseq = mbp->msg_wseq;
  353         len = MSGBUF_SEQSUB(mbp, wseq, *seqp);
  354         if (len == 0) {
  355                 mtx_unlock_spin(&mbp->msg_lock);
  356                 return (0);
  357         }
  358         if (len > mbp->msg_size) {
  359                 *seqp = MSGBUF_SEQNORM(mbp, wseq - mbp->msg_size);
  360                 len = mbp->msg_size;
  361         }
  362         pos = MSGBUF_SEQ_TO_POS(mbp, *seqp);
  363         len = min(len, mbp->msg_size - pos);
  364         len = min(len, (u_int)buflen);
  365         bcopy(&mbp->msg_ptr[MSGBUF_SEQ_TO_POS(mbp, *seqp)], buf, len);
  366         *seqp = MSGBUF_SEQNORM(mbp, *seqp + len);
  367 
  368         mtx_unlock_spin(&mbp->msg_lock);
  369 
  370         return (len);
  371 }
  372 
  373 /*
  374  * Compute the checksum for the complete message buffer contents.
  375  */
  376 static u_int
  377 msgbuf_cksum(struct msgbuf *mbp)
  378 {
  379         u_int i, sum;
  380 
  381         sum = 0;
  382         for (i = 0; i < mbp->msg_size; i++)
  383                 sum += (u_char)mbp->msg_ptr[i];
  384         return (sum);
  385 }
  386 
  387 /*
  388  * Copy from one message buffer to another.
  389  */
  390 void
  391 msgbuf_copy(struct msgbuf *src, struct msgbuf *dst)
  392 {
  393         int c;
  394 
  395         while ((c = msgbuf_getchar(src)) >= 0)
  396                 msgbuf_addchar(dst, c);
  397 }

Cache object: 64976dfe87b45412f6cdea449f580a2a


[ 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.