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/10.3/sys/kern/subr_msgbuf.c 233135 2012-03-19 00:36:32Z eadler $
   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/kernel.h>
   36 #include <sys/mutex.h>
   37 #include <sys/msgbuf.h>
   38 #include <sys/sysctl.h>
   39 
   40 /*
   41  * Maximum number conversion buffer length: uintmax_t in base 2, plus <>
   42  * around the priority, and a terminating NUL.
   43  */
   44 #define MAXPRIBUF       (sizeof(intmax_t) * NBBY + 3)
   45 
   46 /* Read/write sequence numbers are modulo a multiple of the buffer size. */
   47 #define SEQMOD(size) ((size) * 16)
   48 
   49 static u_int msgbuf_cksum(struct msgbuf *mbp);
   50 
   51 /*
   52  * Timestamps in msgbuf are useful when trying to diagnose when core dumps
   53  * or other actions occured.
   54  */
   55 static int msgbuf_show_timestamp = 0;
   56 SYSCTL_INT(_kern, OID_AUTO, msgbuf_show_timestamp, CTLFLAG_RW | CTLFLAG_TUN,
   57     &msgbuf_show_timestamp, 0, "Show timestamp in msgbuf");
   58 TUNABLE_INT("kern.msgbuf_show_timestamp", &msgbuf_show_timestamp);
   59 
   60 /*
   61  * Initialize a message buffer of the specified size at the specified
   62  * location. This also zeros the buffer area.
   63  */
   64 void
   65 msgbuf_init(struct msgbuf *mbp, void *ptr, int size)
   66 {
   67 
   68         mbp->msg_ptr = ptr;
   69         mbp->msg_size = size;
   70         mbp->msg_seqmod = SEQMOD(size);
   71         msgbuf_clear(mbp);
   72         mbp->msg_magic = MSG_MAGIC;
   73         mbp->msg_lastpri = -1;
   74         mbp->msg_flags = 0;
   75         bzero(&mbp->msg_lock, sizeof(mbp->msg_lock));
   76         mtx_init(&mbp->msg_lock, "msgbuf", NULL, MTX_SPIN);
   77 }
   78 
   79 /*
   80  * Reinitialize a message buffer, retaining its previous contents if
   81  * the size and checksum are correct. If the old contents cannot be
   82  * recovered, the message buffer is cleared.
   83  */
   84 void
   85 msgbuf_reinit(struct msgbuf *mbp, void *ptr, int size)
   86 {
   87         u_int cksum;
   88 
   89         if (mbp->msg_magic != MSG_MAGIC || mbp->msg_size != size) {
   90                 msgbuf_init(mbp, ptr, size);
   91                 return;
   92         }
   93         mbp->msg_seqmod = SEQMOD(size);
   94         mbp->msg_wseq = MSGBUF_SEQNORM(mbp, mbp->msg_wseq);
   95         mbp->msg_rseq = MSGBUF_SEQNORM(mbp, mbp->msg_rseq);
   96         mbp->msg_ptr = ptr;
   97         cksum = msgbuf_cksum(mbp);
   98         if (cksum != mbp->msg_cksum) {
   99                 if (bootverbose) {
  100                         printf("msgbuf cksum mismatch (read %x, calc %x)\n",
  101                             mbp->msg_cksum, cksum);
  102                         printf("Old msgbuf not recovered\n");
  103                 }
  104                 msgbuf_clear(mbp);
  105         }
  106 
  107         mbp->msg_lastpri = -1;
  108         /* Assume that the old message buffer didn't end in a newline. */
  109         mbp->msg_flags |= MSGBUF_NEEDNL;
  110         bzero(&mbp->msg_lock, sizeof(mbp->msg_lock));
  111         mtx_init(&mbp->msg_lock, "msgbuf", NULL, MTX_SPIN);
  112 }
  113 
  114 /*
  115  * Clear the message buffer.
  116  */
  117 void
  118 msgbuf_clear(struct msgbuf *mbp)
  119 {
  120 
  121         bzero(mbp->msg_ptr, mbp->msg_size);
  122         mbp->msg_wseq = 0;
  123         mbp->msg_rseq = 0;
  124         mbp->msg_cksum = 0;
  125 }
  126 
  127 /*
  128  * Get a count of the number of unread characters in the message buffer.
  129  */
  130 int
  131 msgbuf_getcount(struct msgbuf *mbp)
  132 {
  133         u_int len;
  134 
  135         len = MSGBUF_SEQSUB(mbp, mbp->msg_wseq, mbp->msg_rseq);
  136         if (len > mbp->msg_size)
  137                 len = mbp->msg_size;
  138         return (len);
  139 }
  140 
  141 /*
  142  * Add a character into the message buffer, and update the checksum and
  143  * sequence number.
  144  *
  145  * The caller should hold the message buffer spinlock.
  146  */
  147 
  148 static void
  149 msgbuf_do_addchar(struct msgbuf * const mbp, u_int * const seq, const int c)
  150 {
  151         u_int pos;
  152 
  153         /* Make sure we properly wrap the sequence number. */
  154         pos = MSGBUF_SEQ_TO_POS(mbp, *seq);
  155         mbp->msg_cksum += (u_int)(u_char)c -
  156             (u_int)(u_char)mbp->msg_ptr[pos];
  157         mbp->msg_ptr[pos] = c;
  158         *seq = MSGBUF_SEQNORM(mbp, *seq + 1);
  159 }
  160 
  161 /*
  162  * Append a character to a message buffer.
  163  */
  164 void
  165 msgbuf_addchar(struct msgbuf *mbp, int c)
  166 {
  167         mtx_lock_spin(&mbp->msg_lock);
  168 
  169         msgbuf_do_addchar(mbp, &mbp->msg_wseq, c);
  170 
  171         mtx_unlock_spin(&mbp->msg_lock);
  172 }
  173 
  174 /*
  175  * Append a NUL-terminated string with a priority to a message buffer.
  176  * Filter carriage returns if the caller requests it.
  177  *
  178  * XXX The carriage return filtering behavior is present in the
  179  * msglogchar() API, however testing has shown that we don't seem to send
  180  * carriage returns down this path.  So do we still need it?
  181  */
  182 void
  183 msgbuf_addstr(struct msgbuf *mbp, int pri, char *str, int filter_cr)
  184 {
  185         u_int seq;
  186         size_t len, prefix_len;
  187         char prefix[MAXPRIBUF];
  188         char buf[32];
  189         int nl, i, j, needtime;
  190 
  191         len = strlen(str);
  192         prefix_len = 0;
  193         nl = 0;
  194 
  195         /* If we have a zero-length string, no need to do anything. */
  196         if (len == 0)
  197                 return;
  198 
  199         mtx_lock_spin(&mbp->msg_lock);
  200 
  201         /*
  202          * If this is true, we may need to insert a new priority sequence,
  203          * so prepare the prefix.
  204          */
  205         if (pri != -1)
  206                 prefix_len = sprintf(prefix, "<%d>", pri);
  207 
  208         /*
  209          * Starting write sequence number.
  210          */
  211         seq = mbp->msg_wseq;
  212 
  213         /*
  214          * Whenever there is a change in priority, we have to insert a
  215          * newline, and a priority prefix if the priority is not -1.  Here
  216          * we detect whether there was a priority change, and whether we
  217          * did not end with a newline.  If that is the case, we need to
  218          * insert a newline before this string.
  219          */
  220         if (mbp->msg_lastpri != pri && (mbp->msg_flags & MSGBUF_NEEDNL) != 0) {
  221 
  222                 msgbuf_do_addchar(mbp, &seq, '\n');
  223                 mbp->msg_flags &= ~MSGBUF_NEEDNL;
  224         }
  225 
  226         needtime = 1;
  227         for (i = 0; i < len; i++) {
  228                 /*
  229                  * If we just had a newline, and the priority is not -1
  230                  * (and therefore prefix_len != 0), then we need a priority
  231                  * prefix for this line.
  232                  */
  233                 if ((mbp->msg_flags & MSGBUF_NEEDNL) == 0 && prefix_len != 0) {
  234                         int j;
  235 
  236                         for (j = 0; j < prefix_len; j++)
  237                                 msgbuf_do_addchar(mbp, &seq, prefix[j]);
  238                 }
  239 
  240                 if (msgbuf_show_timestamp && needtime == 1 &&
  241                     (mbp->msg_flags & MSGBUF_NEEDNL) == 0) {
  242 
  243                         snprintf(buf, sizeof(buf), "[%jd] ",
  244                             (intmax_t)time_uptime);
  245                         for (j = 0; buf[j] != '\0'; j++)
  246                                 msgbuf_do_addchar(mbp, &seq, buf[j]);
  247                         needtime = 0;
  248                 }
  249 
  250                 /*
  251                  * Don't copy carriage returns if the caller requested
  252                  * filtering.
  253                  * 
  254                  * XXX This matches the behavior of msglogchar(), but is it
  255                  * necessary?  Testing has shown that we don't seem to get
  256                  * carriage returns here.
  257                  */
  258                 if ((filter_cr != 0) && (str[i] == '\r'))
  259                         continue;
  260 
  261                 /*
  262                  * Clear this flag if we see a newline.  This affects whether
  263                  * we need to insert a new prefix or insert a newline later.
  264                  */
  265                 if (str[i] == '\n')
  266                         mbp->msg_flags &= ~MSGBUF_NEEDNL;
  267                 else
  268                         mbp->msg_flags |= MSGBUF_NEEDNL;
  269 
  270                 msgbuf_do_addchar(mbp, &seq, str[i]);
  271         }
  272         /*
  273          * Update the write sequence number for the actual number of
  274          * characters we put in the message buffer.  (Depends on whether
  275          * carriage returns are filtered.)
  276          */
  277         mbp->msg_wseq = seq;
  278 
  279         /*
  280          * Set the last priority.
  281          */
  282         mbp->msg_lastpri = pri;
  283 
  284         mtx_unlock_spin(&mbp->msg_lock);
  285 
  286 }
  287 
  288 /*
  289  * Read and mark as read a character from a message buffer.
  290  * Returns the character, or -1 if no characters are available.
  291  */
  292 int
  293 msgbuf_getchar(struct msgbuf *mbp)
  294 {
  295         u_int len, wseq;
  296         int c;
  297 
  298         mtx_lock_spin(&mbp->msg_lock);
  299 
  300         wseq = mbp->msg_wseq;
  301         len = MSGBUF_SEQSUB(mbp, wseq, mbp->msg_rseq);
  302         if (len == 0) {
  303                 mtx_unlock_spin(&mbp->msg_lock);
  304                 return (-1);
  305         }
  306         if (len > mbp->msg_size)
  307                 mbp->msg_rseq = MSGBUF_SEQNORM(mbp, wseq - mbp->msg_size);
  308         c = (u_char)mbp->msg_ptr[MSGBUF_SEQ_TO_POS(mbp, mbp->msg_rseq)];
  309         mbp->msg_rseq = MSGBUF_SEQNORM(mbp, mbp->msg_rseq + 1);
  310 
  311         mtx_unlock_spin(&mbp->msg_lock);
  312 
  313         return (c);
  314 }
  315 
  316 /*
  317  * Read and mark as read a number of characters from a message buffer.
  318  * Returns the number of characters that were placed in `buf'.
  319  */
  320 int
  321 msgbuf_getbytes(struct msgbuf *mbp, char *buf, int buflen)
  322 {
  323         u_int len, pos, wseq;
  324 
  325         mtx_lock_spin(&mbp->msg_lock);
  326 
  327         wseq = mbp->msg_wseq;
  328         len = MSGBUF_SEQSUB(mbp, wseq, mbp->msg_rseq);
  329         if (len == 0) {
  330                 mtx_unlock_spin(&mbp->msg_lock);
  331                 return (0);
  332         }
  333         if (len > mbp->msg_size) {
  334                 mbp->msg_rseq = MSGBUF_SEQNORM(mbp, wseq - mbp->msg_size);
  335                 len = mbp->msg_size;
  336         }
  337         pos = MSGBUF_SEQ_TO_POS(mbp, mbp->msg_rseq);
  338         len = min(len, mbp->msg_size - pos);
  339         len = min(len, (u_int)buflen);
  340 
  341         bcopy(&mbp->msg_ptr[pos], buf, len);
  342         mbp->msg_rseq = MSGBUF_SEQNORM(mbp, mbp->msg_rseq + len);
  343 
  344         mtx_unlock_spin(&mbp->msg_lock);
  345 
  346         return (len);
  347 }
  348 
  349 /*
  350  * Peek at the full contents of a message buffer without marking any
  351  * data as read. `seqp' should point to an unsigned integer that
  352  * msgbuf_peekbytes() can use to retain state between calls so that
  353  * the whole message buffer can be read in multiple short reads.
  354  * To initialise this variable to the start of the message buffer,
  355  * call msgbuf_peekbytes() with a NULL `buf' parameter.
  356  *
  357  * Returns the number of characters that were placed in `buf'.
  358  */
  359 int
  360 msgbuf_peekbytes(struct msgbuf *mbp, char *buf, int buflen, u_int *seqp)
  361 {
  362         u_int len, pos, wseq;
  363 
  364         mtx_lock_spin(&mbp->msg_lock);
  365 
  366         if (buf == NULL) {
  367                 /* Just initialise *seqp. */
  368                 *seqp = MSGBUF_SEQNORM(mbp, mbp->msg_wseq - mbp->msg_size);
  369                 mtx_unlock_spin(&mbp->msg_lock);
  370                 return (0);
  371         }
  372 
  373         wseq = mbp->msg_wseq;
  374         len = MSGBUF_SEQSUB(mbp, wseq, *seqp);
  375         if (len == 0) {
  376                 mtx_unlock_spin(&mbp->msg_lock);
  377                 return (0);
  378         }
  379         if (len > mbp->msg_size) {
  380                 *seqp = MSGBUF_SEQNORM(mbp, wseq - mbp->msg_size);
  381                 len = mbp->msg_size;
  382         }
  383         pos = MSGBUF_SEQ_TO_POS(mbp, *seqp);
  384         len = min(len, mbp->msg_size - pos);
  385         len = min(len, (u_int)buflen);
  386         bcopy(&mbp->msg_ptr[MSGBUF_SEQ_TO_POS(mbp, *seqp)], buf, len);
  387         *seqp = MSGBUF_SEQNORM(mbp, *seqp + len);
  388 
  389         mtx_unlock_spin(&mbp->msg_lock);
  390 
  391         return (len);
  392 }
  393 
  394 /*
  395  * Compute the checksum for the complete message buffer contents.
  396  */
  397 static u_int
  398 msgbuf_cksum(struct msgbuf *mbp)
  399 {
  400         u_int i, sum;
  401 
  402         sum = 0;
  403         for (i = 0; i < mbp->msg_size; i++)
  404                 sum += (u_char)mbp->msg_ptr[i];
  405         return (sum);
  406 }
  407 
  408 /*
  409  * Copy from one message buffer to another.
  410  */
  411 void
  412 msgbuf_copy(struct msgbuf *src, struct msgbuf *dst)
  413 {
  414         int c;
  415 
  416         while ((c = msgbuf_getchar(src)) >= 0)
  417                 msgbuf_addchar(dst, c);
  418 }

Cache object: eef4ec99b6149897f78455f30450ee4d


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