|
|
1.1 ! root 1: /* $Header: /kernel/kersrc/io.286/msg.c,v 1.1 92/07/17 15:24:33 bin Exp Locker: bin $ ! 2: * ! 3: * The information contained herein is a trade secret of INETCO ! 4: * Systems, and is confidential information. It is provided under ! 5: * a license agreement, and may be copied or disclosed only under ! 6: * the terms of that agreement. Any reproduction or disclosure of ! 7: * this material without the express written authorization of ! 8: * INETCO Systems or persuant to the license agreement is unlawful. ! 9: * ! 10: * Copyright (c) 1987, 1986, 1985, 1984. ! 11: * An unpublished work by INETCO Systems, Ltd. ! 12: * All rights reserved. ! 13: */ ! 14: ! 15: /* ! 16: * System V Compatible Messaging ! 17: * ! 18: * This module provides System V compatible messaging operations. ! 19: * ! 20: * Author: Allan Cornish, INETCO Systems Ltd., Oct 1984 ! 21: * ! 22: * $Log: msg.c,v $ ! 23: * Revision 1.1 92/07/17 15:24:33 bin ! 24: * Initial revision ! 25: * ! 26: * Revision 2.1 88/09/03 13:09:07 src ! 27: * *** empty log message *** ! 28: * ! 29: * Revision 1.2 88/08/02 16:49:52 src ! 30: * Bug: msgget with IPC_CREAT could fail if message queue already ! 31: * existed, and queue permissions were not an exact match ! 32: * for requested permissions. ! 33: * Fix: Permission checking made more rigorous. ! 34: * ! 35: * Revision 1.1 88/03/24 17:05:44 src ! 36: * Initial revision ! 37: * ! 38: * 87/04/24 Allan Cornish /usr/src/sys/i8086/drv/msg.c ! 39: * Msgctl() IPC_STAT check of polled devices modified. ! 40: * ! 41: * 87/04/01 Allan Cornish /usr/src/sys/i8086/drv/msg.c ! 42: * Msgctl() now correctly reports polling events on an IPC_STAT operation. ! 43: * ! 44: * 87/03/20 Allan Cornish /usr/src/sys/i8086/drv/msg.c ! 45: * Msgpoll() now correctly reports POLLOUT events. ! 46: * ! 47: * 87/01/20 Allan Cornish /usr/src/sys/i8086/drv/msg.c ! 48: * msginit() is now more paranoid about validating NMSC, NMSG, NMSQID. ! 49: * ! 50: * 87/01/05 Allan Cornish /usr/src/sys/i8086/drv/msg.c ! 51: * msginit() now allocates message buffers in high memory. ! 52: * ! 53: * 86/12/12 Allan Cornish /usr/src/sys/i8086/drv/msg.c ! 54: * Added 3rd argument to msgpoll() to support non-blocking polls. ! 55: * ! 56: * 86/11/21 Allan Cornish /usr/src/sys/i8086/drv/msg.c ! 57: * Added support for System V.3 compatible polls. ! 58: * Added msgpoll() routine and xmsqid_ds structure. ! 59: * ! 60: * 85/08/06 Allan Cornish /usr/src/sys/i8086/drv/msg.c ! 61: * Msg.c split into configuration (msgcon.c) and implementation (msg.c). ! 62: * ! 63: * 85/07/22 Allan Cornish /usr/src/sys/i8086/drv/msg.c ! 64: * Msgget, msgctl, msgsnd, msgrcv now return immediately if u.u_error is set. ! 65: * ! 66: * 85/07/19 Allan Cornish ! 67: * Msgrcv() now reports E2BIG if message is larger than size requested. ! 68: * Msgfree() integrated into msginit() and msgrcv() functions. ! 69: * Msgsnd() now checks for queue removal after waking from sleep. ! 70: * Msgsnd() and msgrcv() now detect address faults and report EFAULT. ! 71: * ! 72: * 85/07/03 Allan Cornish ! 73: * Replaced use of EDOM with EIDRM. ! 74: * Replaced msgaccess() by calls to ipcaccess(), increasing shared ipc code. ! 75: * Eliminated many calls to sphi() and spl(). They are not really required, ! 76: * since system calls are synchronous unless they sleep or are interrupted. ! 77: * Sleeps cause no problem, and interrupts do not affect messaging state. ! 78: * ! 79: * 85/06/19 Allan Cornish ! 80: * Added code to msgctl to allow the owner of a queue to reduce msg_qbytes. ! 81: * Previously only the super-user could modify msg_qbytes. ! 82: * ! 83: * 85/06/18 Allan Cornish ! 84: * Added code to msgsnd to check for full queue (msg_cbytes >= msg_qbytes). ! 85: * Integrated msgalloc function into msgsnd, since only called from there. ! 86: * Fixed bug in msgrcv when msgtyp < 0, to treat msg_type as mesg priority. ! 87: * ! 88: * 85/05/10 Allan Cornish ! 89: * C compiler bug in msginit caused 'mp->msg_spot = (wanted -= NMSC)' to fail. ! 90: * For NMSG=10, NMSC=640, msg_spot always set to 0x1900 or 0xE980. ! 91: * Code changed to 'wanted -= NMSC; mp->msg_spot = wanted'. ! 92: * ! 93: * 85/04/01 Allan Cornish ! 94: * fixed qp->msg_last bug in msgrcv(). ! 95: */ ! 96: ! 97: #include <sys/coherent.h> ! 98: #include <sched.h> ! 99: #include <types.h> ! 100: #include <errno.h> ! 101: #include <stat.h> ! 102: #include <sys/con.h> ! 103: #include <seg.h> ! 104: #include <msg.h> ! 105: ! 106: #ifndef EIDRM ! 107: #define EIDRM EDOM ! 108: #endif ! 109: ! 110: /* ! 111: * Extended message queue id data structure. ! 112: * - extended to support System V.3 compatible polls. ! 113: */ ! 114: struct xmsqid_ds { ! 115: struct msqid_ds msq; ! 116: struct event ipolls; ! 117: struct event opolls; ! 118: }; ! 119: ! 120: /* ! 121: * Message Information ! 122: */ ! 123: ! 124: struct xmsqid_ds *msqs = 0; /* Pointer to array of message queues */ ! 125: /* (first queue contains free message list) */ ! 126: ! 127: struct msg * msgs = 0; /* Pointer to array of message headers */ ! 128: ! 129: static SEG * msgsp; /* Segment containing messages */ ! 130: #define msgsel FP_SEL(msgsp->s_faddr) ! 131: ! 132: /* ! 133: * Global Message Parameters ! 134: */ ! 135: ! 136: unsigned NMSQID = 9; /* allocated number of message queues */ ! 137: unsigned NMSQB = 2048; /* default maximum queue size in bytes */ ! 138: unsigned NMSG = 10; /* allocated messages: (NMSG * NMSC) < 2^16 */ ! 139: unsigned NMSC = 640; /* maximum message text size */ ! 140: ! 141: /* ! 142: * Message Device Initialization. ! 143: * ! 144: * Initialize message ids. ! 145: */ ! 146: ! 147: msginit() ! 148: { ! 149: register struct xmsqid_ds *qp; ! 150: register struct msg *mp; ! 151: long wanted; ! 152: int i; ! 153: ! 154: if ( NMSG == 0 ) ! 155: NMSQID = 0; ! 156: if ( NMSC == 0 ) ! 157: NMSQID = 0; ! 158: if ( NMSQID == 0 ) ! 159: return 0; ! 160: ! 161: if ( NMSQID > 128 ) ! 162: NMSQID = 128; ! 163: ! 164: /* ! 165: * Allocate message queues and message headers. ! 166: */ ! 167: wanted = (NMSQID * (long) sizeof(struct xmsqid_ds)) + ! 168: (NMSG * (long) sizeof(struct msg)); ! 169: if (wanted > 16384) { ! 170: printf("invalid NMSQID or NMSG kernel variable\n"); ! 171: NMSQID=0; ! 172: return; ! 173: } ! 174: ! 175: if ( msqs = kalloc( (unsigned) wanted) ) { ! 176: ! 177: /* ! 178: * Ensure allocated space is cleared. ! 179: */ ! 180: memset( msqs, 0, (unsigned) wanted ); ! 181: ! 182: /* ! 183: * Message headers are contiguous to message queues. ! 184: */ ! 185: msgs = (struct msg *) (&msqs[NMSQID]); ! 186: ! 187: /* ! 188: * Allocate message buffers. ! 189: */ ! 190: wanted = (long) NMSG * NMSC; ! 191: if ( wanted > 0xFFFFL ) { ! 192: printf("invalid NMSG or NMSC kernel variable\n"); ! 193: kfree( msqs ); ! 194: NMSQID = 0; ! 195: msqs = 0; ! 196: return; ! 197: } ! 198: ! 199: msgsp = salloc( (size_t) wanted, SFHIGH|SFNSWP|SFNCLR ); ! 200: ! 201: if ( msgsp == 0 ) { ! 202: printf("could not salloc %u messages\n", NMSG); ! 203: kfree( msqs ); ! 204: NMSQID = 0; ! 205: msqs = 0; ! 206: return; ! 207: } ! 208: ! 209: /* ! 210: * Initialize message queues. ! 211: */ ! 212: for ( qp = msqs, i = 0; i < NMSQID; i++, qp++ ) { ! 213: ! 214: qp->msq.msg_perm.seq = i * 256; ! 215: ! 216: qp->ipolls.e_dnext = ! 217: qp->ipolls.e_dlast = &qp->ipolls; ! 218: ! 219: qp->opolls.e_dnext = ! 220: qp->opolls.e_dlast = &qp->opolls; ! 221: } ! 222: ! 223: /* ! 224: * Initialize message headers, place on free queue. ! 225: */ ! 226: for ( qp = msqs, mp = &msgs[NMSG]; --mp >= msgs; ) { ! 227: wanted -= NMSC; ! 228: mp->msg_spot = wanted; ! 229: mp->msg_next = qp->msq.msg_first; ! 230: qp->msq.msg_first = mp; ! 231: } ! 232: } ! 233: else { ! 234: printf("could not kalloc %u message ids\n", NMSQID); ! 235: NMSQID = 0; ! 236: } ! 237: } ! 238: ! 239: ! 240: /* ! 241: * Msgctl - Message Control Operations. ! 242: */ ! 243: ! 244: umsgctl( qid, cmd, buf ) ! 245: ! 246: int qid; ! 247: int cmd; ! 248: struct msqid_ds *buf; ! 249: ! 250: { ! 251: register struct xmsqid_ds *qp; ! 252: register struct msg *mp; ! 253: unsigned n; ! 254: ! 255: /* ! 256: * Validate queue identifier. ! 257: */ ! 258: if ( (qid <= 0) || (qid/256 >= NMSQID) || (msqs == 0) ) { ! 259: u.u_error = EINVAL; ! 260: return -1; ! 261: } ! 262: ! 263: qp = &msqs[ qid / 256 ]; ! 264: ! 265: /* ! 266: * Validate queue existence. ! 267: */ ! 268: if ( (qp == 0) || ((qp->msq.msg_perm.mode & IPC_ALLOC) == 0) ) { ! 269: u.u_error = EINVAL; ! 270: return -1; ! 271: } ! 272: ! 273: /* ! 274: * Validate qid for all commands except for IPC_STAT. ! 275: */ ! 276: if ( (cmd != IPC_STAT) && (qp->msq.msg_perm.seq != qid) ) { ! 277: u.u_error = EINVAL; ! 278: return -1; ! 279: } ! 280: ! 281: switch ( cmd ) { ! 282: ! 283: case IPC_STAT: ! 284: /* ! 285: * Validate access authority. ! 286: */ ! 287: if ( (ipcaccess(&qp->msq.msg_perm) & MSG_R) == 0 ) { ! 288: u.u_error = EACCES; ! 289: break; ! 290: } ! 291: ! 292: /* ! 293: * Copy queue info to user. ! 294: */ ! 295: kucopy( qp, buf, sizeof(struct msqid_ds) ); ! 296: ! 297: /* ! 298: * Include input polls in receive waiting. ! 299: */ ! 300: if ( (qp->ipolls.e_dnext != NULL) ! 301: && (qp->ipolls.e_dnext != &qp->ipolls) ) { ! 302: putuwd( &buf->msg_perm.mode, ! 303: getuwd( &buf->msg_perm.mode ) | MSG_RWAIT ); ! 304: } ! 305: ! 306: /* ! 307: * Include output polls in write waiting. ! 308: */ ! 309: if ( (qp->opolls.e_dnext != NULL) ! 310: && (qp->opolls.e_dnext != &qp->opolls) ) { ! 311: putuwd( &buf->msg_perm.mode, ! 312: getuwd( &buf->msg_perm.mode ) | MSG_WWAIT ); ! 313: } ! 314: ! 315: /* ! 316: * Validate qid. ! 317: * Doing it now lets user get info on message queue. ! 318: */ ! 319: if ( qp->msq.msg_perm.seq != qid ) ! 320: u.u_error = EINVAL; ! 321: break; ! 322: ! 323: case IPC_SET: ! 324: /* ! 325: * Validate modify authority. ! 326: */ ! 327: if ( (u.u_uid != 0) && (u.u_uid != qp->msq.msg_perm.uid) ) { ! 328: u.u_error = EPERM; ! 329: break; ! 330: } ! 331: ! 332: /* ! 333: * Get desired queue size. ! 334: */ ! 335: n = getuwd( &(buf->msg_qbytes) ); ! 336: if (u.u_error) ! 337: break; ! 338: ! 339: /* ! 340: * Only super-user can increase queue size. ! 341: */ ! 342: if ( (u.u_uid != 0) && (n > qp->msq.msg_qbytes) ) { ! 343: u.u_error = EPERM; ! 344: break; ! 345: } ! 346: ! 347: /* ! 348: * Set queue parameters. ! 349: */ ! 350: qp->msq.msg_perm.uid = getuwd( &(buf->msg_perm.uid ) ); ! 351: qp->msq.msg_perm.gid = getuwd( &(buf->msg_perm.gid ) ); ! 352: qp->msq.msg_perm.mode &= ~0777; ! 353: qp->msq.msg_perm.mode |= getuwd( &(buf->msg_perm.mode) ) & 0777; ! 354: qp->msq.msg_qbytes = n; ! 355: break; ! 356: ! 357: case IPC_RMID: ! 358: /* ! 359: * Validate removal authority. ! 360: */ ! 361: if ( (u.u_uid != 0) && (u.u_uid != qp->msq.msg_perm.uid) ) { ! 362: u.u_error = EPERM; ! 363: break; ! 364: } ! 365: ! 366: /* ! 367: * Free all messages on the queue being removed. ! 368: */ ! 369: while ( mp = qp->msq.msg_first ) { ! 370: qp->msq.msg_first = mp->msg_next; ! 371: mp->msg_next = msqs->msq.msg_first; ! 372: msqs->msq.msg_first = mp; ! 373: } ! 374: ! 375: /* ! 376: * Wakeup processes waiting for free message buffers. ! 377: */ ! 378: if ( msqs->msq.msg_perm.mode & MSG_RWAIT ) { ! 379: msqs->msq.msg_perm.mode &= ~MSG_RWAIT; ! 380: wakeup( msqs ); ! 381: } ! 382: if ( msqs->ipolls.e_procp ) ! 383: pollwake( &msqs->ipolls ); ! 384: ! 385: /* ! 386: * Initialize queue parameters. ! 387: */ ! 388: qp->msq.msg_last = 0; ! 389: qp->msq.msg_qnum = 0; ! 390: qp->msq.msg_cbytes = 0; ! 391: if ( (qp->msq.msg_perm.seq & 0x00FF) == 0x00FF ) ! 392: qp->msq.msg_perm.seq &= 0x7F00; ! 393: qp->msq.msg_perm.seq++; ! 394: ! 395: /* ! 396: * Wakeup processes sleeping on the removed message queue. ! 397: */ ! 398: if ( qp->msq.msg_perm.mode & (MSG_RWAIT|MSG_WWAIT) ) ! 399: wakeup( qp ); ! 400: if ( qp->ipolls.e_procp ) ! 401: pollwake( &qp->ipolls ); ! 402: if ( qp->opolls.e_procp ) ! 403: pollwake( &qp->opolls ); ! 404: ! 405: qp->msq.msg_perm.mode = 0; ! 406: break; ! 407: ! 408: default: ! 409: u.u_error = EINVAL; ! 410: } ! 411: ! 412: if ( u.u_error ) ! 413: return -1; ! 414: ! 415: return 0; ! 416: } ! 417: ! 418: /* ! 419: * Msgget - Get set of messages ! 420: */ ! 421: ! 422: umsgget( mykey, msgflg ) ! 423: ! 424: key_t mykey; ! 425: int msgflg; ! 426: ! 427: { ! 428: register struct xmsqid_ds *qp; ! 429: register struct xmsqid_ds *freeidp = 0; ! 430: int rwmode; ! 431: ! 432: if ( msqs == 0 ) { ! 433: ! 434: msginit(); ! 435: ! 436: if ( msqs == 0 ) { ! 437: u.u_error = ENOMEM; ! 438: return; ! 439: } ! 440: } ! 441: ! 442: /* ! 443: * Extract desired access mode from flags. ! 444: */ ! 445: rwmode = msgflg & 0777; ! 446: ! 447: /* ! 448: * Search for desired message queue [also for first free queue]. ! 449: */ ! 450: for ( qp = &msqs[NMSQID]; --qp > msqs; ) { ! 451: ! 452: if ( (qp->msq.msg_perm.mode & IPC_ALLOC) == 0 ) { ! 453: ! 454: if ((freeidp == 0) || ! 455: (freeidp->msq.msg_ctime > qp->msq.msg_ctime)) ! 456: freeidp = qp; ! 457: continue; ! 458: } ! 459: ! 460: if (mykey == IPC_PRIVATE) ! 461: continue; ! 462: ! 463: if ( mykey == qp->msq.msg_perm.key ) { /* found! */ ! 464: ! 465: if ( (msgflg & IPC_CREAT) && (msgflg & IPC_EXCL) ) { ! 466: u.u_error = EEXIST; ! 467: return -1; ! 468: } ! 469: ! 470: if ( (qp->msq.msg_perm.mode & rwmode) != rwmode ) { ! 471: u.u_error = EACCES; ! 472: return -1; ! 473: } ! 474: ! 475: return qp->msq.msg_perm.seq; ! 476: } ! 477: } ! 478: ! 479: if ( ! (msgflg & IPC_CREAT) ) { ! 480: u.u_error = ENOENT; ! 481: return -1; ! 482: } ! 483: ! 484: if ( (qp = freeidp) == 0 ) { ! 485: u.u_error = ENOSPC; ! 486: return -1; ! 487: } ! 488: ! 489: qp->msq.msg_first = 0; ! 490: qp->msq.msg_last = 0; ! 491: qp->msq.msg_cbytes = 0; ! 492: qp->msq.msg_qnum = 0; ! 493: qp->msq.msg_qbytes = NMSQB; ! 494: qp->msq.msg_lspid = 0; ! 495: qp->msq.msg_lrpid = 0; ! 496: qp->msq.msg_stime = 0; ! 497: qp->msq.msg_rtime = 0; ! 498: qp->msq.msg_ctime = timer.t_time; ! 499: ! 500: qp->msq.msg_perm.cuid = qp->msq.msg_perm.uid = u.u_uid; ! 501: qp->msq.msg_perm.cgid = qp->msq.msg_perm.gid = u.u_gid; ! 502: qp->msq.msg_perm.mode = rwmode | IPC_ALLOC; ! 503: qp->msq.msg_perm.key = mykey; ! 504: ! 505: return qp->msq.msg_perm.seq; ! 506: } ! 507: ! 508: /* ! 509: * Send a Message ! 510: */ ! 511: ! 512: umsgsnd( qid, bufp, msgsz, msgflg ) ! 513: ! 514: int qid; ! 515: struct msgbuf *bufp; ! 516: unsigned msgsz, msgflg; ! 517: ! 518: { ! 519: register struct xmsqid_ds * qp; ! 520: register struct msg * mp; ! 521: ! 522: /* ! 523: * Validate queue identifier. ! 524: */ ! 525: if ((qid <= 0) || (qid/256 >= NMSQID) || (msgsz > NMSC) || (msqs==0)) { ! 526: u.u_error = EINVAL; ! 527: return -1; ! 528: } ! 529: ! 530: qp = &msqs[ qid / 256 ]; ! 531: ! 532: /* ! 533: * Validate queue existence. ! 534: */ ! 535: if ( (qp->msq.msg_perm.seq != qid) ! 536: || ((qp->msq.msg_perm.mode & IPC_ALLOC) == 0) ) { ! 537: u.u_error = EINVAL; ! 538: return -1; ! 539: } ! 540: ! 541: if ((ipcaccess(&qp->msq.msg_perm) & MSG_W) == 0){ /* can't send mesg */ ! 542: u.u_error = EACCES; ! 543: return -1; ! 544: } ! 545: ! 546: /* ! 547: * Wait for a free message buffer ! 548: */ ! 549: while ( (msqs->msq.msg_first == 0) ! 550: || (qp->msq.msg_qbytes <= qp->msq.msg_cbytes)) { ! 551: ! 552: if ( msgflg & IPC_NOWAIT ) { ! 553: u.u_error = EAGAIN; ! 554: return -1; ! 555: } ! 556: ! 557: if (qp->msq.msg_qbytes <= qp->msq.msg_cbytes) { ! 558: qp->msq.msg_perm.mode |= MSG_WWAIT; ! 559: sleep( qp, CVTTOUT, IVTTOUT, SVTTOUT ); ! 560: } ! 561: else { ! 562: msqs->msq.msg_perm.mode |= MSG_RWAIT; ! 563: sleep( msqs, CVTTOUT, IVTTOUT, SVTTOUT ); ! 564: } ! 565: ! 566: /* ! 567: * Abort if a signal was received ! 568: */ ! 569: if (SELF->p_ssig && nondsig() ) { ! 570: u.u_error = EINTR; ! 571: return -1; ! 572: } ! 573: ! 574: /* ! 575: * Abort if the message queue was removed. ! 576: */ ! 577: if ( qid != qp->msq.msg_perm.seq ) { ! 578: u.u_error = EIDRM; ! 579: return -1; ! 580: } ! 581: } ! 582: ! 583: /* ! 584: * Use first message on free message queue ! 585: */ ! 586: mp = msqs->msq.msg_first; ! 587: mp->msg_ts = msgsz; ! 588: ! 589: /* ! 590: * Transfer the message type and text. ! 591: */ ! 592: ukcopy( &(bufp->mtype), &(mp->msg_type), sizeof(mp->msg_type) ); ! 593: if ( ufcopy( &bufp->mtext[0], mp->msg_spot, msgsel, msgsz ) != msgsz ) ! 594: u.u_error = EFAULT; ! 595: ! 596: /* ! 597: * Abort if address fault occured during transfer. ! 598: */ ! 599: if ( u.u_error ) ! 600: return -1; ! 601: ! 602: /* ! 603: * Move the message to the desired queue. ! 604: */ ! 605: msqs->msq.msg_first = mp->msg_next; ! 606: mp->msg_next = 0; ! 607: ! 608: if ( qp->msq.msg_last ) ! 609: qp->msq.msg_last->msg_next = mp; ! 610: else ! 611: qp->msq.msg_first = mp; ! 612: qp->msq.msg_last = mp; ! 613: ! 614: /* ! 615: * Update queue statistics. ! 616: */ ! 617: qp->msq.msg_cbytes += msgsz; ! 618: qp->msq.msg_qnum++; ! 619: qp->msq.msg_lspid = SELF->p_pid; ! 620: qp->msq.msg_stime = timer.t_time; ! 621: ! 622: /* ! 623: * Wake processes waiting to receive. ! 624: */ ! 625: if ( qp->msq.msg_perm.mode & MSG_RWAIT ) { ! 626: qp->msq.msg_perm.mode &= ~MSG_RWAIT; ! 627: wakeup( qp ); ! 628: } ! 629: if ( qp->ipolls.e_procp ) ! 630: pollwake( &qp->ipolls ); ! 631: ! 632: return 0; ! 633: } ! 634: ! 635: /* ! 636: * Receive A Message ! 637: */ ! 638: ! 639: umsgrcv( qid, bufp, msgsz, msgtyp, msgflg ) ! 640: ! 641: int qid; ! 642: struct msgbuf *bufp; ! 643: unsigned msgsz; ! 644: long msgtyp; ! 645: unsigned msgflg; ! 646: ! 647: { ! 648: register struct xmsqid_ds *qp; ! 649: register struct msg *mp; ! 650: register struct msg *prev; ! 651: ! 652: /* ! 653: * Validate queue identifier. ! 654: */ ! 655: if ( (qid <= 0) || (qid/256 >= NMSQID) || (msqs == 0) ) { ! 656: u.u_error = EINVAL; ! 657: return -1; ! 658: } ! 659: ! 660: qp = &msqs[ qid / 256 ]; ! 661: ! 662: /* ! 663: * Validate queue existence. ! 664: */ ! 665: if ( (qp->msq.msg_perm.seq != qid) ! 666: || ((qp->msq.msg_perm.mode & IPC_ALLOC) == 0) ) { ! 667: u.u_error = EINVAL; ! 668: return -1; ! 669: } ! 670: ! 671: /* ! 672: * Permission denied ! 673: */ ! 674: if ( (ipcaccess(&qp->msq.msg_perm) & MSG_R) == 0 ) { ! 675: u.u_error = EACCES; ! 676: return -1; ! 677: } ! 678: ! 679: /* ! 680: * Wait for message ! 681: */ ! 682: for (;;) { ! 683: ! 684: mp = qp->msq.msg_first; ! 685: prev = 0; ! 686: ! 687: /* ! 688: * Find mesg of type <= abs(msgtyp) ! 689: */ ! 690: if ( msgtyp < 0 ) { ! 691: ! 692: struct msg *xp, *xprev; ! 693: ! 694: xp = 0; ! 695: xprev = 0; ! 696: msgtyp = -msgtyp; ! 697: ! 698: for ( ; mp != 0 ; prev = mp, mp = mp->msg_next ) { ! 699: ! 700: if (mp->msg_type > msgtyp) ! 701: continue; ! 702: ! 703: if ((xp==0) || (mp->msg_type < xp->msg_type)) { ! 704: xp = mp; ! 705: xprev = prev; ! 706: } ! 707: } ! 708: mp = xp; ! 709: prev = xprev; ! 710: msgtyp = -msgtyp; ! 711: } ! 712: ! 713: /* ! 714: * Find message of type == msgtyp ! 715: */ ! 716: else if ( msgtyp > 0 ) { ! 717: ! 718: while ( (mp != 0) && (mp->msg_type != msgtyp) ) { ! 719: prev = mp; ! 720: mp = mp->msg_next; ! 721: } ! 722: } ! 723: ! 724: /* ! 725: * Else take first message ! 726: */ ! 727: ! 728: if ( mp ) ! 729: break; ! 730: ! 731: /* ! 732: * Can't wait to receive mesg ! 733: */ ! 734: if ( msgflg & IPC_NOWAIT ) { ! 735: u.u_error = EAGAIN; ! 736: return -1; ! 737: } ! 738: ! 739: qp->msq.msg_perm.mode |= MSG_RWAIT; ! 740: sleep( qp, CVTTOUT, IVTTOUT, SVTTOUT ); ! 741: ! 742: /* ! 743: * Signal received ! 744: */ ! 745: if ( SELF->p_ssig && nondsig() ) { ! 746: u.u_error = EINTR; ! 747: return -1; ! 748: } ! 749: ! 750: /* ! 751: * Not same q anymore ! 752: */ ! 753: if ( qid != qp->msq.msg_perm.seq ) { ! 754: u.u_error = EIDRM; ! 755: return -1; ! 756: } ! 757: } ! 758: ! 759: /* ! 760: * Ensure entire message can be transferred, or MSG_NOERROR asserted. ! 761: */ ! 762: if ( (msgsz < mp->msg_ts) && ((msgflg & MSG_NOERROR) == 0) ) { ! 763: u.u_error = E2BIG; ! 764: return -1; ! 765: } ! 766: ! 767: /* ! 768: * Transfer message data ! 769: */ ! 770: if ( msgsz > mp->msg_ts ) ! 771: msgsz = mp->msg_ts; ! 772: ! 773: kucopy( &(mp->msg_type), &(bufp->mtype), sizeof(mp->msg_type) ); ! 774: if (fucopy( mp->msg_spot, msgsel, &(bufp->mtext[0]), msgsz ) != msgsz) ! 775: u.u_error = EFAULT; ! 776: ! 777: /* ! 778: * Abort if address fault occurred during transfer. ! 779: */ ! 780: if ( u.u_error ) ! 781: return -1; ! 782: ! 783: /* ! 784: * Remove message from queue ! 785: */ ! 786: if ( prev ) ! 787: prev->msg_next = mp->msg_next; ! 788: else ! 789: qp->msq.msg_first = mp->msg_next; ! 790: ! 791: if ( qp->msq.msg_last == mp ) ! 792: qp->msq.msg_last = prev; ! 793: ! 794: /* ! 795: * Update queue statistics ! 796: */ ! 797: qp->msq.msg_cbytes -= mp->msg_ts; ! 798: qp->msq.msg_qnum--; ! 799: qp->msq.msg_lrpid = SELF->p_pid; ! 800: qp->msq.msg_rtime = timer.t_time; ! 801: ! 802: /* ! 803: * Wakeup processes waiting to send. ! 804: */ ! 805: if (qp->msq.msg_perm.mode & MSG_WWAIT) { ! 806: qp->msq.msg_perm.mode &= ~MSG_WWAIT; ! 807: wakeup( qp ); ! 808: } ! 809: if ( qp->opolls.e_procp ) ! 810: pollwake( &qp->opolls ); ! 811: ! 812: /* ! 813: * Place message buffer on free message queue ! 814: */ ! 815: qp = msqs; ! 816: mp->msg_next = qp->msq.msg_first; ! 817: qp->msq.msg_first = mp; ! 818: ! 819: /* ! 820: * Wakeup processes waiting for empty message buffer ! 821: */ ! 822: if ( qp->msq.msg_perm.mode & MSG_RWAIT ) { ! 823: qp->msq.msg_perm.mode &= ~MSG_RWAIT; ! 824: wakeup( qp ); ! 825: } ! 826: if ( msqs->ipolls.e_procp ) ! 827: pollwake( &msqs->ipolls ); ! 828: ! 829: return msgsz; ! 830: } ! 831: ! 832: /* ! 833: * Msgpoll - Message Queue Polling. ! 834: */ ! 835: msgpoll( qid, ev, msec ) ! 836: int qid; ! 837: int ev; ! 838: int msec; ! 839: { ! 840: register struct xmsqid_ds * qp; ! 841: ! 842: /* ! 843: * Validate queue identifier. ! 844: */ ! 845: if ( (qid <= 0) || (qid/256 >= NMSQID) || (msqs == 0) ) ! 846: return POLLNVAL; ! 847: ! 848: qp = &msqs[ qid / 256 ]; ! 849: ! 850: /* ! 851: * Validate queue existence. ! 852: */ ! 853: if ( ((qp->msq.msg_perm.mode & IPC_ALLOC) == 0) ! 854: || (qp->msq.msg_perm.seq != qid) ) ! 855: return POLLHUP; ! 856: ! 857: /* ! 858: * Priority polls not supported. ! 859: */ ! 860: ev &= ~POLLPRI; ! 861: ! 862: /* ! 863: * Input poll. ! 864: */ ! 865: if ( ev & POLLIN ) { ! 866: ! 867: /* ! 868: * No messages on queue. ! 869: */ ! 870: if ( qp->msq.msg_qnum == 0 ) { ! 871: /* ! 872: * Enable input monitor. ! 873: */ ! 874: if ( msec != 0 ) ! 875: pollopen( &qp->ipolls ); ! 876: ev &= ~POLLIN; ! 877: } ! 878: ! 879: /* ! 880: * Prevent output monitor. ! 881: */ ! 882: else ! 883: msec = 0; ! 884: } ! 885: ! 886: /* ! 887: * Output poll. ! 888: */ ! 889: if ( ev & POLLOUT ) { ! 890: ! 891: /* ! 892: * Queue full. ! 893: */ ! 894: if ( qp->msq.msg_cbytes >= qp->msq.msg_qbytes ) { ! 895: if ( msec != 0 ) ! 896: pollopen( &qp->opolls ); ! 897: ev &= ~POLLOUT; ! 898: } ! 899: ! 900: /* ! 901: * No free message buffers. ! 902: */ ! 903: else if ( msqs->msq.msg_first == NULL ) { ! 904: if ( msec != 0 ) ! 905: pollopen( &msqs->ipolls ); ! 906: ev &= ~POLLOUT; ! 907: } ! 908: } ! 909: ! 910: return ev; ! 911: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.