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

Cache object: e1244d45ad9622e67a3a24b56996c54f


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