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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2003 Ian Dowse.  All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  *
   27  * $FreeBSD: releng/12.0/sys/kern/subr_msgbuf.c 337544 2018-08-09 17:42:27Z kevans $
   28  */
   29 
   30 /*
   31  * Generic message buffer support routines.
   32  */
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/lock.h>
   37 #include <sys/kernel.h>
   38 #include <sys/mutex.h>
   39 #include <sys/msgbuf.h>
   40 #include <sys/sysctl.h>
   41 
   42 /*
   43  * Maximum number conversion buffer length: uintmax_t in base 2, plus <>
   44  * around the priority, and a terminating NUL.
   45  */
   46 #define MAXPRIBUF       (sizeof(intmax_t) * NBBY + 3)
   47 
   48 /* Read/write sequence numbers are modulo a multiple of the buffer size. */
   49 #define SEQMOD(size) ((size) * 16)
   50 
   51 static u_int msgbuf_cksum(struct msgbuf *mbp);
   52 
   53 /*
   54  * Timestamps in msgbuf are useful when trying to diagnose when core dumps
   55  * or other actions occurred.
   56  */
   57 static int msgbuf_show_timestamp = 0;
   58 SYSCTL_INT(_kern, OID_AUTO, msgbuf_show_timestamp, CTLFLAG_RWTUN,
   59     &msgbuf_show_timestamp, 0, "Show timestamp in msgbuf");
   60 
   61 /*
   62  * Initialize a message buffer of the specified size at the specified
   63  * location. This also zeros the buffer area.
   64  */
   65 void
   66 msgbuf_init(struct msgbuf *mbp, void *ptr, int size)
   67 {
   68 
   69         mbp->msg_ptr = ptr;
   70         mbp->msg_size = size;
   71         mbp->msg_seqmod = SEQMOD(size);
   72         msgbuf_clear(mbp);
   73         mbp->msg_magic = MSG_MAGIC;
   74         mbp->msg_lastpri = -1;
   75         mbp->msg_flags = 0;
   76         bzero(&mbp->msg_lock, sizeof(mbp->msg_lock));
   77         mtx_init(&mbp->msg_lock, "msgbuf", NULL, MTX_SPIN);
   78 }
   79 
   80 /*
   81  * Reinitialize a message buffer, retaining its previous contents if
   82  * the size and checksum are correct. If the old contents cannot be
   83  * recovered, the message buffer is cleared.
   84  */
   85 void
   86 msgbuf_reinit(struct msgbuf *mbp, void *ptr, int size)
   87 {
   88         u_int cksum;
   89 
   90         if (mbp->msg_magic != MSG_MAGIC || mbp->msg_size != size) {
   91                 msgbuf_init(mbp, ptr, size);
   92                 return;
   93         }
   94         mbp->msg_seqmod = SEQMOD(size);
   95         mbp->msg_wseq = MSGBUF_SEQNORM(mbp, mbp->msg_wseq);
   96         mbp->msg_rseq = MSGBUF_SEQNORM(mbp, mbp->msg_rseq);
   97         mbp->msg_ptr = ptr;
   98         cksum = msgbuf_cksum(mbp);
   99         if (cksum != mbp->msg_cksum) {
  100                 if (bootverbose) {
  101                         printf("msgbuf cksum mismatch (read %x, calc %x)\n",
  102                             mbp->msg_cksum, cksum);
  103                         printf("Old msgbuf not recovered\n");
  104                 }
  105                 msgbuf_clear(mbp);
  106         }
  107 
  108         mbp->msg_lastpri = -1;
  109         /* Assume that the old message buffer didn't end in a newline. */
  110         mbp->msg_flags |= MSGBUF_NEEDNL;
  111         bzero(&mbp->msg_lock, sizeof(mbp->msg_lock));
  112         mtx_init(&mbp->msg_lock, "msgbuf", NULL, MTX_SPIN);
  113 }
  114 
  115 /*
  116  * Clear the message buffer.
  117  */
  118 void
  119 msgbuf_clear(struct msgbuf *mbp)
  120 {
  121 
  122         bzero(mbp->msg_ptr, mbp->msg_size);
  123         mbp->msg_wseq = 0;
  124         mbp->msg_rseq = 0;
  125         mbp->msg_cksum = 0;
  126 }
  127 
  128 /*
  129  * Get a count of the number of unread characters in the message buffer.
  130  */
  131 int
  132 msgbuf_getcount(struct msgbuf *mbp)
  133 {
  134         u_int len;
  135 
  136         len = MSGBUF_SEQSUB(mbp, mbp->msg_wseq, mbp->msg_rseq);
  137         if (len > mbp->msg_size)
  138                 len = mbp->msg_size;
  139         return (len);
  140 }
  141 
  142 /*
  143  * Add a character into the message buffer, and update the checksum and
  144  * sequence number.
  145  *
  146  * The caller should hold the message buffer spinlock.
  147  */
  148 
  149 static void
  150 msgbuf_do_addchar(struct msgbuf * const mbp, u_int * const seq, const int c)
  151 {
  152         u_int pos;
  153 
  154         /* Make sure we properly wrap the sequence number. */
  155         pos = MSGBUF_SEQ_TO_POS(mbp, *seq);
  156         mbp->msg_cksum += (u_int)(u_char)c -
  157             (u_int)(u_char)mbp->msg_ptr[pos];
  158         mbp->msg_ptr[pos] = c;
  159         *seq = MSGBUF_SEQNORM(mbp, *seq + 1);
  160 }
  161 
  162 /*
  163  * Append a character to a message buffer.
  164  */
  165 void
  166 msgbuf_addchar(struct msgbuf *mbp, int c)
  167 {
  168         mtx_lock_spin(&mbp->msg_lock);
  169 
  170         msgbuf_do_addchar(mbp, &mbp->msg_wseq, c);
  171 
  172         mtx_unlock_spin(&mbp->msg_lock);
  173 }
  174 
  175 /*
  176  * Append a NUL-terminated string with a priority to a message buffer.
  177  * Filter carriage returns if the caller requests it.
  178  *
  179  * XXX The carriage return filtering behavior is present in the
  180  * msglogchar() API, however testing has shown that we don't seem to send
  181  * carriage returns down this path.  So do we still need it?
  182  */
  183 void
  184 msgbuf_addstr(struct msgbuf *mbp, int pri, const char *str, int filter_cr)
  185 {
  186         u_int seq;
  187         size_t len, prefix_len;
  188         char prefix[MAXPRIBUF];
  189         char buf[32];
  190         int i, j, needtime;
  191 
  192         len = strlen(str);
  193         prefix_len = 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: 5b0e8f976e14a804ecaf5daaeb3c8a5b


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