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/sysv_msg.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 /*      $NetBSD: sysv_msg.c,v 1.38 2005/02/26 21:34:55 perry Exp $      */
    2 
    3 /*-
    4  * Copyright (c) 1999 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
    9  * NASA Ames Research Center.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. All advertising materials mentioning features or use of this software
   20  *    must display the following acknowledgement:
   21  *      This product includes software developed by the NetBSD
   22  *      Foundation, Inc. and its contributors.
   23  * 4. Neither the name of The NetBSD Foundation nor the names of its
   24  *    contributors may be used to endorse or promote products derived
   25  *    from this software without specific prior written permission.
   26  *
   27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   37  * POSSIBILITY OF SUCH DAMAGE.
   38  */
   39 
   40 /*
   41  * Implementation of SVID messages
   42  *
   43  * Author: Daniel Boulet
   44  *
   45  * Copyright 1993 Daniel Boulet and RTMX Inc.
   46  *
   47  * This system call was implemented by Daniel Boulet under contract from RTMX.
   48  *
   49  * Redistribution and use in source forms, with and without modification,
   50  * are permitted provided that this entire comment appears intact.
   51  *
   52  * Redistribution in binary form may occur without any restrictions.
   53  * Obviously, it would be nice if you gave credit where credit is due
   54  * but requiring it would be too onerous.
   55  *
   56  * This software is provided ``AS IS'' without any warranties of any kind.
   57  */
   58 
   59 #include <sys/cdefs.h>
   60 __KERNEL_RCSID(0, "$NetBSD: sysv_msg.c,v 1.38 2005/02/26 21:34:55 perry Exp $");
   61 
   62 #define SYSVMSG
   63 
   64 #include <sys/param.h>
   65 #include <sys/kernel.h>
   66 #include <sys/msg.h>
   67 #include <sys/sysctl.h>
   68 #include <sys/mount.h>          /* XXX for <sys/syscallargs.h> */
   69 #include <sys/sa.h>
   70 #include <sys/syscallargs.h>
   71 
   72 #define MSG_DEBUG
   73 #undef MSG_DEBUG_OK
   74 
   75 #ifdef MSG_DEBUG_OK
   76 #define MSG_PRINTF(a)   printf a
   77 #else
   78 #define MSG_PRINTF(a)
   79 #endif
   80 
   81 static int      nfree_msgmaps;          /* # of free map entries */
   82 static short    free_msgmaps;   /* head of linked list of free map entries */
   83 static struct   __msg *free_msghdrs;    /* list of free msg headers */
   84 static char     *msgpool;               /* MSGMAX byte long msg buffer pool */
   85 static struct   msgmap *msgmaps;        /* MSGSEG msgmap structures */
   86 static struct __msg *msghdrs;           /* MSGTQL msg headers */
   87 struct  msqid_ds *msqids;               /* MSGMNI msqid_ds struct's */
   88 
   89 static void msg_freehdr(struct __msg *);
   90 
   91 void
   92 msginit()
   93 {
   94         int i, sz;
   95         vaddr_t v;
   96 
   97         /*
   98          * msginfo.msgssz should be a power of two for efficiency reasons.
   99          * It is also pretty silly if msginfo.msgssz is less than 8
  100          * or greater than about 256 so ...
  101          */
  102 
  103         i = 8;
  104         while (i < 1024 && i != msginfo.msgssz)
  105                 i <<= 1;
  106         if (i != msginfo.msgssz) {
  107                 MSG_PRINTF(("msginfo.msgssz=%d (0x%x)\n", msginfo.msgssz,
  108                     msginfo.msgssz));
  109                 panic("msginfo.msgssz not a small power of 2");
  110         }
  111 
  112         if (msginfo.msgseg > 32767) {
  113                 MSG_PRINTF(("msginfo.msgseg=%d\n", msginfo.msgseg));
  114                 panic("msginfo.msgseg > 32767");
  115         }
  116 
  117         /* Allocate pageable memory for our structures */
  118         sz = msginfo.msgmax
  119                 + msginfo.msgseg * sizeof(struct msgmap)
  120                 + msginfo.msgtql * sizeof(struct __msg)
  121                 + msginfo.msgmni * sizeof(struct msqid_ds);
  122         if ((v = uvm_km_zalloc(kernel_map, round_page(sz))) == 0)
  123                 panic("sysv_msg: cannot allocate memory");
  124         msgpool = (void *)v;
  125         msgmaps = (void *) (msgpool + msginfo.msgmax);
  126         msghdrs = (void *) (msgmaps + msginfo.msgseg);
  127         msqids = (void *) (msghdrs + msginfo.msgtql);
  128 
  129         for (i = 0; i < msginfo.msgseg; i++) {
  130                 if (i > 0)
  131                         msgmaps[i-1].next = i;
  132                 msgmaps[i].next = -1;   /* implies entry is available */
  133         }
  134         free_msgmaps = 0;
  135         nfree_msgmaps = msginfo.msgseg;
  136 
  137         if (msghdrs == NULL)
  138                 panic("msghdrs is NULL");
  139 
  140         for (i = 0; i < msginfo.msgtql; i++) {
  141                 msghdrs[i].msg_type = 0;
  142                 if (i > 0)
  143                         msghdrs[i-1].msg_next = &msghdrs[i];
  144                 msghdrs[i].msg_next = NULL;
  145         }
  146         free_msghdrs = &msghdrs[0];
  147 
  148         if (msqids == NULL)
  149                 panic("msqids is NULL");
  150 
  151         for (i = 0; i < msginfo.msgmni; i++) {
  152                 msqids[i].msg_qbytes = 0;       /* implies entry is available */
  153                 msqids[i].msg_perm._seq = 0;    /* reset to a known value */
  154         }
  155 }
  156 
  157 static void
  158 msg_freehdr(msghdr)
  159         struct __msg *msghdr;
  160 {
  161         while (msghdr->msg_ts > 0) {
  162                 short next;
  163                 if (msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg)
  164                         panic("msghdr->msg_spot out of range");
  165                 next = msgmaps[msghdr->msg_spot].next;
  166                 msgmaps[msghdr->msg_spot].next = free_msgmaps;
  167                 free_msgmaps = msghdr->msg_spot;
  168                 nfree_msgmaps++;
  169                 msghdr->msg_spot = next;
  170                 if (msghdr->msg_ts >= msginfo.msgssz)
  171                         msghdr->msg_ts -= msginfo.msgssz;
  172                 else
  173                         msghdr->msg_ts = 0;
  174         }
  175         if (msghdr->msg_spot != -1)
  176                 panic("msghdr->msg_spot != -1");
  177         msghdr->msg_next = free_msghdrs;
  178         free_msghdrs = msghdr;
  179 }
  180 
  181 int
  182 sys___msgctl13(l, v, retval)
  183         struct lwp *l;
  184         void *v;
  185         register_t *retval;
  186 {
  187         struct sys___msgctl13_args /* {
  188                 syscallarg(int) msqid;
  189                 syscallarg(int) cmd;
  190                 syscallarg(struct msqid_ds *) buf;
  191         } */ *uap = v;
  192         struct proc *p = l->l_proc;
  193         struct msqid_ds msqbuf;
  194         int cmd, error;
  195 
  196         cmd = SCARG(uap, cmd);
  197 
  198         if (cmd == IPC_SET) {
  199                 error = copyin(SCARG(uap, buf), &msqbuf, sizeof(msqbuf));
  200                 if (error)
  201                         return (error);
  202         }
  203 
  204         error = msgctl1(p, SCARG(uap, msqid), cmd,
  205             (cmd == IPC_SET || cmd == IPC_STAT) ? &msqbuf : NULL);
  206 
  207         if (error == 0 && cmd == IPC_STAT)
  208                 error = copyout(&msqbuf, SCARG(uap, buf), sizeof(msqbuf));
  209 
  210         return (error);
  211 }
  212 
  213 int
  214 msgctl1(p, msqid, cmd, msqbuf)
  215         struct proc *p;
  216         int msqid;
  217         int cmd;
  218         struct msqid_ds *msqbuf;
  219 {
  220         struct ucred *cred = p->p_ucred;
  221         struct msqid_ds *msqptr;
  222         int error = 0, ix;
  223 
  224         MSG_PRINTF(("call to msgctl1(%d, %d)\n", msqid, cmd));
  225 
  226         ix = IPCID_TO_IX(msqid);
  227 
  228         if (ix < 0 || ix >= msginfo.msgmni) {
  229                 MSG_PRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", ix,
  230                     msginfo.msgmni));
  231                 return (EINVAL);
  232         }
  233 
  234         msqptr = &msqids[ix];
  235 
  236         if (msqptr->msg_qbytes == 0) {
  237                 MSG_PRINTF(("no such msqid\n"));
  238                 return (EINVAL);
  239         }
  240         if (msqptr->msg_perm._seq != IPCID_TO_SEQ(msqid)) {
  241                 MSG_PRINTF(("wrong sequence number\n"));
  242                 return (EINVAL);
  243         }
  244 
  245         switch (cmd) {
  246         case IPC_RMID:
  247         {
  248                 struct __msg *msghdr;
  249                 if ((error = ipcperm(cred, &msqptr->msg_perm, IPC_M)) != 0)
  250                         return (error);
  251                 /* Free the message headers */
  252                 msghdr = msqptr->_msg_first;
  253                 while (msghdr != NULL) {
  254                         struct __msg *msghdr_tmp;
  255 
  256                         /* Free the segments of each message */
  257                         msqptr->_msg_cbytes -= msghdr->msg_ts;
  258                         msqptr->msg_qnum--;
  259                         msghdr_tmp = msghdr;
  260                         msghdr = msghdr->msg_next;
  261                         msg_freehdr(msghdr_tmp);
  262                 }
  263 
  264                 if (msqptr->_msg_cbytes != 0)
  265                         panic("msg_cbytes is screwed up");
  266                 if (msqptr->msg_qnum != 0)
  267                         panic("msg_qnum is screwed up");
  268 
  269                 msqptr->msg_qbytes = 0; /* Mark it as free */
  270 
  271                 wakeup(msqptr);
  272         }
  273                 break;
  274 
  275         case IPC_SET:
  276                 if ((error = ipcperm(cred, &msqptr->msg_perm, IPC_M)))
  277                         return (error);
  278                 if (msqbuf->msg_qbytes > msqptr->msg_qbytes && cred->cr_uid != 0)
  279                         return (EPERM);
  280                 if (msqbuf->msg_qbytes > msginfo.msgmnb) {
  281                         MSG_PRINTF(("can't increase msg_qbytes beyond %d "
  282                             "(truncating)\n", msginfo.msgmnb));
  283                         /* silently restrict qbytes to system limit */
  284                         msqbuf->msg_qbytes = msginfo.msgmnb;
  285                 }
  286                 if (msqbuf->msg_qbytes == 0) {
  287                         MSG_PRINTF(("can't reduce msg_qbytes to 0\n"));
  288                         return (EINVAL);        /* XXX non-standard errno! */
  289                 }
  290                 msqptr->msg_perm.uid = msqbuf->msg_perm.uid;
  291                 msqptr->msg_perm.gid = msqbuf->msg_perm.gid;
  292                 msqptr->msg_perm.mode = (msqptr->msg_perm.mode & ~0777) |
  293                     (msqbuf->msg_perm.mode & 0777);
  294                 msqptr->msg_qbytes = msqbuf->msg_qbytes;
  295                 msqptr->msg_ctime = time.tv_sec;
  296                 break;
  297 
  298         case IPC_STAT:
  299                 if ((error = ipcperm(cred, &msqptr->msg_perm, IPC_R))) {
  300                         MSG_PRINTF(("requester doesn't have read access\n"));
  301                         return (error);
  302                 }
  303                 memcpy(msqbuf, msqptr, sizeof(struct msqid_ds));
  304                 break;
  305 
  306         default:
  307                 MSG_PRINTF(("invalid command %d\n", cmd));
  308                 return (EINVAL);
  309         }
  310 
  311         return (error);
  312 }
  313 
  314 int
  315 sys_msgget(l, v, retval)
  316         struct lwp *l;
  317         void *v;
  318         register_t *retval;
  319 {
  320         struct sys_msgget_args /* {
  321                 syscallarg(key_t) key;
  322                 syscallarg(int) msgflg;
  323         } */ *uap = v;
  324         struct proc *p = l->l_proc;
  325         int msqid, error;
  326         int key = SCARG(uap, key);
  327         int msgflg = SCARG(uap, msgflg);
  328         struct ucred *cred = p->p_ucred;
  329         struct msqid_ds *msqptr = NULL;
  330 
  331         MSG_PRINTF(("msgget(0x%x, 0%o)\n", key, msgflg));
  332 
  333         if (key != IPC_PRIVATE) {
  334                 for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
  335                         msqptr = &msqids[msqid];
  336                         if (msqptr->msg_qbytes != 0 &&
  337                             msqptr->msg_perm._key == key)
  338                                 break;
  339                 }
  340                 if (msqid < msginfo.msgmni) {
  341                         MSG_PRINTF(("found public key\n"));
  342                         if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) {
  343                                 MSG_PRINTF(("not exclusive\n"));
  344                                 return(EEXIST);
  345                         }
  346                         if ((error = ipcperm(cred, &msqptr->msg_perm,
  347                             msgflg & 0700 ))) {
  348                                 MSG_PRINTF(("requester doesn't have 0%o access\n",
  349                                     msgflg & 0700));
  350                                 return (error);
  351                         }
  352                         goto found;
  353                 }
  354         }
  355 
  356         MSG_PRINTF(("need to allocate the msqid_ds\n"));
  357         if (key == IPC_PRIVATE || (msgflg & IPC_CREAT)) {
  358                 for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
  359                         /*
  360                          * Look for an unallocated and unlocked msqid_ds.
  361                          * msqid_ds's can be locked by msgsnd or msgrcv while
  362                          * they are copying the message in/out.  We can't
  363                          * re-use the entry until they release it.
  364                          */
  365                         msqptr = &msqids[msqid];
  366                         if (msqptr->msg_qbytes == 0 &&
  367                             (msqptr->msg_perm.mode & MSG_LOCKED) == 0)
  368                                 break;
  369                 }
  370                 if (msqid == msginfo.msgmni) {
  371                         MSG_PRINTF(("no more msqid_ds's available\n"));
  372                         return (ENOSPC);
  373                 }
  374                 MSG_PRINTF(("msqid %d is available\n", msqid));
  375                 msqptr->msg_perm._key = key;
  376                 msqptr->msg_perm.cuid = cred->cr_uid;
  377                 msqptr->msg_perm.uid = cred->cr_uid;
  378                 msqptr->msg_perm.cgid = cred->cr_gid;
  379                 msqptr->msg_perm.gid = cred->cr_gid;
  380                 msqptr->msg_perm.mode = (msgflg & 0777);
  381                 /* Make sure that the returned msqid is unique */
  382                 msqptr->msg_perm._seq++;
  383                 msqptr->_msg_first = NULL;
  384                 msqptr->_msg_last = NULL;
  385                 msqptr->_msg_cbytes = 0;
  386                 msqptr->msg_qnum = 0;
  387                 msqptr->msg_qbytes = msginfo.msgmnb;
  388                 msqptr->msg_lspid = 0;
  389                 msqptr->msg_lrpid = 0;
  390                 msqptr->msg_stime = 0;
  391                 msqptr->msg_rtime = 0;
  392                 msqptr->msg_ctime = time.tv_sec;
  393         } else {
  394                 MSG_PRINTF(("didn't find it and wasn't asked to create it\n"));
  395                 return (ENOENT);
  396         }
  397 
  398  found:
  399         /* Construct the unique msqid */
  400         *retval = IXSEQ_TO_IPCID(msqid, msqptr->msg_perm);
  401         return (0);
  402 }
  403 
  404 int
  405 sys_msgsnd(l, v, retval)
  406         struct lwp *l;
  407         void *v;
  408         register_t *retval;
  409 {
  410         struct sys_msgsnd_args /* {
  411                 syscallarg(int) msqid;
  412                 syscallarg(const void *) msgp;
  413                 syscallarg(size_t) msgsz;
  414                 syscallarg(int) msgflg;
  415         } */ *uap = v;
  416         struct proc *p = l->l_proc;
  417         int msqid = SCARG(uap, msqid);
  418         const char *user_msgp = SCARG(uap, msgp);
  419         size_t msgsz = SCARG(uap, msgsz);
  420         int msgflg = SCARG(uap, msgflg);
  421         int segs_needed, error;
  422         struct ucred *cred = p->p_ucred;
  423         struct msqid_ds *msqptr;
  424         struct __msg *msghdr;
  425         short next;
  426 
  427         MSG_PRINTF(("call to msgsnd(%d, %p, %lld, %d)\n", msqid, user_msgp,
  428             (long long)msgsz, msgflg));
  429 
  430         msqid = IPCID_TO_IX(msqid);
  431 
  432         if (msqid < 0 || msqid >= msginfo.msgmni) {
  433                 MSG_PRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
  434                     msginfo.msgmni));
  435                 return (EINVAL);
  436         }
  437 
  438         msqptr = &msqids[msqid];
  439         if (msqptr->msg_qbytes == 0) {
  440                 MSG_PRINTF(("no such message queue id\n"));
  441                 return (EINVAL);
  442         }
  443         if (msqptr->msg_perm._seq != IPCID_TO_SEQ(SCARG(uap, msqid))) {
  444                 MSG_PRINTF(("wrong sequence number\n"));
  445                 return (EINVAL);
  446         }
  447 
  448         if ((error = ipcperm(cred, &msqptr->msg_perm, IPC_W))) {
  449                 MSG_PRINTF(("requester doesn't have write access\n"));
  450                 return (error);
  451         }
  452 
  453         segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz;
  454         MSG_PRINTF(("msgsz=%lld, msgssz=%d, segs_needed=%d\n",
  455             (long long)msgsz, msginfo.msgssz, segs_needed));
  456         for (;;) {
  457                 int need_more_resources = 0;
  458 
  459                 /*
  460                  * check msgsz [cannot be negative since it is unsigned]
  461                  * (inside this loop in case msg_qbytes changes while we sleep)
  462                  */
  463 
  464                 if (msgsz > msqptr->msg_qbytes) {
  465                         MSG_PRINTF(("msgsz > msqptr->msg_qbytes\n"));
  466                         return (EINVAL);
  467                 }
  468 
  469                 if (msqptr->msg_perm.mode & MSG_LOCKED) {
  470                         MSG_PRINTF(("msqid is locked\n"));
  471                         need_more_resources = 1;
  472                 }
  473                 if (msgsz + msqptr->_msg_cbytes > msqptr->msg_qbytes) {
  474                         MSG_PRINTF(("msgsz + msg_cbytes > msg_qbytes\n"));
  475                         need_more_resources = 1;
  476                 }
  477                 if (segs_needed > nfree_msgmaps) {
  478                         MSG_PRINTF(("segs_needed > nfree_msgmaps\n"));
  479                         need_more_resources = 1;
  480                 }
  481                 if (free_msghdrs == NULL) {
  482                         MSG_PRINTF(("no more msghdrs\n"));
  483                         need_more_resources = 1;
  484                 }
  485 
  486                 if (need_more_resources) {
  487                         int we_own_it;
  488 
  489                         if ((msgflg & IPC_NOWAIT) != 0) {
  490                                 MSG_PRINTF(("need more resources but caller "
  491                                     "doesn't want to wait\n"));
  492                                 return (EAGAIN);
  493                         }
  494 
  495                         if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0) {
  496                                 MSG_PRINTF(("we don't own the msqid_ds\n"));
  497                                 we_own_it = 0;
  498                         } else {
  499                                 /* Force later arrivals to wait for our
  500                                    request */
  501                                 MSG_PRINTF(("we own the msqid_ds\n"));
  502                                 msqptr->msg_perm.mode |= MSG_LOCKED;
  503                                 we_own_it = 1;
  504                         }
  505                         MSG_PRINTF(("goodnight\n"));
  506                         error = tsleep(msqptr, (PZERO - 4) | PCATCH,
  507                             "msgwait", 0);
  508                         MSG_PRINTF(("good morning, error=%d\n", error));
  509                         if (we_own_it)
  510                                 msqptr->msg_perm.mode &= ~MSG_LOCKED;
  511                         if (error != 0) {
  512                                 MSG_PRINTF(("msgsnd: interrupted system "
  513                                     "call\n"));
  514                                 return (EINTR);
  515                         }
  516 
  517                         /*
  518                          * Make sure that the msq queue still exists
  519                          */
  520 
  521                         if (msqptr->msg_qbytes == 0) {
  522                                 MSG_PRINTF(("msqid deleted\n"));
  523                                 return (EIDRM);
  524                         }
  525                 } else {
  526                         MSG_PRINTF(("got all the resources that we need\n"));
  527                         break;
  528                 }
  529         }
  530 
  531         /*
  532          * We have the resources that we need.
  533          * Make sure!
  534          */
  535 
  536         if (msqptr->msg_perm.mode & MSG_LOCKED)
  537                 panic("msg_perm.mode & MSG_LOCKED");
  538         if (segs_needed > nfree_msgmaps)
  539                 panic("segs_needed > nfree_msgmaps");
  540         if (msgsz + msqptr->_msg_cbytes > msqptr->msg_qbytes)
  541                 panic("msgsz + msg_cbytes > msg_qbytes");
  542         if (free_msghdrs == NULL)
  543                 panic("no more msghdrs");
  544 
  545         /*
  546          * Re-lock the msqid_ds in case we page-fault when copying in the
  547          * message
  548          */
  549 
  550         if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0)
  551                 panic("msqid_ds is already locked");
  552         msqptr->msg_perm.mode |= MSG_LOCKED;
  553 
  554         /*
  555          * Allocate a message header
  556          */
  557 
  558         msghdr = free_msghdrs;
  559         free_msghdrs = msghdr->msg_next;
  560         msghdr->msg_spot = -1;
  561         msghdr->msg_ts = msgsz;
  562 
  563         /*
  564          * Allocate space for the message
  565          */
  566 
  567         while (segs_needed > 0) {
  568                 if (nfree_msgmaps <= 0)
  569                         panic("not enough msgmaps");
  570                 if (free_msgmaps == -1)
  571                         panic("nil free_msgmaps");
  572                 next = free_msgmaps;
  573                 if (next <= -1)
  574                         panic("next too low #1");
  575                 if (next >= msginfo.msgseg)
  576                         panic("next out of range #1");
  577                 MSG_PRINTF(("allocating segment %d to message\n", next));
  578                 free_msgmaps = msgmaps[next].next;
  579                 nfree_msgmaps--;
  580                 msgmaps[next].next = msghdr->msg_spot;
  581                 msghdr->msg_spot = next;
  582                 segs_needed--;
  583         }
  584 
  585         /*
  586          * Copy in the message type
  587          */
  588 
  589         if ((error = copyin(user_msgp, &msghdr->msg_type,
  590             sizeof(msghdr->msg_type))) != 0) {
  591                 MSG_PRINTF(("error %d copying the message type\n", error));
  592                 msg_freehdr(msghdr);
  593                 msqptr->msg_perm.mode &= ~MSG_LOCKED;
  594                 wakeup(msqptr);
  595                 return (error);
  596         }
  597         user_msgp += sizeof(msghdr->msg_type);
  598 
  599         /*
  600          * Validate the message type
  601          */
  602 
  603         if (msghdr->msg_type < 1) {
  604                 msg_freehdr(msghdr);
  605                 msqptr->msg_perm.mode &= ~MSG_LOCKED;
  606                 wakeup(msqptr);
  607                 MSG_PRINTF(("mtype (%ld) < 1\n", msghdr->msg_type));
  608                 return (EINVAL);
  609         }
  610 
  611         /*
  612          * Copy in the message body
  613          */
  614 
  615         next = msghdr->msg_spot;
  616         while (msgsz > 0) {
  617                 size_t tlen;
  618                 if (msgsz > msginfo.msgssz)
  619                         tlen = msginfo.msgssz;
  620                 else
  621                         tlen = msgsz;
  622                 if (next <= -1)
  623                         panic("next too low #2");
  624                 if (next >= msginfo.msgseg)
  625                         panic("next out of range #2");
  626                 if ((error = copyin(user_msgp, &msgpool[next * msginfo.msgssz],
  627                     tlen)) != 0) {
  628                         MSG_PRINTF(("error %d copying in message segment\n",
  629                             error));
  630                         msg_freehdr(msghdr);
  631                         msqptr->msg_perm.mode &= ~MSG_LOCKED;
  632                         wakeup(msqptr);
  633                         return (error);
  634                 }
  635                 msgsz -= tlen;
  636                 user_msgp += tlen;
  637                 next = msgmaps[next].next;
  638         }
  639         if (next != -1)
  640                 panic("didn't use all the msg segments");
  641 
  642         /*
  643          * We've got the message.  Unlock the msqid_ds.
  644          */
  645 
  646         msqptr->msg_perm.mode &= ~MSG_LOCKED;
  647 
  648         /*
  649          * Make sure that the msqid_ds is still allocated.
  650          */
  651 
  652         if (msqptr->msg_qbytes == 0) {
  653                 msg_freehdr(msghdr);
  654                 wakeup(msqptr);
  655                 return (EIDRM);
  656         }
  657 
  658         /*
  659          * Put the message into the queue
  660          */
  661 
  662         if (msqptr->_msg_first == NULL) {
  663                 msqptr->_msg_first = msghdr;
  664                 msqptr->_msg_last = msghdr;
  665         } else {
  666                 msqptr->_msg_last->msg_next = msghdr;
  667                 msqptr->_msg_last = msghdr;
  668         }
  669         msqptr->_msg_last->msg_next = NULL;
  670 
  671         msqptr->_msg_cbytes += msghdr->msg_ts;
  672         msqptr->msg_qnum++;
  673         msqptr->msg_lspid = p->p_pid;
  674         msqptr->msg_stime = time.tv_sec;
  675 
  676         wakeup(msqptr);
  677         return (0);
  678 }
  679 
  680 int
  681 sys_msgrcv(l, v, retval)
  682         struct lwp *l;
  683         void *v;
  684         register_t *retval;
  685 {
  686         struct sys_msgrcv_args /* {
  687                 syscallarg(int) msqid;
  688                 syscallarg(void *) msgp;
  689                 syscallarg(size_t) msgsz;
  690                 syscallarg(long) msgtyp;
  691                 syscallarg(int) msgflg;
  692         } */ *uap = v;
  693         struct proc *p = l->l_proc;
  694         int msqid = SCARG(uap, msqid);
  695         char *user_msgp = SCARG(uap, msgp);
  696         size_t msgsz = SCARG(uap, msgsz);
  697         long msgtyp = SCARG(uap, msgtyp);
  698         int msgflg = SCARG(uap, msgflg);
  699         size_t len;
  700         struct ucred *cred = p->p_ucred;
  701         struct msqid_ds *msqptr;
  702         struct __msg *msghdr;
  703         int error;
  704         short next;
  705 
  706         MSG_PRINTF(("call to msgrcv(%d, %p, %lld, %ld, %d)\n", msqid,
  707             user_msgp, (long long)msgsz, msgtyp, msgflg));
  708 
  709         msqid = IPCID_TO_IX(msqid);
  710 
  711         if (msqid < 0 || msqid >= msginfo.msgmni) {
  712                 MSG_PRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
  713                     msginfo.msgmni));
  714                 return (EINVAL);
  715         }
  716 
  717         msqptr = &msqids[msqid];
  718         if (msqptr->msg_qbytes == 0) {
  719                 MSG_PRINTF(("no such message queue id\n"));
  720                 return (EINVAL);
  721         }
  722         if (msqptr->msg_perm._seq != IPCID_TO_SEQ(SCARG(uap, msqid))) {
  723                 MSG_PRINTF(("wrong sequence number\n"));
  724                 return (EINVAL);
  725         }
  726 
  727         if ((error = ipcperm(cred, &msqptr->msg_perm, IPC_R))) {
  728                 MSG_PRINTF(("requester doesn't have read access\n"));
  729                 return (error);
  730         }
  731 
  732 #if 0
  733         /* cannot happen, msgsz is unsigned */
  734         if (msgsz < 0) {
  735                 MSG_PRINTF(("msgsz < 0\n"));
  736                 return (EINVAL);
  737         }
  738 #endif
  739 
  740         msghdr = NULL;
  741         while (msghdr == NULL) {
  742                 if (msgtyp == 0) {
  743                         msghdr = msqptr->_msg_first;
  744                         if (msghdr != NULL) {
  745                                 if (msgsz < msghdr->msg_ts &&
  746                                     (msgflg & MSG_NOERROR) == 0) {
  747                                         MSG_PRINTF(("first message on the "
  748                                             "queue is too big "
  749                                             "(want %lld, got %d)\n",
  750                                             (long long)msgsz, msghdr->msg_ts));
  751                                         return (E2BIG);
  752                                 }
  753                                 if (msqptr->_msg_first == msqptr->_msg_last) {
  754                                         msqptr->_msg_first = NULL;
  755                                         msqptr->_msg_last = NULL;
  756                                 } else {
  757                                         msqptr->_msg_first = msghdr->msg_next;
  758                                         if (msqptr->_msg_first == NULL)
  759                                                 panic("msg_first/last screwed "
  760                                                     "up #1");
  761                                 }
  762                         }
  763                 } else {
  764                         struct __msg *previous;
  765                         struct __msg **prev;
  766 
  767                         for (previous = NULL, prev = &msqptr->_msg_first;
  768                              (msghdr = *prev) != NULL;
  769                              previous = msghdr, prev = &msghdr->msg_next) {
  770                                 /*
  771                                  * Is this message's type an exact match or is
  772                                  * this message's type less than or equal to
  773                                  * the absolute value of a negative msgtyp?
  774                                  * Note that the second half of this test can
  775                                  * NEVER be true if msgtyp is positive since
  776                                  * msg_type is always positive!
  777                                  */
  778 
  779                                 if (msgtyp == msghdr->msg_type ||
  780                                     msghdr->msg_type <= -msgtyp) {
  781                                         MSG_PRINTF(("found message type %ld, "
  782                                             "requested %ld\n",
  783                                             msghdr->msg_type, msgtyp));
  784                                         if (msgsz < msghdr->msg_ts &&
  785                                             (msgflg & MSG_NOERROR) == 0) {
  786                                                 MSG_PRINTF(("requested message "
  787                                                     "on the queue is too big "
  788                                                     "(want %lld, got %d)\n",
  789                                                     (long long)msgsz,
  790                                                     msghdr->msg_ts));
  791                                                 return (E2BIG);
  792                                         }
  793                                         *prev = msghdr->msg_next;
  794                                         if (msghdr == msqptr->_msg_last) {
  795                                                 if (previous == NULL) {
  796                                                         if (prev !=
  797                                                             &msqptr->_msg_first)
  798                                                                 panic("msg_first/last screwed up #2");
  799                                                         msqptr->_msg_first =
  800                                                             NULL;
  801                                                         msqptr->_msg_last =
  802                                                             NULL;
  803                                                 } else {
  804                                                         if (prev ==
  805                                                             &msqptr->_msg_first)
  806                                                                 panic("msg_first/last screwed up #3");
  807                                                         msqptr->_msg_last =
  808                                                             previous;
  809                                                 }
  810                                         }
  811                                         break;
  812                                 }
  813                         }
  814                 }
  815 
  816                 /*
  817                  * We've either extracted the msghdr for the appropriate
  818                  * message or there isn't one.
  819                  * If there is one then bail out of this loop.
  820                  */
  821 
  822                 if (msghdr != NULL)
  823                         break;
  824 
  825                 /*
  826                  * Hmph!  No message found.  Does the user want to wait?
  827                  */
  828 
  829                 if ((msgflg & IPC_NOWAIT) != 0) {
  830                         MSG_PRINTF(("no appropriate message found (msgtyp=%ld)\n",
  831                             msgtyp));
  832                         /* The SVID says to return ENOMSG. */
  833 #ifdef ENOMSG
  834                         return (ENOMSG);
  835 #else
  836                         /* Unfortunately, BSD doesn't define that code yet! */
  837                         return (EAGAIN);
  838 #endif
  839                 }
  840 
  841                 /*
  842                  * Wait for something to happen
  843                  */
  844 
  845                 MSG_PRINTF(("msgrcv:  goodnight\n"));
  846                 error = tsleep(msqptr, (PZERO - 4) | PCATCH, "msgwait",
  847                     0);
  848                 MSG_PRINTF(("msgrcv: good morning (error=%d)\n", error));
  849 
  850                 if (error != 0) {
  851                         MSG_PRINTF(("msgsnd: interrupted system call\n"));
  852                         return (EINTR);
  853                 }
  854 
  855                 /*
  856                  * Make sure that the msq queue still exists
  857                  */
  858 
  859                 if (msqptr->msg_qbytes == 0 ||
  860                     msqptr->msg_perm._seq != IPCID_TO_SEQ(SCARG(uap, msqid))) {
  861                         MSG_PRINTF(("msqid deleted\n"));
  862                         return (EIDRM);
  863                 }
  864         }
  865 
  866         /*
  867          * Return the message to the user.
  868          *
  869          * First, do the bookkeeping (before we risk being interrupted).
  870          */
  871 
  872         msqptr->_msg_cbytes -= msghdr->msg_ts;
  873         msqptr->msg_qnum--;
  874         msqptr->msg_lrpid = p->p_pid;
  875         msqptr->msg_rtime = time.tv_sec;
  876 
  877         /*
  878          * Make msgsz the actual amount that we'll be returning.
  879          * Note that this effectively truncates the message if it is too long
  880          * (since msgsz is never increased).
  881          */
  882 
  883         MSG_PRINTF(("found a message, msgsz=%lld, msg_ts=%d\n",
  884             (long long)msgsz, msghdr->msg_ts));
  885         if (msgsz > msghdr->msg_ts)
  886                 msgsz = msghdr->msg_ts;
  887 
  888         /*
  889          * Return the type to the user.
  890          */
  891 
  892         error = copyout(&msghdr->msg_type, user_msgp, sizeof(msghdr->msg_type));
  893         if (error != 0) {
  894                 MSG_PRINTF(("error (%d) copying out message type\n", error));
  895                 msg_freehdr(msghdr);
  896                 wakeup(msqptr);
  897                 return (error);
  898         }
  899         user_msgp += sizeof(msghdr->msg_type);
  900 
  901         /*
  902          * Return the segments to the user
  903          */
  904 
  905         next = msghdr->msg_spot;
  906         for (len = 0; len < msgsz; len += msginfo.msgssz) {
  907                 size_t tlen;
  908 
  909                 if (msgsz - len > msginfo.msgssz)
  910                         tlen = msginfo.msgssz;
  911                 else
  912                         tlen = msgsz - len;
  913                 if (next <= -1)
  914                         panic("next too low #3");
  915                 if (next >= msginfo.msgseg)
  916                         panic("next out of range #3");
  917                 error = copyout(&msgpool[next * msginfo.msgssz],
  918                     user_msgp, tlen);
  919                 if (error != 0) {
  920                         MSG_PRINTF(("error (%d) copying out message segment\n",
  921                             error));
  922                         msg_freehdr(msghdr);
  923                         wakeup(msqptr);
  924                         return (error);
  925                 }
  926                 user_msgp += tlen;
  927                 next = msgmaps[next].next;
  928         }
  929 
  930         /*
  931          * Done, return the actual number of bytes copied out.
  932          */
  933 
  934         msg_freehdr(msghdr);
  935         wakeup(msqptr);
  936         *retval = msgsz;
  937         return (0);
  938 }

Cache object: f8cca95cfebd9544cb7d15d7b711bb21


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