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

Cache object: 76ae9b47cd1bc916224742a44c4e0ee8


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