|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* ! 26: * Copyright (c) 1995, 1994, 1993, 1992, 1991, 1990 ! 27: * Open Software Foundation, Inc. ! 28: * ! 29: * Permission to use, copy, modify, and distribute this software and ! 30: * its documentation for any purpose and without fee is hereby granted, ! 31: * provided that the above copyright notice appears in all copies and ! 32: * that both the copyright notice and this permission notice appear in ! 33: * supporting documentation, and that the name of ("OSF") or Open Software ! 34: * Foundation not be used in advertising or publicity pertaining to ! 35: * distribution of the software without specific, written prior permission. ! 36: * ! 37: * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE ! 38: * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ! 39: * FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL OSF BE LIABLE FOR ANY ! 40: * SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ! 41: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN ! 42: * ACTION OF CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING ! 43: * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE ! 44: */ ! 45: /* ! 46: * OSF Research Institute MK6.1 (unencumbered) 1/31/1995 ! 47: */ ! 48: /* ! 49: * Mach Operating System ! 50: * Copyright (c) 1991,1990,1989 Carnegie Mellon University ! 51: * All Rights Reserved. ! 52: * ! 53: * Permission to use, copy, modify and distribute this software and its ! 54: * documentation is hereby granted, provided that both the copyright ! 55: * notice and this permission notice appear in all copies of the ! 56: * software, derivative works or modified versions, and any portions ! 57: * thereof, and that both notices appear in supporting documentation. ! 58: * ! 59: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 60: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 61: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 62: * ! 63: * Carnegie Mellon requests users of this software to return to ! 64: * ! 65: * Software Distribution Coordinator or [email protected] ! 66: * School of Computer Science ! 67: * Carnegie Mellon University ! 68: * Pittsburgh PA 15213-3890 ! 69: * ! 70: * any improvements or extensions that they make and grant Carnegie Mellon ! 71: * the rights to redistribute these changes. ! 72: */ ! 73: /* ! 74: * File: ipc/ipc_mqueue.c ! 75: * Author: Rich Draves ! 76: * Date: 1989 ! 77: * ! 78: * Functions to manipulate IPC message queues. ! 79: */ ! 80: ! 81: #include <mach/port.h> ! 82: #include <mach/message.h> ! 83: #include <kern/assert.h> ! 84: #include <kern/counters.h> ! 85: #include <kern/sched_prim.h> ! 86: #include <kern/ipc_sched.h> ! 87: #include <kern/ipc_kobject.h> ! 88: #include <ipc/ipc_mqueue.h> ! 89: #include <ipc/ipc_thread.h> ! 90: #include <ipc/ipc_kmsg.h> ! 91: #include <ipc/ipc_port.h> ! 92: #include <ipc/ipc_pset.h> ! 93: #include <ipc/ipc_space.h> ! 94: #include <ipc/ipc_marequest.h> ! 95: ! 96: /* ! 97: * Routine: ipc_mqueue_init ! 98: * Purpose: ! 99: * Initialize a newly-allocated message queue. ! 100: */ ! 101: ! 102: void ! 103: ipc_mqueue_init( ! 104: ipc_mqueue_t mqueue) ! 105: { ! 106: imq_lock_init(mqueue); ! 107: ipc_kmsg_queue_init(&mqueue->imq_messages); ! 108: ipc_thread_queue_init(&mqueue->imq_threads); ! 109: } ! 110: ! 111: /* ! 112: * Routine: ipc_mqueue_move ! 113: * Purpose: ! 114: * Move messages from one queue (source) to another (dest). ! 115: * Only moves messages sent to the specified port. ! 116: * Conditions: ! 117: * Both queues must be locked. ! 118: * (This is sufficient to manipulate port->ip_seqno.) ! 119: */ ! 120: ! 121: void ! 122: ipc_mqueue_move( ! 123: ipc_mqueue_t dest, ! 124: ipc_mqueue_t source, ! 125: ipc_port_t port) ! 126: { ! 127: ipc_kmsg_queue_t oldq, newq; ! 128: ipc_thread_queue_t blockedq; ! 129: ipc_kmsg_t kmsg, next; ! 130: ipc_thread_t th; ! 131: ! 132: oldq = &source->imq_messages; ! 133: newq = &dest->imq_messages; ! 134: blockedq = &dest->imq_threads; ! 135: ! 136: for (kmsg = ipc_kmsg_queue_first(oldq); ! 137: kmsg != IKM_NULL; kmsg = next) { ! 138: next = ipc_kmsg_queue_next(oldq, kmsg); ! 139: ! 140: /* only move messages sent to port */ ! 141: ! 142: if (kmsg->ikm_header.msgh_remote_port != (mach_port_t) port) ! 143: continue; ! 144: ! 145: ipc_kmsg_rmqueue(oldq, kmsg); ! 146: ! 147: /* before adding kmsg to newq, check for a blocked receiver */ ! 148: ! 149: if (kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_OLD_FORMAT) { ! 150: while ((th = ipc_thread_dequeue(blockedq)) != ITH_NULL) { ! 151: assert(ipc_kmsg_queue_empty(newq)); ! 152: ! 153: /* check if the receiver can handle the message */ ! 154: ! 155: if (!(th->ith_rcv_option & MACH_RCV_OLD_FORMAT)) { ! 156: th->ith_state = MACH_RCV_HEADER_ERROR; ! 157: th->ith_kmsg = kmsg; ! 158: th->ith_seqno = port->ip_seqno++; ! 159: thread_go(th); ! 160: ! 161: goto next_kmsg; ! 162: } ! 163: else ! 164: if (kmsg->ikm_header.msgh_size <= th->ith_msize) { ! 165: th->ith_state = MACH_MSG_SUCCESS; ! 166: th->ith_kmsg = kmsg; ! 167: th->ith_seqno = port->ip_seqno++; ! 168: thread_go(th); ! 169: ! 170: goto next_kmsg; ! 171: } ! 172: else { ! 173: th->ith_state = MACH_RCV_TOO_LARGE; ! 174: th->ith_msize = kmsg->ikm_header.msgh_size; ! 175: } ! 176: ! 177: thread_go(th); ! 178: } ! 179: } ! 180: else { ! 181: boolean_t msg_is_complex = ! 182: (kmsg->ikm_header.msgh_bits & ! 183: MACH_MSGH_BITS_COMPLEX) != 0; ! 184: ! 185: while ((th = ipc_thread_dequeue(blockedq)) != ITH_NULL) { ! 186: assert(ipc_kmsg_queue_empty(newq)); ! 187: ! 188: /* ! 189: * Check if the receiver can handle the message ! 190: */ ! 191: if (th->ith_rcv_option & MACH_RCV_OLD_FORMAT) { ! 192: if (msg_is_complex || ! 193: kmsg->ikm_header.msgh_size > ! 194: sizeof (mach_msg_header_t) || ! 195: th->ith_msize < ! 196: sizeof (mach_msg_header_t)) { ! 197: th->ith_state = MACH_RCV_HEADER_ERROR; ! 198: th->ith_kmsg = kmsg; ! 199: th->ith_seqno = port->ip_seqno++; ! 200: thread_go(th); ! 201: ! 202: goto next_kmsg; ! 203: } ! 204: ! 205: /* ! 206: * As a special case, allow simple ! 207: * messages which consist of only a ! 208: * header to be received with the old ! 209: * messaging primatives. ! 210: */ ! 211: th->ith_state = MACH_MSG_SUCCESS; ! 212: } ! 213: else ! 214: if (kmsg->ikm_header.msgh_size > (th->ith_msize - ! 215: REQUESTED_TRAILER_SIZE(th->ith_rcv_option))) { ! 216: /* ! 217: * The receive buffer isn't large enough ! 218: */ ! 219: th->ith_state = MACH_RCV_TOO_LARGE; ! 220: ! 221: if (th->ith_rcv_option & MACH_RCV_LARGE) { ! 222: th->ith_msize = kmsg->ikm_header.msgh_size; ! 223: thread_go(th); ! 224: continue; ! 225: } ! 226: } ! 227: else ! 228: if (msg_is_complex && th->ith_list != IKM_NULL && ! 229: (th->ith_state = ! 230: ipc_kmsg_check_scatter( ! 231: kmsg, th->ith_rcv_option, ! 232: &th->ith_list)) ! 233: != MACH_MSG_SUCCESS) { ! 234: /* ! 235: * Check for type/VM errors. ! 236: */ ! 237: if (th->ith_state == MACH_RCV_INVALID_TYPE || ! 238: (th->ith_state & MACH_MSG_VM_KERNEL) != 0) { ! 239: thread_go(th); ! 240: continue; ! 241: } ! 242: ! 243: /* ! 244: * The scatter list isn't large enough. ! 245: */ ! 246: if (th->ith_rcv_option & MACH_RCV_LARGE) { ! 247: th->ith_msize = kmsg->ikm_header.msgh_size; ! 248: thread_go(th); ! 249: continue; ! 250: } ! 251: } ! 252: else ! 253: th->ith_state = MACH_MSG_SUCCESS; ! 254: ! 255: /* ! 256: * Got a receiver. Possibly with a size error. ! 257: * Hand the receiver the message and process the ! 258: * next one. ! 259: */ ! 260: th->ith_kmsg = kmsg; ! 261: th->ith_seqno = port->ip_seqno++; ! 262: thread_go(th); ! 263: goto next_kmsg; ! 264: } ! 265: } ! 266: ! 267: /* didn't find a receiver to handle the message */ ! 268: ! 269: ipc_kmsg_enqueue(newq, kmsg); ! 270: next_kmsg:; ! 271: } ! 272: } ! 273: ! 274: /* ! 275: * Routine: ipc_mqueue_changed ! 276: * Purpose: ! 277: * Wake up receivers waiting in a message queue. ! 278: * Conditions: ! 279: * The message queue is locked. ! 280: */ ! 281: ! 282: void ! 283: ipc_mqueue_changed( ! 284: ipc_mqueue_t mqueue, ! 285: mach_msg_return_t mr) ! 286: { ! 287: ipc_thread_t th; ! 288: ! 289: while ((th = ipc_thread_dequeue(&mqueue->imq_threads)) != ITH_NULL) { ! 290: th->ith_state = mr; ! 291: thread_go(th); ! 292: } ! 293: } ! 294: ! 295: /* ! 296: * Routine: ipc_mqueue_send ! 297: * Purpose: ! 298: * Send a message to a port. The message holds a reference ! 299: * for the destination port in the msgh_remote_port field. ! 300: * ! 301: * If unsuccessful, the caller still has possession of ! 302: * the message and must do something with it. If successful, ! 303: * the message is queued, given to a receiver, destroyed, ! 304: * or handled directly by the kernel via mach_msg. ! 305: * Conditions: ! 306: * Nothing locked. ! 307: * Returns: ! 308: * MACH_MSG_SUCCESS The message was accepted. ! 309: * MACH_SEND_TIMED_OUT Caller still has message. ! 310: * MACH_SEND_INTERRUPTED Caller still has message. ! 311: */ ! 312: ! 313: mach_msg_return_t ! 314: ipc_mqueue_send( ! 315: ipc_kmsg_t kmsg, ! 316: mach_msg_option_t option, ! 317: mach_msg_timeout_t timeout, ! 318: void (*continuation)(void)) ! 319: { ! 320: ipc_port_t port; ! 321: ! 322: port = (ipc_port_t) kmsg->ikm_header.msgh_remote_port; ! 323: assert(IP_VALID(port)); ! 324: ! 325: ip_lock(port); ! 326: ! 327: if (port->ip_receiver == ipc_space_kernel) { ! 328: ipc_kmsg_t reply; ! 329: ! 330: /* ! 331: * We can check ip_receiver == ipc_space_kernel ! 332: * before checking that the port is active because ! 333: * ipc_port_dealloc_kernel clears ip_receiver ! 334: * before destroying a kernel port. ! 335: */ ! 336: ! 337: assert(ip_active(port)); ! 338: ip_unlock(port); ! 339: ! 340: reply = ipc_kobject_server(kmsg); ! 341: if (reply != IKM_NULL) ! 342: ipc_mqueue_send_always(reply); ! 343: ! 344: return MACH_MSG_SUCCESS; ! 345: } ! 346: ! 347: for (;;) { ! 348: ipc_thread_t self; ! 349: ! 350: /* ! 351: * Can't deliver to a dead port. ! 352: * However, we can pretend it got sent ! 353: * and was then immediately destroyed. ! 354: */ ! 355: ! 356: if (!ip_active(port)) { ! 357: /* ! 358: * We can't let ipc_kmsg_destroy deallocate ! 359: * the port right, because we might end up ! 360: * in an infinite loop trying to deliver ! 361: * a send-once notification. ! 362: */ ! 363: ! 364: ip_release(port); ! 365: ip_check_unlock(port); ! 366: kmsg->ikm_header.msgh_remote_port = MACH_PORT_NULL; ! 367: ipc_kmsg_destroy(kmsg); ! 368: return MACH_MSG_SUCCESS; ! 369: } ! 370: ! 371: /* ! 372: * Don't block if: ! 373: * 1) We're under the queue limit. ! 374: * 2) Caller used the MACH_SEND_ALWAYS internal option. ! 375: * 3) Message is sent to a send-once right. ! 376: */ ! 377: ! 378: if ((port->ip_msgcount < port->ip_qlimit) || ! 379: (option & MACH_SEND_ALWAYS) || ! 380: (MACH_MSGH_BITS_REMOTE(kmsg->ikm_header.msgh_bits) == ! 381: MACH_MSG_TYPE_PORT_SEND_ONCE)) ! 382: break; ! 383: ! 384: /* must block waiting for queue to clear */ ! 385: ! 386: self = current_thread(); ! 387: ! 388: if (option & MACH_SEND_TIMEOUT) { ! 389: if (timeout == 0) { ! 390: ip_unlock(port); ! 391: return MACH_SEND_TIMED_OUT; ! 392: } ! 393: ! 394: thread_will_wait_with_timeout(self, timeout); ! 395: } else ! 396: thread_will_wait(self); ! 397: ! 398: ipc_thread_enqueue(&port->ip_blocked, self); ! 399: self->ith_state = MACH_SEND_IN_PROGRESS; ! 400: ! 401: ip_unlock(port); ! 402: counter(c_ipc_mqueue_send_block++); ! 403: thread_block_with_continuation((void (*)(void)) 0); ! 404: ip_lock(port); ! 405: ! 406: /* why did we wake up? */ ! 407: ! 408: if (self->ith_state == MACH_MSG_SUCCESS) ! 409: continue; ! 410: assert(self->ith_state == MACH_SEND_IN_PROGRESS); ! 411: ! 412: /* take ourselves off blocked queue */ ! 413: ! 414: ipc_thread_rmqueue(&port->ip_blocked, self); ! 415: ! 416: /* ! 417: * Thread wakeup-reason field tells us why ! 418: * the wait was interrupted. ! 419: */ ! 420: ! 421: switch (self->ith_wait_result) { ! 422: case THREAD_INTERRUPTED: ! 423: case THREAD_SHOULD_TERMINATE: ! 424: /* send was interrupted - give up */ ! 425: ! 426: ip_unlock(port); ! 427: return MACH_SEND_INTERRUPTED; ! 428: ! 429: case THREAD_TIMED_OUT: ! 430: /* timeout expired */ ! 431: ! 432: assert(option & MACH_SEND_TIMEOUT); ! 433: timeout = 0; ! 434: break; ! 435: ! 436: case THREAD_RESTART: ! 437: default: ! 438: panic("ipc_mqueue_send"); ! 439: } ! 440: } ! 441: ! 442: if (kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_CIRCULAR) { ! 443: ip_unlock(port); ! 444: ! 445: /* don't allow the creation of a circular loop */ ! 446: ! 447: ipc_kmsg_destroy(kmsg); ! 448: return MACH_MSG_SUCCESS; ! 449: } ! 450: ! 451: { ! 452: ipc_mqueue_t mqueue; ! 453: ipc_pset_t pset; ! 454: ipc_thread_t receiver; ! 455: ipc_thread_queue_t receivers; ! 456: ! 457: port->ip_msgcount++; ! 458: assert(port->ip_msgcount > 0); ! 459: ! 460: pset = port->ip_pset; ! 461: if (pset == IPS_NULL) ! 462: mqueue = &port->ip_messages; ! 463: else ! 464: mqueue = &pset->ips_messages; ! 465: ! 466: imq_lock(mqueue); ! 467: receivers = &mqueue->imq_threads; ! 468: ! 469: /* ! 470: * Can unlock the port now that the msg queue is locked ! 471: * and we know the port is active. While the msg queue ! 472: * is locked, we have control of the kmsg, so the ref in ! 473: * it for the port is still good. If the msg queue is in ! 474: * a set (dead or alive), then we're OK because the port ! 475: * is still a member of the set and the set won't go away ! 476: * until the port is taken out, which tries to lock the ! 477: * set's msg queue to remove the port's msgs. ! 478: */ ! 479: ! 480: ip_unlock(port); ! 481: ! 482: /* check for a receiver for the message */ ! 483: ! 484: if (kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_OLD_FORMAT) { ! 485: for (;;) { ! 486: receiver = ipc_thread_queue_first(receivers); ! 487: if (receiver == ITH_NULL) { ! 488: /* no receivers; queue kmsg */ ! 489: ! 490: ipc_kmsg_enqueue_macro(&mqueue->imq_messages, kmsg); ! 491: imq_unlock(mqueue); ! 492: break; ! 493: } ! 494: ! 495: ipc_thread_rmqueue_first_macro(receivers, receiver); ! 496: assert(ipc_kmsg_queue_empty(&mqueue->imq_messages)); ! 497: ! 498: if (!(receiver->ith_rcv_option & MACH_RCV_OLD_FORMAT)) { ! 499: receiver->ith_state = MACH_RCV_HEADER_ERROR; ! 500: receiver->ith_kmsg = kmsg; ! 501: receiver->ith_seqno = port->ip_seqno++; ! 502: imq_unlock(mqueue); ! 503: ! 504: thread_go(receiver); ! 505: break; ! 506: } ! 507: else ! 508: if (kmsg->ikm_header.msgh_size <= receiver->ith_msize) { ! 509: /* got a successful receiver */ ! 510: ! 511: receiver->ith_state = MACH_MSG_SUCCESS; ! 512: receiver->ith_kmsg = kmsg; ! 513: receiver->ith_seqno = port->ip_seqno++; ! 514: imq_unlock(mqueue); ! 515: ! 516: if (option & MACH_SEND_SWITCH) ! 517: thread_go_and_switch(continuation, receiver); ! 518: else ! 519: thread_go(receiver); ! 520: break; ! 521: } ! 522: else { ! 523: receiver->ith_state = MACH_RCV_TOO_LARGE; ! 524: receiver->ith_msize = kmsg->ikm_header.msgh_size; ! 525: } ! 526: ! 527: thread_go(receiver); ! 528: } ! 529: } ! 530: else { ! 531: boolean_t msg_is_complex = ! 532: (kmsg->ikm_header.msgh_bits & ! 533: MACH_MSGH_BITS_COMPLEX) != 0; ! 534: ! 535: for (;;) { ! 536: receiver = ipc_thread_queue_first(receivers); ! 537: if (receiver == ITH_NULL) { ! 538: /* no receivers; queue kmsg */ ! 539: ! 540: ipc_kmsg_enqueue_macro(&mqueue->imq_messages, kmsg); ! 541: imq_unlock(mqueue); ! 542: break; ! 543: } ! 544: ! 545: ipc_thread_rmqueue_first_macro(receivers, receiver); ! 546: assert(ipc_kmsg_queue_empty(&mqueue->imq_messages)); ! 547: ! 548: /* ! 549: * Got a potential receiver, verify sizes ! 550: */ ! 551: if (receiver->ith_rcv_option & MACH_RCV_OLD_FORMAT) { ! 552: if (msg_is_complex || ! 553: kmsg->ikm_header.msgh_size > ! 554: sizeof (mach_msg_header_t) || ! 555: receiver->ith_msize < ! 556: sizeof (mach_msg_header_t)) { ! 557: receiver->ith_state = MACH_RCV_HEADER_ERROR; ! 558: receiver->ith_kmsg = kmsg; ! 559: receiver->ith_seqno = port->ip_seqno++; ! 560: imq_unlock(mqueue); ! 561: thread_go(receiver); ! 562: break; ! 563: } ! 564: ! 565: receiver->ith_state = MACH_MSG_SUCCESS; ! 566: } ! 567: else ! 568: if (kmsg->ikm_header.msgh_size > (receiver->ith_msize - ! 569: REQUESTED_TRAILER_SIZE(receiver->ith_rcv_option))) { ! 570: /* ! 571: * The receive buffer isn't large enough ! 572: */ ! 573: receiver->ith_state = MACH_RCV_TOO_LARGE; ! 574: ! 575: if (receiver->ith_rcv_option & MACH_RCV_LARGE) { ! 576: receiver->ith_msize = kmsg->ikm_header.msgh_size; ! 577: thread_go(receiver); ! 578: continue; ! 579: } ! 580: } ! 581: else ! 582: if (msg_is_complex && receiver->ith_list != IKM_NULL && ! 583: (receiver->ith_state = ! 584: ipc_kmsg_check_scatter( ! 585: kmsg, receiver->ith_rcv_option, ! 586: &receiver->ith_list)) ! 587: != MACH_MSG_SUCCESS) { ! 588: /* ! 589: * Check for type/VM errors. ! 590: */ ! 591: if (receiver->ith_state == MACH_RCV_INVALID_TYPE || ! 592: (receiver->ith_state & MACH_MSG_VM_KERNEL) != 0) { ! 593: thread_go(receiver); ! 594: continue; ! 595: } ! 596: ! 597: /* ! 598: * The scatter list isn't large enough. ! 599: */ ! 600: if (receiver->ith_rcv_option & MACH_RCV_LARGE) { ! 601: receiver->ith_msize = kmsg->ikm_header.msgh_size; ! 602: thread_go(receiver); ! 603: continue; ! 604: } ! 605: } ! 606: else ! 607: receiver->ith_state = MACH_MSG_SUCCESS; ! 608: ! 609: /* ! 610: * Got a valid receiver. Possibly with an error. ! 611: * Hand the receiver the message. ! 612: */ ! 613: receiver->ith_kmsg = kmsg; ! 614: receiver->ith_seqno = port->ip_seqno++; ! 615: imq_unlock(mqueue); ! 616: thread_go(receiver); ! 617: break; ! 618: } ! 619: } ! 620: } ! 621: ! 622: return MACH_MSG_SUCCESS; ! 623: } ! 624: ! 625: mach_msg_return_t ! 626: ipc_mqueue_send_interrupt(kmsg) ! 627: ipc_kmsg_t kmsg; ! 628: { ! 629: ipc_port_t port; ! 630: ! 631: port = (ipc_port_t) kmsg->ikm_header.msgh_remote_port; ! 632: ! 633: if (!ip_lock_try(port)) ! 634: return MACH_MSG_IPC_KERNEL; ! 635: ! 636: if (!ip_active(port)) { ! 637: ip_unlock(port); ! 638: return MACH_SEND_INVALID_DEST; ! 639: } ! 640: ! 641: assert(!(kmsg->ikm_header.msgh_bits & ! 642: (MACH_MSGH_BITS_COMPLEX|MACH_MSGH_BITS_OLD_FORMAT))); ! 643: ! 644: { ! 645: ipc_mqueue_t mqueue; ! 646: ipc_pset_t pset; ! 647: ipc_thread_t receiver; ! 648: ipc_thread_queue_t receivers; ! 649: ! 650: pset = port->ip_pset; ! 651: if (pset == IPS_NULL) ! 652: mqueue = &port->ip_messages; ! 653: else ! 654: mqueue = &pset->ips_messages; ! 655: ! 656: if (!imq_lock_try(mqueue)) { ! 657: ip_unlock(port); ! 658: return MACH_MSG_IPC_KERNEL; ! 659: } ! 660: receivers = &mqueue->imq_threads; ! 661: ! 662: port->ip_msgcount++; ! 663: ! 664: /* ! 665: * Can unlock the port now that the msg queue is locked ! 666: * and we know the port is active. While the msg queue ! 667: * is locked, we have control of the kmsg, so the ref in ! 668: * it for the port is still good. If the msg queue is in ! 669: * a set (dead or alive), then we're OK because the port ! 670: * is still a member of the set and the set won't go away ! 671: * until the port is taken out, which tries to lock the ! 672: * set's msg queue to remove the port's msgs. ! 673: */ ! 674: ! 675: ip_unlock(port); ! 676: ! 677: /* check for a receiver for the message */ ! 678: ! 679: for (;;) { ! 680: receiver = ipc_thread_queue_first(receivers); ! 681: if (receiver == ITH_NULL) { ! 682: /* no receivers; queue kmsg */ ! 683: ! 684: ipc_kmsg_enqueue_macro(&mqueue->imq_messages, kmsg); ! 685: imq_unlock(mqueue); ! 686: break; ! 687: } ! 688: ! 689: ipc_thread_rmqueue_first_macro(receivers, receiver); ! 690: assert(ipc_kmsg_queue_empty(&mqueue->imq_messages)); ! 691: ! 692: /* ! 693: * Got a potential receiver, verify sizes ! 694: */ ! 695: if (receiver->ith_rcv_option & MACH_RCV_OLD_FORMAT) { ! 696: if ( kmsg->ikm_header.msgh_size > ! 697: sizeof (mach_msg_header_t) || ! 698: receiver->ith_msize < ! 699: sizeof (mach_msg_header_t)) { ! 700: receiver->ith_state = MACH_RCV_HEADER_ERROR; ! 701: receiver->ith_kmsg = kmsg; ! 702: receiver->ith_seqno = port->ip_seqno++; ! 703: imq_unlock(mqueue); ! 704: thread_go(receiver); ! 705: break; ! 706: } ! 707: ! 708: receiver->ith_state = MACH_MSG_SUCCESS; ! 709: } ! 710: else ! 711: if (kmsg->ikm_header.msgh_size > (receiver->ith_msize - ! 712: REQUESTED_TRAILER_SIZE(receiver->ith_rcv_option))) { ! 713: /* ! 714: * The receive buffer isn't large enough ! 715: */ ! 716: receiver->ith_state = MACH_RCV_TOO_LARGE; ! 717: ! 718: if (receiver->ith_rcv_option & MACH_RCV_LARGE) { ! 719: receiver->ith_msize = kmsg->ikm_header.msgh_size; ! 720: thread_go(receiver); ! 721: continue; ! 722: } ! 723: } ! 724: else ! 725: receiver->ith_state = MACH_MSG_SUCCESS; ! 726: ! 727: /* ! 728: * Got a valid receiver. Possibly with an error. ! 729: * Hand the receiver the message. ! 730: */ ! 731: receiver->ith_kmsg = kmsg; ! 732: receiver->ith_seqno = port->ip_seqno++; ! 733: imq_unlock(mqueue); ! 734: thread_go(receiver); ! 735: break; ! 736: } ! 737: } ! 738: ! 739: return MACH_MSG_SUCCESS; ! 740: } ! 741: ! 742: /* ! 743: * Routine: ipc_mqueue_copyin ! 744: * Purpose: ! 745: * Convert a name in a space to a message queue. ! 746: * Conditions: ! 747: * Nothing locked. If successful, the message queue ! 748: * is returned locked and caller gets a ref for the object. ! 749: * This ref ensures the continued existence of the queue. ! 750: * Returns: ! 751: * MACH_MSG_SUCCESS Found a message queue. ! 752: * MACH_RCV_INVALID_NAME The space is dead. ! 753: * MACH_RCV_INVALID_NAME The name doesn't denote a right. ! 754: * MACH_RCV_INVALID_NAME ! 755: * The denoted right is not receive or port set. ! 756: * MACH_RCV_IN_SET Receive right is a member of a set. ! 757: */ ! 758: ! 759: mach_msg_return_t ! 760: ipc_mqueue_copyin( ! 761: ipc_space_t space, ! 762: mach_port_t name, ! 763: ipc_mqueue_t *mqueuep, ! 764: ipc_object_t *objectp) ! 765: { ! 766: ipc_entry_t entry; ! 767: ipc_entry_bits_t bits; ! 768: ipc_object_t object; ! 769: ipc_mqueue_t mqueue; ! 770: ! 771: is_read_lock(space); ! 772: if (!space->is_active) { ! 773: is_read_unlock(space); ! 774: return MACH_RCV_INVALID_NAME; ! 775: } ! 776: ! 777: entry = ipc_entry_lookup(space, name); ! 778: if (entry == IE_NULL) { ! 779: is_read_unlock(space); ! 780: return MACH_RCV_INVALID_NAME; ! 781: } ! 782: ! 783: bits = entry->ie_bits; ! 784: object = entry->ie_object; ! 785: ! 786: if (bits & MACH_PORT_TYPE_RECEIVE) { ! 787: ipc_port_t port; ! 788: ipc_pset_t pset; ! 789: ! 790: port = (ipc_port_t) object; ! 791: assert(port != IP_NULL); ! 792: ! 793: ip_lock(port); ! 794: assert(ip_active(port)); ! 795: assert(port->ip_receiver_name == name); ! 796: assert(port->ip_receiver == space); ! 797: is_read_unlock(space); ! 798: ! 799: pset = port->ip_pset; ! 800: if (pset != IPS_NULL) { ! 801: ips_lock(pset); ! 802: if (ips_active(pset)) { ! 803: ips_unlock(pset); ! 804: ip_unlock(port); ! 805: return MACH_RCV_IN_SET; ! 806: } ! 807: ! 808: ipc_pset_remove(pset, port); ! 809: ips_check_unlock(pset); ! 810: assert(port->ip_pset == IPS_NULL); ! 811: } ! 812: ! 813: mqueue = &port->ip_messages; ! 814: } else if (bits & MACH_PORT_TYPE_PORT_SET) { ! 815: ipc_pset_t pset; ! 816: ! 817: pset = (ipc_pset_t) object; ! 818: assert(pset != IPS_NULL); ! 819: ! 820: ips_lock(pset); ! 821: assert(ips_active(pset)); ! 822: assert(pset->ips_local_name == name); ! 823: is_read_unlock(space); ! 824: ! 825: mqueue = &pset->ips_messages; ! 826: } else { ! 827: is_read_unlock(space); ! 828: return MACH_RCV_INVALID_NAME; ! 829: } ! 830: ! 831: /* ! 832: * At this point, the object is locked and active, ! 833: * the space is unlocked, and mqueue is initialized. ! 834: */ ! 835: ! 836: io_reference(object); ! 837: imq_lock(mqueue); ! 838: io_unlock(object); ! 839: ! 840: *objectp = object; ! 841: *mqueuep = mqueue; ! 842: return MACH_MSG_SUCCESS; ! 843: } ! 844: ! 845: /* ! 846: * Routine: ipc_mqueue_receive ! 847: * Purpose: ! 848: * Receive a message from a message queue. ! 849: * ! 850: * If continuation is non-zero, then we might discard ! 851: * our kernel stack when we block. We will continue ! 852: * after unblocking by executing continuation. ! 853: * ! 854: * If resume is true, then we are resuming a receive ! 855: * operation after a blocked receive discarded our stack. ! 856: * Conditions: ! 857: * The message queue is locked; it is unlocked. ! 858: * ! 859: * Our caller must hold a reference for the port or port set ! 860: * to which this queue belongs, to keep the queue ! 861: * from being deallocated. Furthermore, the port or set ! 862: * must have been active when the queue was locked. ! 863: * ! 864: * The kmsg is returned with clean header fields ! 865: * and with the circular bit turned off. ! 866: * Returns: ! 867: * MACH_MSG_SUCCESS Message returned in kmsgp. ! 868: * MACH_RCV_TOO_LARGE Message size returned in kmsgp. ! 869: * MACH_RCV_TIMED_OUT No message obtained. ! 870: * MACH_RCV_INTERRUPTED No message obtained. ! 871: * MACH_RCV_PORT_DIED Port/set died; no message. ! 872: * MACH_RCV_PORT_CHANGED Port moved into set; no msg. ! 873: */ ! 874: ! 875: mach_msg_return_t ! 876: ipc_mqueue_receive( ! 877: ipc_mqueue_t mqueue, ! 878: mach_msg_option_t option, ! 879: mach_msg_size_t max_size, ! 880: mach_msg_timeout_t timeout, ! 881: boolean_t resume, ! 882: void (*continuation)(void), ! 883: ipc_kmsg_t *kmsgp, ! 884: mach_port_seqno_t *seqnop, ! 885: ipc_kmsg_t *list) ! 886: { ! 887: ipc_port_t port; ! 888: ipc_kmsg_t kmsg; ! 889: mach_port_seqno_t seqno; ! 890: mach_msg_return_t mr; ! 891: ! 892: { ! 893: ipc_kmsg_queue_t kmsgs = &mqueue->imq_messages; ! 894: ipc_thread_t self = current_thread(); ! 895: ! 896: if (resume) ! 897: goto after_thread_block; ! 898: ! 899: for (;;) { ! 900: kmsg = ipc_kmsg_queue_first(kmsgs); ! 901: if (kmsg != IKM_NULL) { ! 902: if (kmsg->ikm_header.msgh_bits & ! 903: MACH_MSGH_BITS_OLD_FORMAT) { ! 904: /* ! 905: * Old format message. (typed data) Verify ! 906: * that one of the old messaging primatives ! 907: * is being used for the receive operation. ! 908: */ ! 909: if (!(option & MACH_RCV_OLD_FORMAT)) { ! 910: self->ith_state = MACH_RCV_HEADER_ERROR; ! 911: ipc_kmsg_rmqueue_first_macro(kmsgs, kmsg); ! 912: port = (ipc_port_t) ! 913: kmsg->ikm_header.msgh_remote_port; ! 914: seqno = port->ip_seqno++; ! 915: break; ! 916: } ! 917: ! 918: /* check space requirements */ ! 919: ! 920: if (kmsg->ikm_header.msgh_size > max_size) { ! 921: * (mach_msg_size_t *) kmsgp = ! 922: kmsg->ikm_header.msgh_size; ! 923: imq_unlock(mqueue); ! 924: return MACH_RCV_TOO_LARGE; ! 925: } ! 926: ! 927: self->ith_state = MACH_MSG_SUCCESS; ! 928: } ! 929: else { ! 930: /* ! 931: * New format message. (untyped data) Verify ! 932: * that one of the new messaging primatives ! 933: * is being used for the receive operation. ! 934: */ ! 935: if (option & MACH_RCV_OLD_FORMAT) { ! 936: if ((kmsg->ikm_header.msgh_bits & ! 937: MACH_MSGH_BITS_COMPLEX) || ! 938: kmsg->ikm_header.msgh_size > ! 939: sizeof (mach_msg_header_t) || ! 940: max_size < ! 941: sizeof (mach_msg_header_t)) { ! 942: self->ith_state = MACH_RCV_HEADER_ERROR; ! 943: ipc_kmsg_rmqueue_first_macro(kmsgs, kmsg); ! 944: port = (ipc_port_t) ! 945: kmsg->ikm_header.msgh_remote_port; ! 946: seqno = port->ip_seqno++; ! 947: break; ! 948: } ! 949: ! 950: self->ith_state = MACH_MSG_SUCCESS; ! 951: } ! 952: else ! 953: /* ! 954: * Verify sizes. ! 955: */ ! 956: if (kmsg->ikm_header.msgh_size > (max_size - ! 957: REQUESTED_TRAILER_SIZE(option))) { ! 958: /* ! 959: * The receive buffer isn't large enough. ! 960: */ ! 961: if (option & MACH_RCV_LARGE) { ! 962: *(mach_msg_size_t *)kmsgp = ! 963: kmsg->ikm_header.msgh_size; ! 964: imq_unlock(mqueue); ! 965: return MACH_RCV_TOO_LARGE; ! 966: } ! 967: ! 968: self->ith_state = MACH_RCV_TOO_LARGE; ! 969: } ! 970: else ! 971: if ((kmsg->ikm_header.msgh_bits & ! 972: MACH_MSGH_BITS_COMPLEX) && ! 973: list && (*list) != IKM_NULL && ! 974: (self->ith_state = ! 975: ipc_kmsg_check_scatter( ! 976: kmsg, option, list)) ! 977: != MACH_MSG_SUCCESS) { ! 978: /* ! 979: * Check for type/VM errors. ! 980: */ ! 981: if (self->ith_state == MACH_RCV_INVALID_TYPE || ! 982: (self->ith_state & MACH_MSG_VM_KERNEL) != 0) { ! 983: imq_unlock(mqueue); ! 984: return self->ith_state; ! 985: } ! 986: ! 987: /* ! 988: * The scatter list isn't large enough. ! 989: */ ! 990: if (option & MACH_RCV_LARGE) { ! 991: *(mach_msg_size_t *)kmsgp = ! 992: kmsg->ikm_header.msgh_size; ! 993: imq_unlock(mqueue); ! 994: return self->ith_state; ! 995: } ! 996: } ! 997: else ! 998: self->ith_state = MACH_MSG_SUCCESS; ! 999: } ! 1000: ! 1001: ipc_kmsg_rmqueue_first_macro(kmsgs, kmsg); ! 1002: port = (ipc_port_t) kmsg->ikm_header.msgh_remote_port; ! 1003: seqno = port->ip_seqno++; ! 1004: break; ! 1005: } ! 1006: ! 1007: /* must block waiting for a message */ ! 1008: ! 1009: if (option & MACH_RCV_TIMEOUT) { ! 1010: if (timeout == 0) { ! 1011: imq_unlock(mqueue); ! 1012: return MACH_RCV_TIMED_OUT; ! 1013: } ! 1014: ! 1015: thread_will_wait_with_timeout(self, timeout); ! 1016: } else ! 1017: thread_will_wait(self); ! 1018: ! 1019: ipc_thread_enqueue_macro(&mqueue->imq_threads, self); ! 1020: self->ith_state = MACH_RCV_IN_PROGRESS; ! 1021: self->ith_msize = max_size; ! 1022: self->ith_rcv_option = option; ! 1023: self->ith_list = list ? *list : IKM_NULL; ! 1024: ! 1025: imq_unlock(mqueue); ! 1026: if (continuation != (void (*)(void)) 0) { ! 1027: counter(c_ipc_mqueue_receive_block_user++); ! 1028: thread_block_with_continuation(continuation); ! 1029: } else { ! 1030: counter(c_ipc_mqueue_receive_block_kernel++); ! 1031: thread_block_with_continuation((void (*)(void)) 0); ! 1032: } ! 1033: after_thread_block: ! 1034: imq_lock(mqueue); ! 1035: if (list) ! 1036: (*list) = self->ith_list; ! 1037: ! 1038: /* why did we wake up? */ ! 1039: ! 1040: if (self->ith_state == MACH_MSG_SUCCESS) { ! 1041: return_kmsg: ! 1042: /* pick up the message that was handed to us */ ! 1043: ! 1044: kmsg = self->ith_kmsg; ! 1045: seqno = self->ith_seqno; ! 1046: port = (ipc_port_t) kmsg->ikm_header.msgh_remote_port; ! 1047: break; ! 1048: } ! 1049: ! 1050: switch (self->ith_state) { ! 1051: case MACH_RCV_INVALID_TYPE: ! 1052: /* bad invalid scatter list */ ! 1053: ! 1054: imq_unlock(mqueue); ! 1055: return self->ith_state; ! 1056: ! 1057: case MACH_RCV_TOO_LARGE: ! 1058: case MACH_RCV_SCATTER_SMALL: ! 1059: /* ! 1060: * The receive buffer isn't large enough or ! 1061: * there is a scatter list and it doesn't match ! 1062: * the gather list. ! 1063: */ ! 1064: if (!(self->ith_rcv_option & ! 1065: (MACH_RCV_LARGE|MACH_RCV_OLD_FORMAT))) ! 1066: goto return_kmsg; ! 1067: ! 1068: *(mach_msg_size_t *) kmsgp = self->ith_msize; ! 1069: ! 1070: /* fall-through */ ! 1071: ! 1072: case MACH_RCV_PORT_DIED: ! 1073: case MACH_RCV_PORT_CHANGED: ! 1074: /* something bad happened to the port/set */ ! 1075: ! 1076: imq_unlock(mqueue); ! 1077: return self->ith_state; ! 1078: ! 1079: case MACH_RCV_IN_PROGRESS: ! 1080: /* ! 1081: * Awakened for other than IPC completion. ! 1082: * Remove ourselves from the waiting queue, ! 1083: * then check the wakeup cause. ! 1084: */ ! 1085: ! 1086: ipc_thread_rmqueue(&mqueue->imq_threads, self); ! 1087: ! 1088: switch (self->ith_wait_result) { ! 1089: case THREAD_INTERRUPTED: ! 1090: case THREAD_SHOULD_TERMINATE: ! 1091: /* receive was interrupted - give up */ ! 1092: ! 1093: imq_unlock(mqueue); ! 1094: return MACH_RCV_INTERRUPTED; ! 1095: ! 1096: case THREAD_TIMED_OUT: ! 1097: /* timeout expired */ ! 1098: ! 1099: assert(option & MACH_RCV_TIMEOUT); ! 1100: timeout = 0; ! 1101: break; ! 1102: ! 1103: case THREAD_RESTART: ! 1104: default: ! 1105: panic("ipc_mqueue_receive"); ! 1106: } ! 1107: break; ! 1108: ! 1109: case MACH_RCV_HEADER_ERROR: ! 1110: /* ! 1111: * There was a message was queued on the ! 1112: * port, but its format was incompatible ! 1113: * with the receive operation we were ! 1114: * performing. ! 1115: */ ! 1116: goto return_kmsg; ! 1117: ! 1118: default: ! 1119: panic("ipc_mqueue_receive: strange ith_state"); ! 1120: } ! 1121: } ! 1122: ! 1123: mr = self->ith_state; ! 1124: ! 1125: /* we have a kmsg; unlock the msg queue */ ! 1126: ! 1127: imq_unlock(mqueue); ! 1128: } ! 1129: ! 1130: { ! 1131: ipc_marequest_t marequest; ! 1132: ! 1133: marequest = kmsg->ikm_marequest; ! 1134: if (marequest != IMAR_NULL) { ! 1135: ipc_marequest_destroy(marequest); ! 1136: kmsg->ikm_marequest = IMAR_NULL; ! 1137: } ! 1138: assert((kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_CIRCULAR) == 0); ! 1139: ! 1140: assert(port == (ipc_port_t) kmsg->ikm_header.msgh_remote_port); ! 1141: ip_lock(port); ! 1142: ! 1143: if (ip_active(port)) { ! 1144: ipc_thread_queue_t senders; ! 1145: ipc_thread_t sender; ! 1146: ! 1147: assert(port->ip_msgcount > 0); ! 1148: port->ip_msgcount--; ! 1149: ! 1150: senders = &port->ip_blocked; ! 1151: sender = ipc_thread_queue_first(senders); ! 1152: ! 1153: if ((sender != ITH_NULL) && ! 1154: (port->ip_msgcount < port->ip_qlimit)) { ! 1155: ipc_thread_rmqueue(senders, sender); ! 1156: sender->ith_state = MACH_MSG_SUCCESS; ! 1157: thread_go(sender); ! 1158: } ! 1159: } ! 1160: ! 1161: ip_unlock(port); ! 1162: } ! 1163: ! 1164: *kmsgp = kmsg; ! 1165: *seqnop = seqno; ! 1166: return mr; ! 1167: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.