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