[BACK]Return to sysv_msg.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / kern

Annotation of src/sys/kern/sysv_msg.c, Revision 1.18

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

CVSweb <webmaster@jp.NetBSD.org>