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$
   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                 msgbuf_do_addchar(mbp, &seq, '\n');
  222                 mbp->msg_flags &= ~MSGBUF_NEEDNL;
  223         }
  224 
  225         needtime = 1;
  226         for (i = 0; i < len; i++) {
  227                 /*
  228                  * If we just had a newline, and the priority is not -1
  229                  * (and therefore prefix_len != 0), then we need a priority
  230                  * prefix for this line.
  231                  */
  232                 if ((mbp->msg_flags & MSGBUF_NEEDNL) == 0 && prefix_len != 0) {
  233                         int j;
  234 
  235                         for (j = 0; j < prefix_len; j++)
  236                                 msgbuf_do_addchar(mbp, &seq, prefix[j]);
  237                 }
  238 
  239                 if (msgbuf_show_timestamp && needtime == 1 &&
  240                     (mbp->msg_flags & MSGBUF_NEEDNL) == 0) {
  241                         snprintf(buf, sizeof(buf), "[%jd] ",
  242                             (intmax_t)time_uptime);
  243                         for (j = 0; buf[j] != '\0'; j++)
  244                                 msgbuf_do_addchar(mbp, &seq, buf[j]);
  245                         needtime = 0;
  246                 }
  247 
  248                 /*
  249                  * Don't copy carriage returns if the caller requested
  250                  * filtering.
  251                  * 
  252                  * XXX This matches the behavior of msglogchar(), but is it
  253                  * necessary?  Testing has shown that we don't seem to get
  254                  * carriage returns here.
  255                  */
  256                 if ((filter_cr != 0) && (str[i] == '\r'))
  257                         continue;
  258 
  259                 /*
  260                  * Clear this flag if we see a newline.  This affects whether
  261                  * we need to insert a new prefix or insert a newline later.
  262                  */
  263                 if (str[i] == '\n')
  264                         mbp->msg_flags &= ~MSGBUF_NEEDNL;
  265                 else
  266                         mbp->msg_flags |= MSGBUF_NEEDNL;
  267 
  268                 msgbuf_do_addchar(mbp, &seq, str[i]);
  269         }
  270         /*
  271          * Update the write sequence number for the actual number of
  272          * characters we put in the message buffer.  (Depends on whether
  273          * carriage returns are filtered.)
  274          */
  275         mbp->msg_wseq = seq;
  276 
  277         /*
  278          * Set the last priority.
  279          */
  280         mbp->msg_lastpri = pri;
  281 
  282         mtx_unlock_spin(&mbp->msg_lock);
  283 
  284 }
  285 
  286 /*
  287  * Read and mark as read a character from a message buffer.
  288  * Returns the character, or -1 if no characters are available.
  289  */
  290 int
  291 msgbuf_getchar(struct msgbuf *mbp)
  292 {
  293         u_int len, wseq;
  294         int c;
  295 
  296         mtx_lock_spin(&mbp->msg_lock);
  297 
  298         wseq = mbp->msg_wseq;
  299         len = MSGBUF_SEQSUB(mbp, wseq, mbp->msg_rseq);
  300         if (len == 0) {
  301                 mtx_unlock_spin(&mbp->msg_lock);
  302                 return (-1);
  303         }
  304         if (len > mbp->msg_size)
  305                 mbp->msg_rseq = MSGBUF_SEQNORM(mbp, wseq - mbp->msg_size);
  306         c = (u_char)mbp->msg_ptr[MSGBUF_SEQ_TO_POS(mbp, mbp->msg_rseq)];
  307         mbp->msg_rseq = MSGBUF_SEQNORM(mbp, mbp->msg_rseq + 1);
  308 
  309         mtx_unlock_spin(&mbp->msg_lock);
  310 
  311         return (c);
  312 }
  313 
  314 /*
  315  * Read and mark as read a number of characters from a message buffer.
  316  * Returns the number of characters that were placed in `buf'.
  317  */
  318 int
  319 msgbuf_getbytes(struct msgbuf *mbp, char *buf, int buflen)
  320 {
  321         u_int len, pos, wseq;
  322 
  323         mtx_lock_spin(&mbp->msg_lock);
  324 
  325         wseq = mbp->msg_wseq;
  326         len = MSGBUF_SEQSUB(mbp, wseq, mbp->msg_rseq);
  327         if (len == 0) {
  328                 mtx_unlock_spin(&mbp->msg_lock);
  329                 return (0);
  330         }
  331         if (len > mbp->msg_size) {
  332                 mbp->msg_rseq = MSGBUF_SEQNORM(mbp, wseq - mbp->msg_size);
  333                 len = mbp->msg_size;
  334         }
  335         pos = MSGBUF_SEQ_TO_POS(mbp, mbp->msg_rseq);
  336         len = min(len, mbp->msg_size - pos);
  337         len = min(len, (u_int)buflen);
  338 
  339         bcopy(&mbp->msg_ptr[pos], buf, len);
  340         mbp->msg_rseq = MSGBUF_SEQNORM(mbp, mbp->msg_rseq + len);
  341 
  342         mtx_unlock_spin(&mbp->msg_lock);
  343 
  344         return (len);
  345 }
  346 
  347 /*
  348  * Peek at the full contents of a message buffer without marking any
  349  * data as read. `seqp' should point to an unsigned integer that
  350  * msgbuf_peekbytes() can use to retain state between calls so that
  351  * the whole message buffer can be read in multiple short reads.
  352  * To initialise this variable to the start of the message buffer,
  353  * call msgbuf_peekbytes() with a NULL `buf' parameter.
  354  *
  355  * Returns the number of characters that were placed in `buf'.
  356  */
  357 int
  358 msgbuf_peekbytes(struct msgbuf *mbp, char *buf, int buflen, u_int *seqp)
  359 {
  360         u_int len, pos, wseq;
  361 
  362         mtx_lock_spin(&mbp->msg_lock);
  363 
  364         if (buf == NULL) {
  365                 /* Just initialise *seqp. */
  366                 *seqp = MSGBUF_SEQNORM(mbp, mbp->msg_wseq - mbp->msg_size);
  367                 mtx_unlock_spin(&mbp->msg_lock);
  368                 return (0);
  369         }
  370 
  371         wseq = mbp->msg_wseq;
  372         len = MSGBUF_SEQSUB(mbp, wseq, *seqp);
  373         if (len == 0) {
  374                 mtx_unlock_spin(&mbp->msg_lock);
  375                 return (0);
  376         }
  377         if (len > mbp->msg_size) {
  378                 *seqp = MSGBUF_SEQNORM(mbp, wseq - mbp->msg_size);
  379                 len = mbp->msg_size;
  380         }
  381         pos = MSGBUF_SEQ_TO_POS(mbp, *seqp);
  382         len = min(len, mbp->msg_size - pos);
  383         len = min(len, (u_int)buflen);
  384         bcopy(&mbp->msg_ptr[MSGBUF_SEQ_TO_POS(mbp, *seqp)], buf, len);
  385         *seqp = MSGBUF_SEQNORM(mbp, *seqp + len);
  386 
  387         mtx_unlock_spin(&mbp->msg_lock);
  388 
  389         return (len);
  390 }
  391 
  392 /*
  393  * Compute the checksum for the complete message buffer contents.
  394  */
  395 static u_int
  396 msgbuf_cksum(struct msgbuf *mbp)
  397 {
  398         u_int i, sum;
  399 
  400         sum = 0;
  401         for (i = 0; i < mbp->msg_size; i++)
  402                 sum += (u_char)mbp->msg_ptr[i];
  403         return (sum);
  404 }
  405 
  406 /*
  407  * Copy from one message buffer to another.
  408  */
  409 void
  410 msgbuf_copy(struct msgbuf *src, struct msgbuf *dst)
  411 {
  412         int c;
  413 
  414         while ((c = msgbuf_getchar(src)) >= 0)
  415                 msgbuf_addchar(dst, c);
  416 }
  417 
  418 /*
  419  * Get a snapshot of the message buffer, without modifying its internal state
  420  * (i.e. don't mark any new characters as read).
  421  */
  422 void
  423 msgbuf_duplicate(struct msgbuf *src, struct msgbuf *dst, char *dst_msgptr)
  424 {
  425 
  426         mtx_lock_spin(&src->msg_lock);
  427         bcopy(src, dst, sizeof(struct msgbuf));
  428         dst->msg_ptr = dst_msgptr;
  429         bcopy(src->msg_ptr, dst->msg_ptr, src->msg_size);
  430         mtx_unlock_spin(&src->msg_lock);
  431 }

Cache object: 961c79e6968b6bc968e44bdd2f5cd26b


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