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