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

Cache object: 1c33197bdb893eba7ae968d582efcf25


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