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$
   26  */
   27 
   28 /*
   29  * Generic message buffer support routines.
   30  */
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/msgbuf.h>
   35 
   36 /* Read/write sequence numbers are modulo a multiple of the buffer size. */
   37 #define SEQMOD(size) ((size) * 16)
   38 
   39 static u_int msgbuf_cksum(struct msgbuf *mbp);
   40 
   41 /*
   42  * Initialize a message buffer of the specified size at the specified
   43  * location. This also zeros the buffer area.
   44  */
   45 void
   46 msgbuf_init(struct msgbuf *mbp, void *ptr, int size)
   47 {
   48 
   49         mbp->msg_ptr = ptr;
   50         mbp->msg_size = size;
   51         mbp->msg_seqmod = SEQMOD(size);
   52         msgbuf_clear(mbp);
   53         mbp->msg_magic = MSG_MAGIC;
   54 }
   55 
   56 /*
   57  * Reinitialize a message buffer, retaining its previous contents if
   58  * the size and checksum are correct. If the old contents cannot be
   59  * recovered, the message buffer is cleared.
   60  */
   61 void
   62 msgbuf_reinit(struct msgbuf *mbp, void *ptr, int size)
   63 {
   64         u_int cksum;
   65 
   66         if (mbp->msg_magic != MSG_MAGIC || mbp->msg_size != size) {
   67                 msgbuf_init(mbp, ptr, size);
   68                 return;
   69         }
   70         mbp->msg_seqmod = SEQMOD(size);
   71         mbp->msg_wseq = MSGBUF_SEQNORM(mbp, mbp->msg_wseq);
   72         mbp->msg_rseq = MSGBUF_SEQNORM(mbp, mbp->msg_rseq);
   73         mbp->msg_ptr = ptr;
   74         cksum = msgbuf_cksum(mbp);
   75         if (cksum != mbp->msg_cksum) {
   76                 if (bootverbose) {
   77                         printf("msgbuf cksum mismatch (read %x, calc %x)\n",
   78                             mbp->msg_cksum, cksum);
   79                         printf("Old msgbuf not recovered\n");
   80                 }
   81                 msgbuf_clear(mbp);
   82         }
   83 }
   84 
   85 /*
   86  * Clear the message buffer.
   87  */
   88 void
   89 msgbuf_clear(struct msgbuf *mbp)
   90 {
   91 
   92         bzero(mbp->msg_ptr, mbp->msg_size);
   93         mbp->msg_wseq = 0;
   94         mbp->msg_rseq = 0;
   95         mbp->msg_cksum = 0;
   96 }
   97 
   98 /*
   99  * Get a count of the number of unread characters in the message buffer.
  100  */
  101 int
  102 msgbuf_getcount(struct msgbuf *mbp)
  103 {
  104         u_int len;
  105 
  106         len = MSGBUF_SEQSUB(mbp, mbp->msg_wseq, mbp->msg_rseq);
  107         if (len > mbp->msg_size)
  108                 len = mbp->msg_size;
  109         return (len);
  110 }
  111 
  112 /*
  113  * Append a character to a message buffer.  This function can be
  114  * considered fully reentrant so long as the number of concurrent
  115  * callers is less than the number of characters in the buffer.
  116  * However, the message buffer is only guaranteed to be consistent
  117  * for reading when there are no callers in this function.
  118  */
  119 void
  120 msgbuf_addchar(struct msgbuf *mbp, int c)
  121 {
  122         u_int new_seq, pos, seq;
  123 
  124         do {
  125                 seq = mbp->msg_wseq;
  126                 new_seq = MSGBUF_SEQNORM(mbp, seq + 1);
  127         } while (atomic_cmpset_rel_int(&mbp->msg_wseq, seq, new_seq) == 0);
  128         pos = MSGBUF_SEQ_TO_POS(mbp, seq);
  129         atomic_add_int(&mbp->msg_cksum, (u_int)(u_char)c -
  130             (u_int)(u_char)mbp->msg_ptr[pos]);
  131         mbp->msg_ptr[pos] = c;
  132 }
  133 
  134 /*
  135  * Read and mark as read a character from a message buffer.
  136  * Returns the character, or -1 if no characters are available.
  137  */
  138 int
  139 msgbuf_getchar(struct msgbuf *mbp)
  140 {
  141         u_int len, wseq;
  142         int c;
  143 
  144         wseq = mbp->msg_wseq;
  145         len = MSGBUF_SEQSUB(mbp, wseq, mbp->msg_rseq);
  146         if (len == 0)
  147                 return (-1);
  148         if (len > mbp->msg_size)
  149                 mbp->msg_rseq = MSGBUF_SEQNORM(mbp, wseq - mbp->msg_size);
  150         c = (u_char)mbp->msg_ptr[MSGBUF_SEQ_TO_POS(mbp, mbp->msg_rseq)];
  151         mbp->msg_rseq = MSGBUF_SEQNORM(mbp, mbp->msg_rseq + 1);
  152         return (c);
  153 }
  154 
  155 /*
  156  * Read and mark as read a number of characters from a message buffer.
  157  * Returns the number of characters that were placed in `buf'.
  158  */
  159 int
  160 msgbuf_getbytes(struct msgbuf *mbp, char *buf, int buflen)
  161 {
  162         u_int len, pos, wseq;
  163 
  164         wseq = mbp->msg_wseq;
  165         len = MSGBUF_SEQSUB(mbp, wseq, mbp->msg_rseq);
  166         if (len == 0)
  167                 return (0);
  168         if (len > mbp->msg_size) {
  169                 mbp->msg_rseq = MSGBUF_SEQNORM(mbp, wseq - mbp->msg_size);
  170                 len = mbp->msg_size;
  171         }
  172         pos = MSGBUF_SEQ_TO_POS(mbp, mbp->msg_rseq);
  173         len = min(len, mbp->msg_size - pos);
  174         len = min(len, (u_int)buflen);
  175 
  176         bcopy(&mbp->msg_ptr[pos], buf, len);
  177         mbp->msg_rseq = MSGBUF_SEQNORM(mbp, mbp->msg_rseq + len);
  178         return (len);
  179 }
  180 
  181 /*
  182  * Peek at the full contents of a message buffer without marking any
  183  * data as read. `seqp' should point to an unsigned integer that
  184  * msgbuf_peekbytes() can use to retain state between calls so that
  185  * the whole message buffer can be read in multiple short reads.
  186  * To initialise this variable to the start of the message buffer,
  187  * call msgbuf_peekbytes() with a NULL `buf' parameter.
  188  *
  189  * Returns the number of characters that were placed in `buf'.
  190  */
  191 int
  192 msgbuf_peekbytes(struct msgbuf *mbp, char *buf, int buflen, u_int *seqp)
  193 {
  194         u_int len, pos, wseq;
  195 
  196         if (buf == NULL) {
  197                 /* Just initialise *seqp. */
  198                 *seqp = MSGBUF_SEQNORM(mbp, mbp->msg_wseq - mbp->msg_size);
  199                 return (0);
  200         }
  201 
  202         wseq = mbp->msg_wseq;
  203         len = MSGBUF_SEQSUB(mbp, wseq, *seqp);
  204         if (len == 0)
  205                 return (0);
  206         if (len > mbp->msg_size) {
  207                 *seqp = MSGBUF_SEQNORM(mbp, wseq - mbp->msg_size);
  208                 len = mbp->msg_size;
  209         }
  210         pos = MSGBUF_SEQ_TO_POS(mbp, *seqp);
  211         len = min(len, mbp->msg_size - pos);
  212         len = min(len, (u_int)buflen);
  213         bcopy(&mbp->msg_ptr[MSGBUF_SEQ_TO_POS(mbp, *seqp)], buf, len);
  214         *seqp = MSGBUF_SEQNORM(mbp, *seqp + len);
  215         return (len);
  216 }
  217 
  218 /*
  219  * Compute the checksum for the complete message buffer contents.
  220  */
  221 static u_int
  222 msgbuf_cksum(struct msgbuf *mbp)
  223 {
  224         u_int i, sum;
  225 
  226         sum = 0;
  227         for (i = 0; i < mbp->msg_size; i++)
  228                 sum += (u_char)mbp->msg_ptr[i];
  229         return (sum);
  230 }
  231 
  232 /*
  233  * Copy from one message buffer to another.
  234  */
  235 void
  236 msgbuf_copy(struct msgbuf *src, struct msgbuf *dst)
  237 {
  238         int c;
  239 
  240         while ((c = msgbuf_getchar(src)) >= 0)
  241                 msgbuf_addchar(dst, c);
  242 }

Cache object: 7b2a641bc3a6a25d1714a463840cad12


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