|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1991,1990,1989 Carnegie Mellon University. ! 4: * Copyright (c) 1993,1994 The University of Utah and ! 5: * the Computer Systems Laboratory (CSL). ! 6: * All rights reserved. ! 7: * ! 8: * Permission to use, copy, modify and distribute this software and its ! 9: * documentation is hereby granted, provided that both the copyright ! 10: * notice and this permission notice appear in all copies of the ! 11: * software, derivative works or modified versions, and any portions ! 12: * thereof, and that both notices appear in supporting documentation. ! 13: * ! 14: * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF ! 15: * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY ! 16: * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF ! 17: * THIS SOFTWARE. ! 18: * ! 19: * Carnegie Mellon requests users of this software to return to ! 20: * ! 21: * Software Distribution Coordinator or [email protected] ! 22: * School of Computer Science ! 23: * Carnegie Mellon University ! 24: * Pittsburgh PA 15213-3890 ! 25: * ! 26: * any improvements or extensions that they make and grant Carnegie Mellon ! 27: * the rights to redistribute these changes. ! 28: */ ! 29: /* ! 30: * File: ipc/ipc_mqueue.c ! 31: * Author: Rich Draves ! 32: * Date: 1989 ! 33: * ! 34: * Functions to manipulate IPC message queues. ! 35: */ ! 36: ! 37: #include <norma_ipc.h> ! 38: ! 39: #include <mach/port.h> ! 40: #include <mach/message.h> ! 41: #include <kern/assert.h> ! 42: #include <kern/counters.h> ! 43: #include <kern/sched_prim.h> ! 44: #include <kern/ipc_sched.h> ! 45: #include <kern/ipc_kobject.h> ! 46: #include <ipc/ipc_mqueue.h> ! 47: #include <ipc/ipc_thread.h> ! 48: #include <ipc/ipc_kmsg.h> ! 49: #include <ipc/ipc_port.h> ! 50: #include <ipc/ipc_pset.h> ! 51: #include <ipc/ipc_space.h> ! 52: #include <ipc/ipc_marequest.h> ! 53: ! 54: ! 55: ! 56: #if NORMA_IPC ! 57: extern ipc_mqueue_t norma_ipc_handoff_mqueue; ! 58: extern ipc_kmsg_t norma_ipc_handoff_msg; ! 59: extern mach_msg_size_t norma_ipc_handoff_max_size; ! 60: extern mach_msg_size_t norma_ipc_handoff_msg_size; ! 61: extern ipc_kmsg_t norma_ipc_kmsg_accept(); ! 62: #endif /* NORMA_IPC */ ! 63: ! 64: /* ! 65: * Routine: ipc_mqueue_init ! 66: * Purpose: ! 67: * Initialize a newly-allocated message queue. ! 68: */ ! 69: ! 70: void ! 71: ipc_mqueue_init( ! 72: ipc_mqueue_t mqueue) ! 73: { ! 74: imq_lock_init(mqueue); ! 75: ipc_kmsg_queue_init(&mqueue->imq_messages); ! 76: ipc_thread_queue_init(&mqueue->imq_threads); ! 77: } ! 78: ! 79: /* ! 80: * Routine: ipc_mqueue_move ! 81: * Purpose: ! 82: * Move messages from one queue (source) to another (dest). ! 83: * Only moves messages sent to the specified port. ! 84: * Conditions: ! 85: * Both queues must be locked. ! 86: * (This is sufficient to manipulate port->ip_seqno.) ! 87: */ ! 88: ! 89: void ! 90: ipc_mqueue_move( ! 91: ipc_mqueue_t dest, ! 92: ipc_mqueue_t source, ! 93: ipc_port_t port) ! 94: { ! 95: ipc_kmsg_queue_t oldq, newq; ! 96: ipc_thread_queue_t blockedq; ! 97: ipc_kmsg_t kmsg, next; ! 98: ipc_thread_t th; ! 99: ! 100: oldq = &source->imq_messages; ! 101: newq = &dest->imq_messages; ! 102: blockedq = &dest->imq_threads; ! 103: ! 104: for (kmsg = ipc_kmsg_queue_first(oldq); ! 105: kmsg != IKM_NULL; kmsg = next) { ! 106: next = ipc_kmsg_queue_next(oldq, kmsg); ! 107: ! 108: /* only move messages sent to port */ ! 109: ! 110: if (kmsg->ikm_header.msgh_remote_port != (mach_port_t) port) ! 111: continue; ! 112: ! 113: ipc_kmsg_rmqueue(oldq, kmsg); ! 114: ! 115: /* before adding kmsg to newq, check for a blocked receiver */ ! 116: ! 117: while ((th = ipc_thread_dequeue(blockedq)) != ITH_NULL) { ! 118: assert(ipc_kmsg_queue_empty(newq)); ! 119: ! 120: thread_go(th); ! 121: ! 122: /* check if the receiver can handle the message */ ! 123: ! 124: if (kmsg->ikm_header.msgh_size <= th->ith_msize) { ! 125: th->ith_state = MACH_MSG_SUCCESS; ! 126: th->ith_kmsg = kmsg; ! 127: th->ith_seqno = port->ip_seqno++; ! 128: ! 129: goto next_kmsg; ! 130: } ! 131: ! 132: th->ith_state = MACH_RCV_TOO_LARGE; ! 133: th->ith_msize = kmsg->ikm_header.msgh_size; ! 134: } ! 135: ! 136: /* didn't find a receiver to handle the message */ ! 137: ! 138: ipc_kmsg_enqueue(newq, kmsg); ! 139: next_kmsg:; ! 140: } ! 141: } ! 142: ! 143: /* ! 144: * Routine: ipc_mqueue_changed ! 145: * Purpose: ! 146: * Wake up receivers waiting in a message queue. ! 147: * Conditions: ! 148: * The message queue is locked. ! 149: */ ! 150: ! 151: void ! 152: ipc_mqueue_changed( ! 153: ipc_mqueue_t mqueue, ! 154: mach_msg_return_t mr) ! 155: { ! 156: ipc_thread_t th; ! 157: ! 158: while ((th = ipc_thread_dequeue(&mqueue->imq_threads)) != ITH_NULL) { ! 159: th->ith_state = mr; ! 160: thread_go(th); ! 161: } ! 162: } ! 163: ! 164: /* ! 165: * Routine: ipc_mqueue_send ! 166: * Purpose: ! 167: * Send a message to a port. The message holds a reference ! 168: * for the destination port in the msgh_remote_port field. ! 169: * ! 170: * If unsuccessful, the caller still has possession of ! 171: * the message and must do something with it. If successful, ! 172: * the message is queued, given to a receiver, destroyed, ! 173: * or handled directly by the kernel via mach_msg. ! 174: * Conditions: ! 175: * Nothing locked. ! 176: * Returns: ! 177: * MACH_MSG_SUCCESS The message was accepted. ! 178: * MACH_SEND_TIMED_OUT Caller still has message. ! 179: * MACH_SEND_INTERRUPTED Caller still has message. ! 180: */ ! 181: ! 182: mach_msg_return_t ! 183: ipc_mqueue_send(kmsg, option, time_out) ! 184: ipc_kmsg_t kmsg; ! 185: mach_msg_option_t option; ! 186: mach_msg_timeout_t time_out; ! 187: { ! 188: ipc_port_t port; ! 189: ! 190: port = (ipc_port_t) kmsg->ikm_header.msgh_remote_port; ! 191: assert(IP_VALID(port)); ! 192: ! 193: ip_lock(port); ! 194: ! 195: if (port->ip_receiver == ipc_space_kernel) { ! 196: ipc_kmsg_t reply; ! 197: ! 198: /* ! 199: * We can check ip_receiver == ipc_space_kernel ! 200: * before checking that the port is active because ! 201: * ipc_port_dealloc_kernel clears ip_receiver ! 202: * before destroying a kernel port. ! 203: */ ! 204: ! 205: assert(ip_active(port)); ! 206: ip_unlock(port); ! 207: ! 208: reply = ipc_kobject_server(kmsg); ! 209: if (reply != IKM_NULL) ! 210: ipc_mqueue_send_always(reply); ! 211: ! 212: return MACH_MSG_SUCCESS; ! 213: } ! 214: ! 215: #if NORMA_IPC ! 216: if (IP_NORMA_IS_PROXY(port)) { ! 217: mach_msg_return_t mr; ! 218: ! 219: mr = norma_ipc_send(kmsg); ! 220: ip_unlock(port); ! 221: return mr; ! 222: } ! 223: #endif /* NORMA_IPC */ ! 224: ! 225: for (;;) { ! 226: ipc_thread_t self; ! 227: ! 228: /* ! 229: * Can't deliver to a dead port. ! 230: * However, we can pretend it got sent ! 231: * and was then immediately destroyed. ! 232: */ ! 233: ! 234: if (!ip_active(port)) { ! 235: /* ! 236: * We can't let ipc_kmsg_destroy deallocate ! 237: * the port right, because we might end up ! 238: * in an infinite loop trying to deliver ! 239: * a send-once notification. ! 240: */ ! 241: ! 242: ip_release(port); ! 243: ip_check_unlock(port); ! 244: kmsg->ikm_header.msgh_remote_port = MACH_PORT_NULL; ! 245: #if NORMA_IPC ! 246: /* XXX until ipc_kmsg_destroy is fixed... */ ! 247: norma_ipc_finish_receiving(&kmsg); ! 248: #endif /* NORMA_IPC */ ! 249: ipc_kmsg_destroy(kmsg); ! 250: return MACH_MSG_SUCCESS; ! 251: } ! 252: ! 253: /* ! 254: * Don't block if: ! 255: * 1) We're under the queue limit. ! 256: * 2) Caller used the MACH_SEND_ALWAYS internal option. ! 257: * 3) Message is sent to a send-once right. ! 258: */ ! 259: ! 260: if ((port->ip_msgcount < port->ip_qlimit) || ! 261: (option & MACH_SEND_ALWAYS) || ! 262: (MACH_MSGH_BITS_REMOTE(kmsg->ikm_header.msgh_bits) == ! 263: MACH_MSG_TYPE_PORT_SEND_ONCE)) ! 264: break; ! 265: ! 266: /* must block waiting for queue to clear */ ! 267: ! 268: self = current_thread(); ! 269: ! 270: if (option & MACH_SEND_TIMEOUT) { ! 271: if (time_out == 0) { ! 272: ip_unlock(port); ! 273: return MACH_SEND_TIMED_OUT; ! 274: } ! 275: ! 276: thread_will_wait_with_timeout(self, time_out); ! 277: } else ! 278: thread_will_wait(self); ! 279: ! 280: ipc_thread_enqueue(&port->ip_blocked, self); ! 281: self->ith_state = MACH_SEND_IN_PROGRESS; ! 282: ! 283: ip_unlock(port); ! 284: counter(c_ipc_mqueue_send_block++); ! 285: thread_block((void (*)(void)) 0); ! 286: ip_lock(port); ! 287: ! 288: /* why did we wake up? */ ! 289: ! 290: if (self->ith_state == MACH_MSG_SUCCESS) ! 291: continue; ! 292: assert(self->ith_state == MACH_SEND_IN_PROGRESS); ! 293: ! 294: /* take ourselves off blocked queue */ ! 295: ! 296: ipc_thread_rmqueue(&port->ip_blocked, self); ! 297: ! 298: /* ! 299: * Thread wakeup-reason field tells us why ! 300: * the wait was interrupted. ! 301: */ ! 302: ! 303: switch (self->ith_wait_result) { ! 304: case THREAD_INTERRUPTED: ! 305: /* send was interrupted - give up */ ! 306: ! 307: ip_unlock(port); ! 308: return MACH_SEND_INTERRUPTED; ! 309: ! 310: case THREAD_TIMED_OUT: ! 311: /* timeout expired */ ! 312: ! 313: assert(option & MACH_SEND_TIMEOUT); ! 314: time_out = 0; ! 315: break; ! 316: ! 317: case THREAD_RESTART: ! 318: default: ! 319: #if MACH_ASSERT ! 320: assert(!"ipc_mqueue_send"); ! 321: #else ! 322: panic("ipc_mqueue_send"); ! 323: #endif ! 324: } ! 325: } ! 326: ! 327: if (kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_CIRCULAR) { ! 328: ip_unlock(port); ! 329: ! 330: /* don't allow the creation of a circular loop */ ! 331: ! 332: #if NORMA_IPC ! 333: /* XXX until ipc_kmsg_destroy is fixed... */ ! 334: norma_ipc_finish_receiving(&kmsg); ! 335: #endif /* NORMA_IPC */ ! 336: ipc_kmsg_destroy(kmsg); ! 337: return MACH_MSG_SUCCESS; ! 338: } ! 339: ! 340: { ! 341: ipc_mqueue_t mqueue; ! 342: ipc_pset_t pset; ! 343: ipc_thread_t receiver; ! 344: ipc_thread_queue_t receivers; ! 345: ! 346: port->ip_msgcount++; ! 347: assert(port->ip_msgcount > 0); ! 348: ! 349: pset = port->ip_pset; ! 350: if (pset == IPS_NULL) ! 351: mqueue = &port->ip_messages; ! 352: else ! 353: mqueue = &pset->ips_messages; ! 354: ! 355: imq_lock(mqueue); ! 356: receivers = &mqueue->imq_threads; ! 357: ! 358: /* ! 359: * Can unlock the port now that the msg queue is locked ! 360: * and we know the port is active. While the msg queue ! 361: * is locked, we have control of the kmsg, so the ref in ! 362: * it for the port is still good. If the msg queue is in ! 363: * a set (dead or alive), then we're OK because the port ! 364: * is still a member of the set and the set won't go away ! 365: * until the port is taken out, which tries to lock the ! 366: * set's msg queue to remove the port's msgs. ! 367: */ ! 368: ! 369: ip_unlock(port); ! 370: ! 371: /* check for a receiver for the message */ ! 372: ! 373: #if NORMA_IPC ! 374: if (mqueue == norma_ipc_handoff_mqueue) { ! 375: norma_ipc_handoff_msg = kmsg; ! 376: if (kmsg->ikm_header.msgh_size <= norma_ipc_handoff_max_size) { ! 377: imq_unlock(mqueue); ! 378: return MACH_MSG_SUCCESS; ! 379: } ! 380: norma_ipc_handoff_msg_size = kmsg->ikm_header.msgh_size; ! 381: } ! 382: #endif /* NORMA_IPC */ ! 383: for (;;) { ! 384: receiver = ipc_thread_queue_first(receivers); ! 385: if (receiver == ITH_NULL) { ! 386: /* no receivers; queue kmsg */ ! 387: ! 388: ipc_kmsg_enqueue_macro(&mqueue->imq_messages, kmsg); ! 389: imq_unlock(mqueue); ! 390: break; ! 391: } ! 392: ! 393: ipc_thread_rmqueue_first_macro(receivers, receiver); ! 394: assert(ipc_kmsg_queue_empty(&mqueue->imq_messages)); ! 395: ! 396: if (kmsg->ikm_header.msgh_size <= receiver->ith_msize) { ! 397: /* got a successful receiver */ ! 398: ! 399: receiver->ith_state = MACH_MSG_SUCCESS; ! 400: receiver->ith_kmsg = kmsg; ! 401: receiver->ith_seqno = port->ip_seqno++; ! 402: imq_unlock(mqueue); ! 403: ! 404: thread_go(receiver); ! 405: break; ! 406: } ! 407: ! 408: receiver->ith_state = MACH_RCV_TOO_LARGE; ! 409: receiver->ith_msize = kmsg->ikm_header.msgh_size; ! 410: thread_go(receiver); ! 411: } ! 412: } ! 413: ! 414: return MACH_MSG_SUCCESS; ! 415: } ! 416: ! 417: /* ! 418: * Routine: ipc_mqueue_copyin ! 419: * Purpose: ! 420: * Convert a name in a space to a message queue. ! 421: * Conditions: ! 422: * Nothing locked. If successful, the message queue ! 423: * is returned locked and caller gets a ref for the object. ! 424: * This ref ensures the continued existence of the queue. ! 425: * Returns: ! 426: * MACH_MSG_SUCCESS Found a message queue. ! 427: * MACH_RCV_INVALID_NAME The space is dead. ! 428: * MACH_RCV_INVALID_NAME The name doesn't denote a right. ! 429: * MACH_RCV_INVALID_NAME ! 430: * The denoted right is not receive or port set. ! 431: * MACH_RCV_IN_SET Receive right is a member of a set. ! 432: */ ! 433: ! 434: mach_msg_return_t ! 435: ipc_mqueue_copyin( ! 436: ipc_space_t space, ! 437: mach_port_t name, ! 438: ipc_mqueue_t *mqueuep, ! 439: ipc_object_t *objectp) ! 440: { ! 441: ipc_entry_t entry; ! 442: ipc_entry_bits_t bits; ! 443: ipc_object_t object; ! 444: ipc_mqueue_t mqueue; ! 445: ! 446: is_read_lock(space); ! 447: if (!space->is_active) { ! 448: is_read_unlock(space); ! 449: return MACH_RCV_INVALID_NAME; ! 450: } ! 451: ! 452: entry = ipc_entry_lookup(space, name); ! 453: if (entry == IE_NULL) { ! 454: is_read_unlock(space); ! 455: return MACH_RCV_INVALID_NAME; ! 456: } ! 457: ! 458: bits = entry->ie_bits; ! 459: object = entry->ie_object; ! 460: ! 461: if (bits & MACH_PORT_TYPE_RECEIVE) { ! 462: ipc_port_t port; ! 463: ipc_pset_t pset; ! 464: ! 465: port = (ipc_port_t) object; ! 466: assert(port != IP_NULL); ! 467: ! 468: ip_lock(port); ! 469: assert(ip_active(port)); ! 470: assert(port->ip_receiver_name == name); ! 471: assert(port->ip_receiver == space); ! 472: is_read_unlock(space); ! 473: ! 474: pset = port->ip_pset; ! 475: if (pset != IPS_NULL) { ! 476: ips_lock(pset); ! 477: if (ips_active(pset)) { ! 478: ips_unlock(pset); ! 479: ip_unlock(port); ! 480: return MACH_RCV_IN_SET; ! 481: } ! 482: ! 483: ipc_pset_remove(pset, port); ! 484: ips_check_unlock(pset); ! 485: assert(port->ip_pset == IPS_NULL); ! 486: } ! 487: ! 488: mqueue = &port->ip_messages; ! 489: } else if (bits & MACH_PORT_TYPE_PORT_SET) { ! 490: ipc_pset_t pset; ! 491: ! 492: pset = (ipc_pset_t) object; ! 493: assert(pset != IPS_NULL); ! 494: ! 495: ips_lock(pset); ! 496: assert(ips_active(pset)); ! 497: assert(pset->ips_local_name == name); ! 498: is_read_unlock(space); ! 499: ! 500: mqueue = &pset->ips_messages; ! 501: } else { ! 502: is_read_unlock(space); ! 503: return MACH_RCV_INVALID_NAME; ! 504: } ! 505: ! 506: /* ! 507: * At this point, the object is locked and active, ! 508: * the space is unlocked, and mqueue is initialized. ! 509: */ ! 510: ! 511: io_reference(object); ! 512: imq_lock(mqueue); ! 513: io_unlock(object); ! 514: ! 515: *objectp = object; ! 516: *mqueuep = mqueue; ! 517: return MACH_MSG_SUCCESS; ! 518: } ! 519: ! 520: /* ! 521: * Routine: ipc_mqueue_receive ! 522: * Purpose: ! 523: * Receive a message from a message queue. ! 524: * ! 525: * If continuation is non-zero, then we might discard ! 526: * our kernel stack when we block. We will continue ! 527: * after unblocking by executing continuation. ! 528: * ! 529: * If resume is true, then we are resuming a receive ! 530: * operation after a blocked receive discarded our stack. ! 531: * Conditions: ! 532: * The message queue is locked; it will be returned unlocked. ! 533: * ! 534: * Our caller must hold a reference for the port or port set ! 535: * to which this queue belongs, to keep the queue ! 536: * from being deallocated. Furthermore, the port or set ! 537: * must have been active when the queue was locked. ! 538: * ! 539: * The kmsg is returned with clean header fields ! 540: * and with the circular bit turned off. ! 541: * Returns: ! 542: * MACH_MSG_SUCCESS Message returned in kmsgp. ! 543: * MACH_RCV_TOO_LARGE Message size returned in kmsgp. ! 544: * MACH_RCV_TIMED_OUT No message obtained. ! 545: * MACH_RCV_INTERRUPTED No message obtained. ! 546: * MACH_RCV_PORT_DIED Port/set died; no message. ! 547: * MACH_RCV_PORT_CHANGED Port moved into set; no msg. ! 548: * ! 549: */ ! 550: ! 551: mach_msg_return_t ! 552: ipc_mqueue_receive( ! 553: ipc_mqueue_t mqueue, ! 554: mach_msg_option_t option, ! 555: mach_msg_size_t max_size, ! 556: mach_msg_timeout_t time_out, ! 557: boolean_t resume, ! 558: void (*continuation)(void), ! 559: ipc_kmsg_t *kmsgp, ! 560: mach_port_seqno_t *seqnop) ! 561: { ! 562: ipc_port_t port; ! 563: ipc_kmsg_t kmsg; ! 564: mach_port_seqno_t seqno; ! 565: ! 566: { ! 567: ipc_kmsg_queue_t kmsgs = &mqueue->imq_messages; ! 568: ipc_thread_t self = current_thread(); ! 569: ! 570: if (resume) ! 571: goto after_thread_block; ! 572: ! 573: for (;;) { ! 574: kmsg = ipc_kmsg_queue_first(kmsgs); ! 575: #if NORMA_IPC ! 576: /* ! 577: * It may be possible to make this work even when a timeout ! 578: * is specified. ! 579: * ! 580: * Netipc_replenish should be moved somewhere else. ! 581: */ ! 582: if (kmsg == IKM_NULL && ! (option & MACH_RCV_TIMEOUT)) { ! 583: netipc_replenish(FALSE); ! 584: *kmsgp = IKM_NULL; ! 585: kmsg = norma_ipc_kmsg_accept(mqueue, max_size, ! 586: (mach_msg_size_t *)kmsgp); ! 587: if (kmsg != IKM_NULL) { ! 588: port = (ipc_port_t) ! 589: kmsg->ikm_header.msgh_remote_port; ! 590: seqno = port->ip_seqno++; ! 591: break; ! 592: } ! 593: if (*kmsgp) { ! 594: imq_unlock(mqueue); ! 595: return MACH_RCV_TOO_LARGE; ! 596: } ! 597: } ! 598: #endif /* NORMA_IPC */ ! 599: if (kmsg != IKM_NULL) { ! 600: /* check space requirements */ ! 601: ! 602: if (kmsg->ikm_header.msgh_size > max_size) { ! 603: * (mach_msg_size_t *) kmsgp = ! 604: kmsg->ikm_header.msgh_size; ! 605: imq_unlock(mqueue); ! 606: return MACH_RCV_TOO_LARGE; ! 607: } ! 608: ! 609: ipc_kmsg_rmqueue_first_macro(kmsgs, kmsg); ! 610: port = (ipc_port_t) kmsg->ikm_header.msgh_remote_port; ! 611: seqno = port->ip_seqno++; ! 612: break; ! 613: } ! 614: ! 615: /* must block waiting for a message */ ! 616: ! 617: if (option & MACH_RCV_TIMEOUT) { ! 618: if (time_out == 0) { ! 619: imq_unlock(mqueue); ! 620: return MACH_RCV_TIMED_OUT; ! 621: } ! 622: ! 623: thread_will_wait_with_timeout(self, time_out); ! 624: } else ! 625: thread_will_wait(self); ! 626: ! 627: ipc_thread_enqueue_macro(&mqueue->imq_threads, self); ! 628: self->ith_state = MACH_RCV_IN_PROGRESS; ! 629: self->ith_msize = max_size; ! 630: ! 631: imq_unlock(mqueue); ! 632: if (continuation != (void (*)(void)) 0) { ! 633: counter(c_ipc_mqueue_receive_block_user++); ! 634: } else { ! 635: counter(c_ipc_mqueue_receive_block_kernel++); ! 636: } ! 637: thread_block(continuation); ! 638: after_thread_block: ! 639: imq_lock(mqueue); ! 640: ! 641: /* why did we wake up? */ ! 642: ! 643: if (self->ith_state == MACH_MSG_SUCCESS) { ! 644: /* pick up the message that was handed to us */ ! 645: ! 646: kmsg = self->ith_kmsg; ! 647: seqno = self->ith_seqno; ! 648: port = (ipc_port_t) kmsg->ikm_header.msgh_remote_port; ! 649: break; ! 650: } ! 651: ! 652: switch (self->ith_state) { ! 653: case MACH_RCV_TOO_LARGE: ! 654: /* pick up size of the too-large message */ ! 655: ! 656: * (mach_msg_size_t *) kmsgp = self->ith_msize; ! 657: /* fall-through */ ! 658: ! 659: case MACH_RCV_PORT_DIED: ! 660: case MACH_RCV_PORT_CHANGED: ! 661: /* something bad happened to the port/set */ ! 662: ! 663: imq_unlock(mqueue); ! 664: return self->ith_state; ! 665: ! 666: case MACH_RCV_IN_PROGRESS: ! 667: /* ! 668: * Awakened for other than IPC completion. ! 669: * Remove ourselves from the waiting queue, ! 670: * then check the wakeup cause. ! 671: */ ! 672: ! 673: ipc_thread_rmqueue(&mqueue->imq_threads, self); ! 674: ! 675: switch (self->ith_wait_result) { ! 676: case THREAD_INTERRUPTED: ! 677: /* receive was interrupted - give up */ ! 678: ! 679: imq_unlock(mqueue); ! 680: return MACH_RCV_INTERRUPTED; ! 681: ! 682: case THREAD_TIMED_OUT: ! 683: /* timeout expired */ ! 684: ! 685: assert(option & MACH_RCV_TIMEOUT); ! 686: time_out = 0; ! 687: break; ! 688: ! 689: case THREAD_RESTART: ! 690: default: ! 691: #if MACH_ASSERT ! 692: assert(!"ipc_mqueue_receive"); ! 693: #else ! 694: panic("ipc_mqueue_receive"); ! 695: #endif ! 696: } ! 697: break; ! 698: ! 699: default: ! 700: #if MACH_ASSERT ! 701: assert(!"ipc_mqueue_receive: strange ith_state"); ! 702: #else ! 703: panic("ipc_mqueue_receive: strange ith_state"); ! 704: #endif ! 705: } ! 706: } ! 707: ! 708: /* we have a kmsg; unlock the msg queue */ ! 709: ! 710: imq_unlock(mqueue); ! 711: assert(kmsg->ikm_header.msgh_size <= max_size); ! 712: } ! 713: ! 714: { ! 715: ipc_marequest_t marequest; ! 716: ! 717: marequest = kmsg->ikm_marequest; ! 718: if (marequest != IMAR_NULL) { ! 719: ipc_marequest_destroy(marequest); ! 720: kmsg->ikm_marequest = IMAR_NULL; ! 721: } ! 722: assert((kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_CIRCULAR) == 0); ! 723: ! 724: assert(port == (ipc_port_t) kmsg->ikm_header.msgh_remote_port); ! 725: ip_lock(port); ! 726: ! 727: if (ip_active(port)) { ! 728: ipc_thread_queue_t senders; ! 729: ipc_thread_t sender; ! 730: ! 731: assert(port->ip_msgcount > 0); ! 732: port->ip_msgcount--; ! 733: ! 734: senders = &port->ip_blocked; ! 735: sender = ipc_thread_queue_first(senders); ! 736: ! 737: if ((sender != ITH_NULL) && ! 738: (port->ip_msgcount < port->ip_qlimit)) { ! 739: ipc_thread_rmqueue(senders, sender); ! 740: sender->ith_state = MACH_MSG_SUCCESS; ! 741: thread_go(sender); ! 742: } ! 743: } ! 744: ! 745: ip_unlock(port); ! 746: } ! 747: ! 748: #if NORMA_IPC ! 749: norma_ipc_finish_receiving(&kmsg); ! 750: #endif /* NORMA_IPC */ ! 751: *kmsgp = kmsg; ! 752: *seqnop = seqno; ! 753: return MACH_MSG_SUCCESS; ! 754: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.