|
|
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/mach_msg.c ! 75: * Author: Rich Draves ! 76: * Date: 1989 ! 77: * ! 78: * Exported message traps. See mach/message.h. ! 79: */ ! 80: ! 81: #import <mach/features.h> ! 82: ! 83: #include <mach/kern_return.h> ! 84: #include <mach/port.h> ! 85: #include <mach/message.h> ! 86: #include <kern/assert.h> ! 87: #include <kern/counters.h> ! 88: #include <kern/lock.h> ! 89: #include <kern/sched_prim.h> ! 90: #include <kern/ipc_sched.h> ! 91: #include <vm/vm_map.h> ! 92: #include <ipc/ipc_kmsg.h> ! 93: #include <ipc/ipc_marequest.h> ! 94: #include <ipc/ipc_mqueue.h> ! 95: #include <ipc/ipc_object.h> ! 96: #include <ipc/ipc_notify.h> ! 97: #include <ipc/ipc_port.h> ! 98: #include <ipc/ipc_pset.h> ! 99: #include <ipc/ipc_space.h> ! 100: #include <ipc/ipc_thread.h> ! 101: #include <ipc/ipc_entry.h> ! 102: #include <ipc/mach_msg.h> ! 103: ! 104: /* ! 105: * Forward declarations ! 106: */ ! 107: ! 108: mach_msg_return_t mach_msg_send( ! 109: mach_msg_header_t *msg, ! 110: mach_msg_option_t option, ! 111: mach_msg_size_t send_size, ! 112: mach_msg_timeout_t timeout, ! 113: mach_port_t notify); ! 114: ! 115: mach_msg_return_t mach_msg_receive( ! 116: mach_msg_header_t *msg, ! 117: mach_msg_option_t option, ! 118: mach_msg_size_t rcv_size, ! 119: mach_port_t rcv_name, ! 120: mach_msg_timeout_t timeout, ! 121: mach_port_t notify, ! 122: mach_msg_size_t list_size); ! 123: ! 124: mach_msg_return_t mach_msg_receive_error( ! 125: ipc_kmsg_t kmsg, ! 126: mach_msg_header_t *msg, ! 127: mach_msg_option_t option, ! 128: mach_port_seqno_t seqno, ! 129: ipc_space_t space); ! 130: ! 131: /* the size of each trailer has to be listed here for copyout purposes */ ! 132: vm_size_t trailer_size[] = { ! 133: sizeof (mach_msg_trailer_t), ! 134: sizeof (mach_msg_seqno_trailer_t), ! 135: sizeof (mach_msg_security_trailer_t) ! 136: }; ! 137: ! 138: /* ! 139: * Routine: mach_msg_send ! 140: * Purpose: ! 141: * Send a message. ! 142: * Conditions: ! 143: * Nothing locked. ! 144: * Returns: ! 145: * MACH_MSG_SUCCESS Sent the message. ! 146: * MACH_SEND_MSG_TOO_SMALL Message smaller than a header. ! 147: * MACH_SEND_NO_BUFFER Couldn't allocate buffer. ! 148: * MACH_SEND_INVALID_DATA Couldn't copy message data. ! 149: * MACH_SEND_INVALID_HEADER ! 150: * Illegal value in the message header bits. ! 151: * MACH_SEND_INVALID_DEST The space is dead. ! 152: * MACH_SEND_INVALID_NOTIFY Bad notify port. ! 153: * MACH_SEND_INVALID_DEST Can't copyin destination port. ! 154: * MACH_SEND_INVALID_REPLY Can't copyin reply port. ! 155: * MACH_SEND_TIMED_OUT Timeout expired without delivery. ! 156: * MACH_SEND_INTERRUPTED Delivery interrupted. ! 157: * MACH_SEND_NO_NOTIFY Can't allocate a msg-accepted request. ! 158: * MACH_SEND_WILL_NOTIFY Msg-accepted notif. requested. ! 159: * MACH_SEND_NOTIFY_IN_PROGRESS ! 160: * This space has already forced a message to this port. ! 161: */ ! 162: ! 163: mach_msg_return_t ! 164: mach_msg_send( ! 165: mach_msg_header_t *msg, ! 166: mach_msg_option_t option, ! 167: mach_msg_size_t send_size, ! 168: mach_msg_timeout_t timeout, ! 169: mach_port_t notify) ! 170: { ! 171: ipc_space_t space = current_space(); ! 172: vm_map_t map = current_map(); ! 173: ipc_kmsg_t kmsg; ! 174: mach_msg_return_t mr; ! 175: ! 176: mr = ipc_kmsg_get(msg, option, send_size, MAX_TRAILER_SIZE, &kmsg); ! 177: if (mr != MACH_MSG_SUCCESS) ! 178: return mr; ! 179: ! 180: if (option & MACH_SEND_CANCEL) { ! 181: if (notify == MACH_PORT_NULL) ! 182: mr = MACH_SEND_INVALID_NOTIFY; ! 183: else ! 184: mr = ipc_kmsg_copyin(kmsg, space, map, notify); ! 185: } else ! 186: mr = ipc_kmsg_copyin(kmsg, space, map, MACH_PORT_NULL); ! 187: if (mr != MACH_MSG_SUCCESS) { ! 188: ikm_free(kmsg); ! 189: return mr; ! 190: } ! 191: ! 192: mr = ipc_mqueue_send(kmsg, option & MACH_SEND_TIMEOUT, ! 193: timeout, IMQ_NULL_CONTINUE); ! 194: if (mr != MACH_MSG_SUCCESS) { ! 195: mr |= ipc_kmsg_copyout_pseudo(kmsg, space, map, IKM_NULL); ! 196: ! 197: assert(kmsg->ikm_marequest == IMAR_NULL); ! 198: (void) ipc_kmsg_put(msg, kmsg, kmsg->ikm_header.msgh_size); ! 199: } ! 200: ! 201: return mr; ! 202: } ! 203: ! 204: #define FREE_SCATTER_LIST(l) \ ! 205: MACRO_BEGIN \ ! 206: if((l) != IKM_NULL) { \ ! 207: ikm_free((l)); \ ! 208: } \ ! 209: MACRO_END ! 210: ! 211: /* ! 212: * Routine: mach_msg_receive ! 213: * Purpose: ! 214: * Receive a message. ! 215: * Conditions: ! 216: * Nothing locked. ! 217: * Returns: ! 218: * MACH_MSG_SUCCESS Received a message. ! 219: * MACH_RCV_INVALID_NAME The name doesn't denote a right, ! 220: * or the denoted right is not receive or port set. ! 221: * MACH_RCV_IN_SET Receive right is a member of a set. ! 222: * MACH_RCV_TOO_LARGE Message wouldn't fit into buffer. ! 223: * MACH_RCV_TIMED_OUT Timeout expired without a message. ! 224: * MACH_RCV_INTERRUPTED Reception interrupted. ! 225: * MACH_RCV_PORT_DIED Port/set died while receiving. ! 226: * MACH_RCV_PORT_CHANGED Port moved into set while receiving. ! 227: * MACH_RCV_INVALID_DATA Couldn't copy to user buffer. ! 228: * MACH_RCV_INVALID_NOTIFY Bad notify port. ! 229: * MACH_RCV_HEADER_ERROR ! 230: */ ! 231: ! 232: mach_msg_return_t ! 233: mach_msg_receive( ! 234: mach_msg_header_t *msg, ! 235: mach_msg_option_t option, ! 236: mach_msg_size_t rcv_size, ! 237: mach_port_t rcv_name, ! 238: mach_msg_timeout_t timeout, ! 239: mach_port_t notify, ! 240: mach_msg_size_t list_size) ! 241: { ! 242: ipc_thread_t self = current_thread(); ! 243: ipc_space_t space = current_space(); ! 244: vm_map_t map = current_map(); ! 245: ipc_object_t object; ! 246: ipc_mqueue_t mqueue; ! 247: ipc_kmsg_t kmsg; ! 248: mach_port_seqno_t seqno; ! 249: ipc_kmsg_t list; ! 250: mach_msg_return_t mr; ! 251: mach_msg_trailer_t *trailer; ! 252: ! 253: /* ! 254: * If MACH_RCV_OVERWRITE was specified, both receive_msg (msg) ! 255: * and receive_msg_size (list_size) need to be non NULL. ! 256: */ ! 257: if (option & MACH_RCV_OVERWRITE) { ! 258: if (list_size < sizeof(mach_msg_base_t)) ! 259: return MACH_RCV_SCATTER_SMALL; ! 260: else ! 261: if (ipc_kmsg_get(msg, MACH_MSG_OPTION_NONE, ! 262: list_size, 0, &list) != MACH_MSG_SUCCESS) ! 263: return MACH_RCV_INVALID_DATA; ! 264: ! 265: else ! 266: if ((((mach_msg_base_t *) ! 267: &kmsg->ikm_header)->body.msgh_descriptor_count * ! 268: sizeof (mach_msg_descriptor_t)) + ! 269: sizeof (mach_msg_base_t) > list_size) { ! 270: FREE_SCATTER_LIST(list); ! 271: return MACH_RCV_INVALID_TYPE; ! 272: } ! 273: } ! 274: else ! 275: list = IKM_NULL; ! 276: ! 277: mr = ipc_mqueue_copyin(space, rcv_name, &mqueue, &object); ! 278: if (mr != MACH_MSG_SUCCESS) { ! 279: FREE_SCATTER_LIST(list); ! 280: return mr; ! 281: } ! 282: /* hold ref for object; mqueue is locked */ ! 283: ! 284: /* ! 285: * ipc_mqueue_receive may not return, because if we block ! 286: * then our kernel stack may be discarded. So we save ! 287: * state here for mach_msg_receive_continue to pick up. ! 288: */ ! 289: ! 290: self->ith_msg = msg; ! 291: self->ith_option = option; ! 292: self->ith_rcv_size = rcv_size; ! 293: self->ith_timeout = timeout; ! 294: self->ith_notify = notify; ! 295: self->ith_object = object; ! 296: self->ith_mqueue = mqueue; ! 297: ! 298: mr = ipc_mqueue_receive(mqueue, ! 299: option & (MACH_RCV_TRAILER_MASK| ! 300: MACH_RCV_TIMEOUT| ! 301: MACH_RCV_LARGE), ! 302: rcv_size, timeout, ! 303: FALSE, mach_msg_receive_continue, ! 304: &kmsg, &seqno, &list); ! 305: /* mqueue is unlocked */ ! 306: ipc_object_release(object); ! 307: ! 308: if (mr != MACH_MSG_SUCCESS) { ! 309: if (mr == MACH_RCV_HEADER_ERROR) { ! 310: mach_msg_return_t pr; ! 311: ! 312: pr = mach_msg_receive_error(kmsg, msg, ! 313: option, seqno, space); ! 314: if (pr != MACH_MSG_SUCCESS) ! 315: mr = pr; ! 316: } ! 317: else ! 318: if (mr == MACH_RCV_TOO_LARGE || mr == MACH_RCV_SCATTER_SMALL) { ! 319: if (option & MACH_RCV_LARGE) { ! 320: if (list != IKM_NULL) { ! 321: mach_msg_return_t pr; ! 322: ! 323: list_size = list->ikm_header.msgh_size; ! 324: list->ikm_header.msgh_size = ! 325: (mach_msg_size_t)kmsg; ! 326: pr = ipc_kmsg_put( ! 327: msg, list, list_size); ! 328: if (pr != MACH_MSG_SUCCESS) ! 329: mr = pr; ! 330: } ! 331: else ! 332: if (copyout((char *) &kmsg, ! 333: (char *) &msg->msgh_size, ! 334: sizeof(mach_msg_size_t))) ! 335: mr = MACH_RCV_INVALID_DATA; ! 336: ! 337: return mr; ! 338: } ! 339: else { ! 340: mach_msg_return_t pr; ! 341: ! 342: pr = mach_msg_receive_error(kmsg, msg, ! 343: option, seqno, space); ! 344: if (pr != MACH_MSG_SUCCESS) ! 345: mr = pr; ! 346: } ! 347: } ! 348: ! 349: FREE_SCATTER_LIST(list); ! 350: return mr; ! 351: } ! 352: ! 353: /* ! 354: * Generate requested trailer. ! 355: */ ! 356: trailer = (mach_msg_trailer_t *) ! 357: ((vm_offset_t)&kmsg->ikm_header + ! 358: kmsg->ikm_header.msgh_size); ! 359: ! 360: if (option & MACH_RCV_NO_TRAILER) { ! 361: trailer->msgh_trailer_size = ! 362: trailer->msgh_trailer_type = 0; ! 363: kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_NO_TRAILER; ! 364: } ! 365: else ! 366: if (kmsg->ikm_delta > 0) { ! 367: /* MACH_SEND_TRAILER */; ! 368: } ! 369: else { ! 370: int elements = GET_RCV_ELEMENTS(option); ! 371: #define trailer0 ((mach_msg_format_0_trailer_t *)trailer) ! 372: ! 373: if (elements == MACH_RCV_TRAILER_SENDER) { ! 374: trailer0->msgh_sender = kmsg->ikm_sender; ! 375: trailer0->msgh_seqno = seqno; ! 376: } ! 377: else ! 378: if (elements == MACH_RCV_TRAILER_SEQNO) ! 379: trailer0->msgh_seqno = seqno; ! 380: ! 381: trailer0->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0; ! 382: trailer0->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option); ! 383: #undef trailer0 ! 384: } ! 385: ! 386: if (option & MACH_RCV_NOTIFY) { ! 387: if (notify == MACH_PORT_NULL) ! 388: mr = MACH_RCV_INVALID_NOTIFY; ! 389: else ! 390: mr = ipc_kmsg_copyout(kmsg, space, map, notify, list); ! 391: } else ! 392: mr = ipc_kmsg_copyout(kmsg, space, map, MACH_PORT_NULL, list); ! 393: if (mr != MACH_MSG_SUCCESS) { ! 394: mach_msg_return_t pr; ! 395: ! 396: if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) { ! 397: pr = ipc_kmsg_put(msg, kmsg, ! 398: kmsg->ikm_header.msgh_size + ! 399: trailer->msgh_trailer_size); ! 400: if (pr != MACH_MSG_SUCCESS) ! 401: mr = pr; ! 402: ! 403: } else { ! 404: pr = mach_msg_receive_error(kmsg, msg, ! 405: option, seqno, space); ! 406: if (pr != MACH_MSG_SUCCESS) ! 407: mr = pr; ! 408: } ! 409: ! 410: FREE_SCATTER_LIST(list); ! 411: return mr; ! 412: } ! 413: ! 414: FREE_SCATTER_LIST(list); ! 415: return ipc_kmsg_put(msg, kmsg, ! 416: kmsg->ikm_header.msgh_size + ! 417: trailer->msgh_trailer_size); ! 418: } ! 419: ! 420: /* ! 421: * Routine: mach_msg_receive_continue ! 422: * Purpose: ! 423: * Continue after blocking for a message. ! 424: * Conditions: ! 425: * Nothing locked. We are running on a new kernel stack, ! 426: * with the receive state saved in the thread. From here ! 427: * control goes back to user space. ! 428: */ ! 429: ! 430: void ! 431: mach_msg_receive_continue(void) ! 432: { ! 433: ipc_thread_t self = current_thread(); ! 434: ipc_space_t space = current_space(); ! 435: vm_map_t map = current_map(); ! 436: mach_msg_header_t *msg = self->ith_msg; ! 437: mach_msg_option_t option = self->ith_option; ! 438: mach_msg_trailer_t *trailer; ! 439: ipc_kmsg_t kmsg; ! 440: mach_port_seqno_t seqno; ! 441: ipc_kmsg_t list; ! 442: mach_msg_return_t mr; ! 443: ! 444: mr = ipc_mqueue_receive(self->ith_mqueue, ! 445: option & (MACH_RCV_TRAILER_MASK| ! 446: MACH_RCV_TIMEOUT| ! 447: MACH_RCV_LARGE), ! 448: self->ith_rcv_size, self->ith_timeout, ! 449: TRUE, mach_msg_receive_continue, ! 450: &kmsg, &seqno, &list); ! 451: /* mqueue is unlocked */ ! 452: ipc_object_release(self->ith_object); ! 453: ! 454: if (mr != MACH_MSG_SUCCESS) { ! 455: if (mr == MACH_RCV_HEADER_ERROR) { ! 456: mach_msg_return_t pr; ! 457: ! 458: pr = mach_msg_receive_error(kmsg, msg, ! 459: option, seqno, space); ! 460: if (pr != MACH_MSG_SUCCESS) ! 461: mr = pr; ! 462: } ! 463: else ! 464: if (mr == MACH_RCV_TOO_LARGE || mr == MACH_RCV_SCATTER_SMALL) { ! 465: if (option & MACH_RCV_LARGE) { ! 466: if (list != IKM_NULL) { ! 467: mach_msg_return_t pr; ! 468: mach_msg_size_t list_size; ! 469: ! 470: list_size = list->ikm_header.msgh_size; ! 471: list->ikm_header.msgh_size = ! 472: (mach_msg_size_t)kmsg; ! 473: pr = ipc_kmsg_put( ! 474: msg, list, list_size); ! 475: if (pr != MACH_MSG_SUCCESS) ! 476: mr = pr; ! 477: } ! 478: else ! 479: if (copyout((char *) &kmsg, ! 480: (char *) &msg->msgh_size, ! 481: sizeof(mach_msg_size_t))) ! 482: mr = MACH_RCV_INVALID_DATA; ! 483: ! 484: thread_syscall_return(mr); ! 485: /*NOTREACHED*/ ! 486: } ! 487: else { ! 488: mach_msg_return_t pr; ! 489: ! 490: pr = mach_msg_receive_error(kmsg, msg, ! 491: option, seqno, space); ! 492: if (pr != MACH_MSG_SUCCESS) ! 493: mr = pr; ! 494: } ! 495: } ! 496: ! 497: FREE_SCATTER_LIST(list); ! 498: thread_syscall_return(mr); ! 499: /*NOTREACHED*/ ! 500: } ! 501: ! 502: /* ! 503: * Generate requested trailer. ! 504: */ ! 505: trailer = (mach_msg_trailer_t *) ! 506: ((vm_offset_t)&kmsg->ikm_header + ! 507: kmsg->ikm_header.msgh_size); ! 508: ! 509: if (option & MACH_RCV_NO_TRAILER) { ! 510: trailer->msgh_trailer_size = ! 511: trailer->msgh_trailer_type = 0; ! 512: kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_NO_TRAILER; ! 513: } ! 514: else ! 515: if (kmsg->ikm_delta > 0) { ! 516: /* MACH_SEND_TRAILER */; ! 517: } ! 518: else { ! 519: int elements = GET_RCV_ELEMENTS(option); ! 520: #define trailer0 ((mach_msg_format_0_trailer_t *)trailer) ! 521: ! 522: if (elements == MACH_RCV_TRAILER_SENDER) { ! 523: trailer0->msgh_sender = kmsg->ikm_sender; ! 524: trailer0->msgh_seqno = seqno; ! 525: } ! 526: else ! 527: if (elements == MACH_RCV_TRAILER_SEQNO) ! 528: trailer0->msgh_seqno = seqno; ! 529: ! 530: trailer0->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0; ! 531: trailer0->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option); ! 532: #undef trailer0 ! 533: } ! 534: ! 535: if (option & MACH_RCV_NOTIFY) { ! 536: if (self->ith_notify == MACH_PORT_NULL) ! 537: mr = MACH_RCV_INVALID_NOTIFY; ! 538: else ! 539: mr = ipc_kmsg_copyout( ! 540: kmsg, space, map, ! 541: self->ith_notify, ! 542: self->ith_list); ! 543: } else ! 544: mr = ipc_kmsg_copyout( ! 545: kmsg, space, map, ! 546: MACH_PORT_NULL, ! 547: self->ith_list); ! 548: if (mr != MACH_MSG_SUCCESS) { ! 549: mach_msg_return_t pr; ! 550: ! 551: if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) { ! 552: pr = ipc_kmsg_put(msg, kmsg, ! 553: kmsg->ikm_header.msgh_size + ! 554: trailer->msgh_trailer_size); ! 555: if (pr != MACH_MSG_SUCCESS) ! 556: mr = pr; ! 557: ! 558: } else { ! 559: pr = mach_msg_receive_error(kmsg, msg, ! 560: option, seqno, space); ! 561: if (pr != MACH_MSG_SUCCESS) ! 562: mr = pr; ! 563: } ! 564: ! 565: FREE_SCATTER_LIST(list); ! 566: thread_syscall_return(mr); ! 567: /*NOTREACHED*/ ! 568: } ! 569: ! 570: FREE_SCATTER_LIST(list); ! 571: mr = ipc_kmsg_put(msg, kmsg, ! 572: kmsg->ikm_header.msgh_size + ! 573: trailer->msgh_trailer_size); ! 574: thread_syscall_return(mr); ! 575: /*NOTREACHED*/ ! 576: } ! 577: ! 578: /* ! 579: * Routine: mach_msg_receive_error [internal] ! 580: * Purpose: ! 581: * Builds a minimal header/trailer and copies it to ! 582: * the user message buffer. Invoked when in the case of a ! 583: * MACH_RCV_TOO_LARGE or MACH_RCV_HEADER_ERROR error. ! 584: * Conditions: ! 585: * Nothing locked. ! 586: * Returns: ! 587: * MACH_MSG_SUCCESS minimal headere/trailer copied ! 588: * MACH_RCV_INVALID_DATA copyout to user buffer failed ! 589: */ ! 590: ! 591: mach_msg_return_t ! 592: mach_msg_receive_error( ! 593: ipc_kmsg_t kmsg, ! 594: mach_msg_header_t *msg, ! 595: mach_msg_option_t option, ! 596: mach_port_seqno_t seqno, ! 597: ipc_space_t space) ! 598: { ! 599: mach_msg_trailer_t *trailer; ! 600: ! 601: /* ! 602: * Copy out the destination port in the message. ! 603: * Destroy all other rights and memory in the message. ! 604: */ ! 605: ipc_kmsg_copyout_dest(kmsg, space); ! 606: ! 607: /* ! 608: * Build a minimal message with a null trailer. ! 609: */ ! 610: kmsg->ikm_header.msgh_size = sizeof(mach_msg_header_t); ! 611: trailer = (mach_msg_trailer_t *) ! 612: ((vm_offset_t)&kmsg->ikm_header + ! 613: kmsg->ikm_header.msgh_size); ! 614: ! 615: if (option & MACH_RCV_NO_TRAILER) { ! 616: trailer->msgh_trailer_size = trailer->msgh_trailer_type = 0; ! 617: kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_NO_TRAILER; ! 618: } ! 619: else { ! 620: trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0; ! 621: trailer->msgh_trailer_size = sizeof (mach_msg_trailer_t); ! 622: } ! 623: ! 624: /* ! 625: * Copy the message to user space ! 626: */ ! 627: return ipc_kmsg_put(msg, kmsg, ! 628: kmsg->ikm_header.msgh_size + ! 629: trailer->msgh_trailer_size); ! 630: } ! 631: ! 632: /* ! 633: * Routine: mach_msg_overwrite_trap [mach trap] ! 634: * Purpose: ! 635: * Possibly send a message; possibly receive a message. ! 636: * Conditions: ! 637: * Nothing locked. ! 638: * Returns: ! 639: * All of mach_msg_send and mach_msg_receive error codes. ! 640: */ ! 641: static __inline__ ! 642: mach_msg_return_t ! 643: _mach_msg_overwrite( ! 644: mach_msg_header_t *msg, ! 645: mach_msg_option_t option, ! 646: mach_msg_size_t send_size, ! 647: mach_msg_size_t rcv_size, ! 648: mach_port_t rcv_name, ! 649: mach_msg_timeout_t timeout, ! 650: mach_port_t notify, ! 651: mach_msg_header_t *rcv_msg, ! 652: mach_msg_size_t list_size) ! 653: { ! 654: mach_msg_return_t mr; ! 655: ! 656: if (option & MACH_SEND_MSG) { ! 657: mr = mach_msg_send(msg, option, send_size, ! 658: timeout, notify); ! 659: if (mr != MACH_MSG_SUCCESS) ! 660: return mr; ! 661: } ! 662: ! 663: if (option & MACH_RCV_MSG) { ! 664: mach_msg_header_t *rcv; ! 665: ! 666: /* ! 667: * 1. MACH_RCV_OVERWRITE is on, and rcv_msg is our scatter list ! 668: * and receive buffer ! 669: * 2. MACH_RCV_OVERWRITE is off, and rcv_msg might be the ! 670: * alternate receive buffer (separate send and receive buffers). ! 671: */ ! 672: if (option & MACH_RCV_OVERWRITE) ! 673: rcv = rcv_msg; ! 674: else if (rcv_msg != MACH_MSG_NULL) ! 675: rcv = rcv_msg; ! 676: else ! 677: rcv = msg; ! 678: mr = mach_msg_receive(rcv, option, rcv_size, rcv_name, ! 679: timeout, notify, list_size); ! 680: if (mr != MACH_MSG_SUCCESS) ! 681: return mr; ! 682: } ! 683: ! 684: return MACH_MSG_SUCCESS; ! 685: } ! 686: ! 687: mach_msg_return_t ! 688: mach_msg_overwrite_trap( ! 689: mach_msg_header_t *msg, ! 690: mach_msg_option_t option, ! 691: mach_msg_size_t sndsiz, ! 692: mach_msg_size_t rcvsiz, ! 693: mach_port_t rcvnam, ! 694: mach_msg_timeout_t tout, ! 695: mach_port_t notify, ! 696: mach_msg_header_t *rmsg, ! 697: mach_msg_size_t rmsgsiz) ! 698: { ! 699: return ! 700: ( ! 701: _mach_msg_overwrite( ! 702: msg, option, ! 703: sndsiz, ! 704: rcvsiz, rcvnam, ! 705: tout, notify, ! 706: rmsg, rmsgsiz)); ! 707: } ! 708: ! 709: mach_msg_return_t ! 710: mach_msg_trap( ! 711: mach_msg_header_t *msg, ! 712: mach_msg_option_t option, ! 713: mach_msg_size_t sndsiz, ! 714: mach_msg_size_t rcvsiz, ! 715: mach_port_t rcvnam, ! 716: mach_msg_timeout_t tout, ! 717: mach_port_t notify) ! 718: { ! 719: return ! 720: ( ! 721: _mach_msg_overwrite( ! 722: msg, option, ! 723: sndsiz, ! 724: rcvsiz, rcvnam, ! 725: tout, notify, ! 726: MACH_MSG_NULL, (mach_msg_size_t) 0)); ! 727: } ! 728: ! 729: mach_msg_return_t ! 730: mach_msg_simple_trap( ! 731: mach_msg_header_t *msg, ! 732: mach_msg_option_t option, ! 733: mach_msg_size_t sndsiz, ! 734: mach_msg_size_t rcvsiz, ! 735: mach_port_t rcvnam) ! 736: { ! 737: return ! 738: ( ! 739: _mach_msg_overwrite( ! 740: msg, option, ! 741: sndsiz, ! 742: rcvsiz, rcvnam, ! 743: MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL, ! 744: MACH_MSG_NULL, (mach_msg_size_t) 0)); ! 745: } ! 746: ! 747: /* ! 748: * Routine: mach_msg_interrupt ! 749: * Purpose: ! 750: * Attempts to force a thread waiting at mach_msg_continue or ! 751: * mach_msg_receive_continue into a clean point. Returns TRUE ! 752: * if this was possible. ! 753: * Conditions: ! 754: * Nothing locked. The thread must NOT be runnable. ! 755: */ ! 756: ! 757: boolean_t ! 758: mach_msg_interrupt( ! 759: thread_t thread) ! 760: { ! 761: ipc_mqueue_t mqueue; ! 762: ! 763: assert((thread->swap_func == (void (*)()) mach_msg_continue) || ! 764: (thread->swap_func == (void (*)()) mach_msg_receive_continue)); ! 765: ! 766: mqueue = thread->ith_mqueue; ! 767: imq_lock(mqueue); ! 768: if (thread->ith_state != MACH_RCV_IN_PROGRESS) { ! 769: /* ! 770: * The thread is no longer waiting for a message. ! 771: * It may have a message sitting in ith_kmsg. ! 772: * We can't clean this up. ! 773: */ ! 774: ! 775: imq_unlock(mqueue); ! 776: return FALSE; ! 777: } ! 778: ipc_thread_rmqueue(&mqueue->imq_threads, thread); ! 779: imq_unlock(mqueue); ! 780: ! 781: ipc_object_release(thread->ith_object); ! 782: ! 783: thread_set_syscall_return(thread, MACH_RCV_INTERRUPTED); ! 784: thread->swap_func = thread_exception_return; ! 785: return TRUE; ! 786: } ! 787: ! 788: #if MACH_IPC_COMPAT ! 789: ! 790: /* ! 791: * Routine: msg_return_translate ! 792: * Purpose: ! 793: * Translate from new error code to old error code. ! 794: */ ! 795: ! 796: msg_return_t ! 797: msg_return_translate( ! 798: mach_msg_return_t mr) ! 799: { ! 800: switch (mr &~ MACH_MSG_MASK) { ! 801: case MACH_MSG_SUCCESS: ! 802: return 0; /* SEND_SUCCESS/RCV_SUCCESS/RPC_SUCCESS */ ! 803: ! 804: case MACH_SEND_NO_BUFFER: ! 805: case MACH_SEND_NO_NOTIFY: ! 806: printf("msg_return_translate: %x -> interrupted\n", mr); ! 807: return SEND_INTERRUPTED; ! 808: ! 809: case MACH_SEND_MSG_TOO_SMALL: ! 810: return SEND_MSG_TOO_SMALL; ! 811: case MACH_SEND_INVALID_DATA: ! 812: case MACH_SEND_INVALID_MEMORY: ! 813: return SEND_INVALID_MEMORY; ! 814: case MACH_SEND_TIMED_OUT: ! 815: return SEND_TIMED_OUT; ! 816: case MACH_SEND_INTERRUPTED: ! 817: return SEND_INTERRUPTED; ! 818: case MACH_SEND_INVALID_DEST: ! 819: case MACH_SEND_INVALID_REPLY: ! 820: case MACH_SEND_INVALID_RIGHT: ! 821: case MACH_SEND_INVALID_TYPE: ! 822: return SEND_INVALID_PORT; ! 823: case MACH_SEND_WILL_NOTIFY: ! 824: return SEND_WILL_NOTIFY; ! 825: case MACH_SEND_NOTIFY_IN_PROGRESS: ! 826: return SEND_NOTIFY_IN_PROGRESS; ! 827: ! 828: case MACH_RCV_INVALID_NAME: ! 829: case MACH_RCV_IN_SET: ! 830: case MACH_RCV_PORT_DIED: ! 831: return RCV_INVALID_PORT; ! 832: case MACH_RCV_TOO_LARGE: ! 833: return RCV_TOO_LARGE; ! 834: case MACH_RCV_TIMED_OUT: ! 835: return RCV_TIMED_OUT; ! 836: case MACH_RCV_INTERRUPTED: ! 837: return RCV_INTERRUPTED; ! 838: case MACH_RCV_PORT_CHANGED: ! 839: return RCV_PORT_CHANGE; ! 840: case MACH_RCV_INVALID_DATA: ! 841: return RCV_INVALID_MEMORY; ! 842: ! 843: case MACH_SEND_IN_PROGRESS: ! 844: case MACH_SEND_INVALID_NOTIFY: ! 845: case MACH_SEND_INVALID_HEADER: ! 846: case MACH_RCV_IN_PROGRESS: ! 847: case MACH_RCV_INVALID_NOTIFY: ! 848: case MACH_RCV_HEADER_ERROR: ! 849: case MACH_RCV_BODY_ERROR: ! 850: default: ! 851: panic("msg_return_translate"); ! 852: } ! 853: } ! 854: ! 855: /* ! 856: * Routine: msg_send_trap [mach trap] ! 857: * Purpose: ! 858: * Send a message. ! 859: * Conditions: ! 860: * Nothing locked. ! 861: * Returns: ! 862: */ ! 863: ! 864: msg_return_t ! 865: msg_send_trap( ! 866: msg_header_t *msg, ! 867: msg_option_t option, ! 868: msg_size_t send_size, ! 869: msg_timeout_t timeout) ! 870: { ! 871: ipc_space_t space = current_space(); ! 872: vm_map_t map = current_map(); ! 873: ipc_kmsg_t kmsg; ! 874: integer_t send_delta = send_size; ! 875: mach_msg_return_t mr; ! 876: ! 877: send_size = (send_size + 3) & ~3; /* round up */ ! 878: send_delta -= send_size; ! 879: ! 880: if (send_size > MSG_SIZE_MAX) ! 881: return SEND_MSG_TOO_LARGE; ! 882: ! 883: mr = ipc_kmsg_get((mach_msg_header_t *) msg, MACH_MSG_OPTION_NONE, ! 884: (mach_msg_size_t) send_size, send_delta, ! 885: &kmsg); ! 886: if (mr != MACH_MSG_SUCCESS) ! 887: return msg_return_translate(mr); ! 888: ! 889: mr = ipc_kmsg_copyin_compat(kmsg, space, map); ! 890: if (mr != MACH_MSG_SUCCESS) { ! 891: ikm_free(kmsg); ! 892: return msg_return_translate(mr); ! 893: } ! 894: ! 895: if (option & SEND_NOTIFY) { ! 896: mr = ipc_mqueue_send(kmsg, ! 897: ((option & SEND_SWITCH) ? ! 898: MACH_SEND_SWITCH : ! 899: MACH_MSG_OPTION_NONE) | ! 900: MACH_SEND_TIMEOUT, ! 901: ((option & SEND_TIMEOUT) ? ! 902: (mach_msg_timeout_t) timeout : ! 903: MACH_MSG_TIMEOUT_NONE), ! 904: IMQ_NULL_CONTINUE); ! 905: if (mr == MACH_SEND_TIMED_OUT) { ! 906: ipc_port_t dest = (ipc_port_t) ! 907: kmsg->ikm_header.msgh_remote_port; ! 908: ! 909: mr = ipc_marequest_create(space, dest, MACH_PORT_NULL, ! 910: &kmsg->ikm_marequest); ! 911: if (mr == MACH_MSG_SUCCESS) { ! 912: ipc_mqueue_send_always(kmsg); ! 913: return SEND_WILL_NOTIFY; ! 914: } ! 915: } ! 916: } ! 917: else if (option & SEND_SWITCH) ! 918: mr = ipc_mqueue_send(kmsg, ! 919: ((option & SEND_TIMEOUT) ? ! 920: MACH_SEND_TIMEOUT : ! 921: MACH_MSG_OPTION_NONE) | ! 922: MACH_SEND_SWITCH, ! 923: (mach_msg_timeout_t) timeout, ! 924: msg_send_switch_continue); ! 925: else ! 926: mr = ipc_mqueue_send(kmsg, ! 927: ((option & SEND_TIMEOUT) ? ! 928: MACH_SEND_TIMEOUT : ! 929: MACH_MSG_OPTION_NONE), ! 930: (mach_msg_timeout_t) timeout, ! 931: IMQ_NULL_CONTINUE); ! 932: ! 933: if (mr != MACH_MSG_SUCCESS) ! 934: ipc_kmsg_destroy(kmsg); ! 935: ! 936: return msg_return_translate(mr); ! 937: } ! 938: ! 939: void ! 940: msg_send_switch_continue(void) ! 941: { ! 942: thread_syscall_return(SEND_SUCCESS); ! 943: /*NOTREACHED*/ ! 944: } ! 945: ! 946: mach_msg_return_t ! 947: msg_receive_error( ! 948: ipc_kmsg_t kmsg, ! 949: msg_header_t *msg, ! 950: ipc_space_t space); ! 951: ! 952: /* ! 953: * Routine: msg_receive_trap [mach trap] ! 954: * Purpose: ! 955: * Receive a message. ! 956: * Conditions: ! 957: * Nothing locked. ! 958: * Returns: ! 959: */ ! 960: ! 961: msg_return_t ! 962: msg_receive_trap( ! 963: msg_header_t *msg, ! 964: msg_option_t option, ! 965: msg_size_t rcv_size, ! 966: port_name_t rcv_name, ! 967: msg_timeout_t timeout) ! 968: { ! 969: ipc_thread_t self; ! 970: ipc_space_t space = current_space(); ! 971: vm_map_t map = current_map(); ! 972: ipc_object_t object; ! 973: ipc_mqueue_t mqueue; ! 974: ipc_kmsg_t kmsg; ! 975: mach_port_seqno_t seqno; ! 976: mach_msg_return_t mr; ! 977: ! 978: mr = ipc_mqueue_copyin(space, (mach_port_t) rcv_name, ! 979: &mqueue, &object); ! 980: if (mr != MACH_MSG_SUCCESS) ! 981: return msg_return_translate(mr); ! 982: /* hold ref for object; mqueue is locked */ ! 983: ! 984: /* ! 985: * ipc_mqueue_receive may not return, because if we block ! 986: * then our kernel stack may be discarded. So we save ! 987: * state here for msg_receive_continue to pick up. ! 988: */ ! 989: ! 990: self = current_thread(); ! 991: self->ith_msg = (mach_msg_header_t *) msg; ! 992: self->ith_option = (mach_msg_option_t) option; ! 993: self->ith_rcv_size = (mach_msg_size_t) rcv_size; ! 994: self->ith_timeout = (mach_msg_timeout_t) timeout; ! 995: self->ith_object = object; ! 996: self->ith_mqueue = mqueue; ! 997: ! 998: mr = ipc_mqueue_receive(mqueue, ! 999: ((option & RCV_TIMEOUT) ? ! 1000: MACH_RCV_TIMEOUT : ! 1001: MACH_MSG_OPTION_NONE) | ! 1002: MACH_RCV_OLD_FORMAT, ! 1003: (option & RCV_LARGE) ? ! 1004: (mach_msg_size_t) rcv_size : ! 1005: MACH_MSG_SIZE_MAX, ! 1006: (mach_msg_timeout_t) timeout, ! 1007: FALSE, msg_receive_continue, ! 1008: &kmsg, &seqno, 0); ! 1009: /* mqueue is unlocked */ ! 1010: ipc_object_release(object); ! 1011: ! 1012: if (mr != MACH_MSG_SUCCESS) { ! 1013: if (mr == MACH_RCV_HEADER_ERROR) ! 1014: mr = msg_receive_error(kmsg, msg, space); ! 1015: else ! 1016: if (mr == MACH_RCV_TOO_LARGE) { ! 1017: msg_size_t real_size = ! 1018: (msg_size_t) (mach_msg_size_t) kmsg; ! 1019: ! 1020: assert(real_size > rcv_size); ! 1021: ! 1022: (void) copyout((vm_offset_t) &real_size, ! 1023: (vm_offset_t) &msg->msg_size, ! 1024: sizeof(msg_size_t)); ! 1025: } ! 1026: ! 1027: return msg_return_translate(mr); ! 1028: } ! 1029: ! 1030: if (kmsg->ikm_header.msgh_size > (mach_msg_size_t) rcv_size) { ! 1031: assert(!(option & RCV_LARGE)); ! 1032: ! 1033: ipc_kmsg_destroy(kmsg); ! 1034: return (RCV_TOO_LARGE); ! 1035: } ! 1036: ! 1037: assert(kmsg->ikm_header.msgh_size <= (mach_msg_size_t) rcv_size); ! 1038: ! 1039: mr = ipc_kmsg_copyout_compat(kmsg, space, map); ! 1040: assert(mr == MACH_MSG_SUCCESS); ! 1041: ! 1042: kmsg->ikm_header.msgh_size += kmsg->ikm_delta; ! 1043: mr = ipc_kmsg_put((mach_msg_header_t *) msg, kmsg, ! 1044: kmsg->ikm_header.msgh_size); ! 1045: return msg_return_translate(mr); ! 1046: } ! 1047: ! 1048: /* ! 1049: * Routine: msg_rpc_trap [mach trap] ! 1050: * Purpose: ! 1051: * Send and receive a message. ! 1052: * Conditions: ! 1053: * Nothing locked. ! 1054: * Returns: ! 1055: */ ! 1056: ! 1057: msg_return_t ! 1058: msg_rpc_trap( ! 1059: msg_header_t *msg, ! 1060: msg_option_t option, ! 1061: msg_size_t send_size, ! 1062: msg_size_t rcv_size, ! 1063: msg_timeout_t send_timeout, ! 1064: msg_timeout_t rcv_timeout) ! 1065: { ! 1066: ipc_thread_t self; ! 1067: ipc_space_t space = current_space(); ! 1068: vm_map_t map = current_map(); ! 1069: ipc_port_t reply; ! 1070: ipc_pset_t pset; ! 1071: ipc_mqueue_t mqueue; ! 1072: ipc_kmsg_t kmsg; ! 1073: integer_t send_delta = send_size; ! 1074: mach_port_seqno_t seqno; ! 1075: mach_msg_return_t mr; ! 1076: ! 1077: /* ! 1078: * Instead of using msg_send_trap and msg_receive_trap, ! 1079: * we implement msg_rpc_trap directly. The difference ! 1080: * is how the reply port is handled. Instead of using ! 1081: * ipc_mqueue_copyin, we save a reference for the reply ! 1082: * port carried in the sent message. For example, ! 1083: * consider a rename kernel call which changes the name ! 1084: * of the call's own reply port. This is the behaviour ! 1085: * of the Mach 2.5 msg_rpc_trap. ! 1086: */ ! 1087: ! 1088: send_size = (send_size + 3) & ~3; /* round up */ ! 1089: send_delta -= send_size; ! 1090: ! 1091: if (send_size > MSG_SIZE_MAX) ! 1092: return SEND_MSG_TOO_LARGE; ! 1093: ! 1094: mr = ipc_kmsg_get((mach_msg_header_t *) msg, MACH_MSG_OPTION_NONE, ! 1095: (mach_msg_size_t) send_size, send_delta, ! 1096: &kmsg); ! 1097: if (mr != MACH_MSG_SUCCESS) ! 1098: return msg_return_translate(mr); ! 1099: ! 1100: mr = ipc_kmsg_copyin_compat(kmsg, space, map); ! 1101: if (mr != MACH_MSG_SUCCESS) { ! 1102: ikm_free(kmsg); ! 1103: return msg_return_translate(mr); ! 1104: } ! 1105: ! 1106: reply = (ipc_port_t) kmsg->ikm_header.msgh_local_port; ! 1107: if (IP_VALID(reply)) { ! 1108: ipc_port_t dest = (ipc_port_t) ! 1109: kmsg->ikm_header.msgh_remote_port; ! 1110: ! 1111: ipc_port_reference(reply); ! 1112: assert(IP_VALID(dest)); ! 1113: ! 1114: ip_lock(dest); ! 1115: ! 1116: if (dest->ip_receiver == ipc_space_kernel) { ! 1117: ipc_mqueue_t mqueue; ! 1118: ! 1119: assert(ip_active(dest)); ! 1120: ip_unlock(dest); ! 1121: ! 1122: kmsg = ipc_kobject_server(kmsg); ! 1123: if (kmsg == IKM_NULL) ! 1124: goto receive_reply; ! 1125: ! 1126: ip_lock(reply); ! 1127: ! 1128: if ((!ip_active(reply)) || ! 1129: (reply->ip_receiver != space) || ! 1130: (reply->ip_pset != IPS_NULL) || ! 1131: (rcv_size < (kmsg->ikm_header.msgh_size + ! 1132: kmsg->ikm_delta))) ! 1133: { ! 1134: ip_unlock(reply); ! 1135: ipc_mqueue_send_always(kmsg); ! 1136: goto receive_reply; ! 1137: } ! 1138: ! 1139: mqueue = &reply->ip_messages; ! 1140: imq_lock(mqueue); ! 1141: ! 1142: if ((ipc_thread_queue_first(&mqueue->imq_threads) ! 1143: != ITH_NULL) || ! 1144: (ipc_kmsg_queue_first(&mqueue->imq_messages) ! 1145: != IKM_NULL)) ! 1146: { ! 1147: imq_unlock(mqueue); ! 1148: ip_unlock(reply); ! 1149: ipc_mqueue_send_always(kmsg); ! 1150: goto receive_reply; ! 1151: } ! 1152: ! 1153: assert(kmsg->ikm_marequest == IMAR_NULL); ! 1154: assert(ipc_thread_queue_first(&reply->ip_blocked) ! 1155: == ITH_NULL); ! 1156: ! 1157: reply->ip_seqno++; ! 1158: imq_unlock(mqueue); ! 1159: ! 1160: ip_release(reply); ! 1161: ip_unlock(reply); ! 1162: ! 1163: goto copyout_reply; ! 1164: } ! 1165: ! 1166: ip_unlock(dest); ! 1167: } ! 1168: ! 1169: if (option & SEND_NOTIFY) { ! 1170: mr = ipc_mqueue_send(kmsg, ! 1171: ((option & SEND_SWITCH) ? ! 1172: MACH_SEND_SWITCH : ! 1173: MACH_MSG_OPTION_NONE) | ! 1174: MACH_SEND_TIMEOUT, ! 1175: ((option & SEND_TIMEOUT) ? ! 1176: (mach_msg_timeout_t) send_timeout : ! 1177: MACH_MSG_TIMEOUT_NONE), ! 1178: IMQ_NULL_CONTINUE); ! 1179: if (mr == MACH_SEND_TIMED_OUT) { ! 1180: ipc_port_t dest = (ipc_port_t) ! 1181: kmsg->ikm_header.msgh_remote_port; ! 1182: ! 1183: mr = ipc_marequest_create(space, dest, MACH_PORT_NULL, ! 1184: &kmsg->ikm_marequest); ! 1185: if (mr == MACH_MSG_SUCCESS) { ! 1186: ipc_mqueue_send_always(kmsg); ! 1187: if (IP_VALID(reply)) ! 1188: ipc_port_release(reply); ! 1189: return SEND_WILL_NOTIFY; ! 1190: } ! 1191: } ! 1192: } ! 1193: else if (option & SEND_SWITCH) ! 1194: mr = ipc_mqueue_send(kmsg, ! 1195: ((option & SEND_TIMEOUT) ? ! 1196: MACH_SEND_TIMEOUT : ! 1197: MACH_MSG_OPTION_NONE) | ! 1198: MACH_SEND_SWITCH, ! 1199: (mach_msg_timeout_t) send_timeout, ! 1200: IMQ_NULL_CONTINUE); ! 1201: else ! 1202: mr = ipc_mqueue_send(kmsg, ! 1203: ((option & SEND_TIMEOUT) ? ! 1204: MACH_SEND_TIMEOUT : ! 1205: MACH_MSG_OPTION_NONE), ! 1206: (mach_msg_timeout_t) send_timeout, ! 1207: IMQ_NULL_CONTINUE); ! 1208: ! 1209: if (mr != MACH_MSG_SUCCESS) { ! 1210: ipc_kmsg_destroy(kmsg); ! 1211: if (IP_VALID(reply)) ! 1212: ipc_port_release(reply); ! 1213: return msg_return_translate(mr); ! 1214: } ! 1215: ! 1216: receive_reply: ! 1217: if (!IP_VALID(reply)) ! 1218: return RCV_INVALID_PORT; ! 1219: ! 1220: ip_lock(reply); ! 1221: if (reply->ip_receiver != space) { ! 1222: ip_release(reply); ! 1223: ip_check_unlock(reply); ! 1224: return RCV_INVALID_PORT; ! 1225: } ! 1226: ! 1227: assert(ip_active(reply)); ! 1228: pset = reply->ip_pset; ! 1229: ! 1230: if (pset != IPS_NULL) { ! 1231: ips_lock(pset); ! 1232: if (ips_active(pset)) { ! 1233: ips_unlock(pset); ! 1234: ip_release(reply); ! 1235: ip_unlock(reply); ! 1236: return RCV_INVALID_PORT; ! 1237: } ! 1238: ! 1239: ipc_pset_remove(pset, reply); ! 1240: ips_check_unlock(pset); ! 1241: assert(reply->ip_pset == IPS_NULL); ! 1242: } ! 1243: ! 1244: mqueue = &reply->ip_messages; ! 1245: imq_lock(mqueue); ! 1246: ip_unlock(reply); ! 1247: ! 1248: /* ! 1249: * ipc_mqueue_receive may not return, because if we block ! 1250: * then our kernel stack may be discarded. So we save ! 1251: * state here for msg_receive_continue to pick up. ! 1252: */ ! 1253: ! 1254: self = current_thread(); ! 1255: self->ith_msg = (mach_msg_header_t *) msg; ! 1256: self->ith_option = (mach_msg_option_t) option; ! 1257: self->ith_rcv_size = (mach_msg_size_t) rcv_size; ! 1258: self->ith_timeout = (mach_msg_timeout_t) rcv_timeout; ! 1259: self->ith_object = (ipc_object_t) reply; ! 1260: self->ith_mqueue = mqueue; ! 1261: ! 1262: mr = ipc_mqueue_receive(mqueue, ! 1263: ((option & RCV_TIMEOUT) ? ! 1264: MACH_RCV_TIMEOUT : ! 1265: MACH_MSG_OPTION_NONE) | ! 1266: MACH_RCV_OLD_FORMAT, ! 1267: (option & RCV_LARGE) ? ! 1268: (mach_msg_size_t) rcv_size : ! 1269: MACH_MSG_SIZE_MAX, ! 1270: (mach_msg_timeout_t) rcv_timeout, ! 1271: FALSE, msg_receive_continue, ! 1272: &kmsg, &seqno, 0); ! 1273: /* mqueue is unlocked */ ! 1274: ipc_port_release(reply); ! 1275: ! 1276: if (mr != MACH_MSG_SUCCESS) { ! 1277: if (mr == MACH_RCV_HEADER_ERROR) ! 1278: mr = msg_receive_error(kmsg, msg, space); ! 1279: else ! 1280: if (mr == MACH_RCV_TOO_LARGE) { ! 1281: msg_size_t real_size = ! 1282: (msg_size_t) (mach_msg_size_t) kmsg; ! 1283: ! 1284: assert(real_size > rcv_size); ! 1285: ! 1286: (void) copyout((vm_offset_t) &real_size, ! 1287: (vm_offset_t) &msg->msg_size, ! 1288: sizeof(msg_size_t)); ! 1289: } ! 1290: ! 1291: return msg_return_translate(mr); ! 1292: } ! 1293: ! 1294: if (kmsg->ikm_header.msgh_size > (mach_msg_size_t) rcv_size) { ! 1295: assert(!(option & RCV_LARGE)); ! 1296: ! 1297: ipc_kmsg_destroy(kmsg); ! 1298: return (RCV_TOO_LARGE); ! 1299: } ! 1300: ! 1301: copyout_reply: ! 1302: assert(kmsg->ikm_header.msgh_size <= (mach_msg_size_t) rcv_size); ! 1303: ! 1304: mr = ipc_kmsg_copyout_compat(kmsg, space, map); ! 1305: assert(mr == MACH_MSG_SUCCESS); ! 1306: ! 1307: kmsg->ikm_header.msgh_size += kmsg->ikm_delta; ! 1308: mr = ipc_kmsg_put((mach_msg_header_t *) msg, ! 1309: kmsg, kmsg->ikm_header.msgh_size); ! 1310: return msg_return_translate(mr); ! 1311: } ! 1312: ! 1313: /* ! 1314: * Routine: msg_receive_continue ! 1315: * Purpose: ! 1316: * Continue after blocking for a message. ! 1317: * Conditions: ! 1318: * Nothing locked. We are running on a new kernel stack, ! 1319: * with the receive state saved in the thread. From here ! 1320: * control goes back to user space. ! 1321: */ ! 1322: ! 1323: void ! 1324: msg_receive_continue(void) ! 1325: { ! 1326: ipc_thread_t self = current_thread(); ! 1327: msg_header_t *msg = (msg_header_t *) self->ith_msg; ! 1328: msg_option_t option = (msg_option_t) self->ith_option; ! 1329: ipc_kmsg_t kmsg; ! 1330: mach_port_seqno_t seqno; ! 1331: mach_msg_return_t mr; ! 1332: ! 1333: mr = ipc_mqueue_receive(self->ith_mqueue, ! 1334: ((option & RCV_TIMEOUT) ? ! 1335: MACH_RCV_TIMEOUT : ! 1336: MACH_MSG_OPTION_NONE) | ! 1337: MACH_RCV_OLD_FORMAT, ! 1338: (option & RCV_LARGE) ? ! 1339: self->ith_rcv_size : ! 1340: MACH_MSG_SIZE_MAX, ! 1341: self->ith_timeout, ! 1342: TRUE, msg_receive_continue, ! 1343: &kmsg, &seqno, 0); ! 1344: /* mqueue is unlocked */ ! 1345: ipc_object_release(self->ith_object); ! 1346: ! 1347: if (mr != MACH_MSG_SUCCESS) { ! 1348: if (mr == MACH_RCV_HEADER_ERROR) ! 1349: mr = msg_receive_error(kmsg, msg, current_space()); ! 1350: else ! 1351: if (mr == MACH_RCV_TOO_LARGE) { ! 1352: msg_size_t real_size = ! 1353: (msg_size_t) (mach_msg_size_t) kmsg; ! 1354: ! 1355: assert(real_size > rcv_size); ! 1356: ! 1357: (void) copyout((vm_offset_t) &real_size, ! 1358: (vm_offset_t) &msg->msg_size, ! 1359: sizeof(msg_size_t)); ! 1360: } ! 1361: ! 1362: thread_syscall_return(msg_return_translate(mr)); ! 1363: /*NOTREACHED*/ ! 1364: } ! 1365: ! 1366: if (kmsg->ikm_header.msgh_size > self->ith_rcv_size) { ! 1367: assert(!(option & RCV_LARGE)); ! 1368: ! 1369: ipc_kmsg_destroy(kmsg); ! 1370: thread_syscall_return(RCV_TOO_LARGE); ! 1371: /*NOTREACHED*/ ! 1372: } ! 1373: ! 1374: assert(kmsg->ikm_header.msgh_size <= self->ith_rcv_size); ! 1375: ! 1376: mr = ipc_kmsg_copyout_compat(kmsg, current_space(), current_map()); ! 1377: assert(mr == MACH_MSG_SUCCESS); ! 1378: ! 1379: kmsg->ikm_header.msgh_size += kmsg->ikm_delta; ! 1380: mr = ipc_kmsg_put((mach_msg_header_t *) msg, kmsg, ! 1381: kmsg->ikm_header.msgh_size); ! 1382: thread_syscall_return(msg_return_translate(mr)); ! 1383: /*NOTREACHED*/ ! 1384: } ! 1385: ! 1386: mach_msg_return_t ! 1387: msg_receive_error( ! 1388: ipc_kmsg_t kmsg, ! 1389: msg_header_t *msg, ! 1390: ipc_space_t space) ! 1391: { ! 1392: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits; ! 1393: ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port; ! 1394: mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits); ! 1395: mach_msg_return_t mr; ! 1396: ! 1397: if (IO_VALID(reply)) ! 1398: ipc_object_destroy(reply, reply_type); ! 1399: (ipc_object_t)kmsg->ikm_header.msgh_local_port = IO_NULL; ! 1400: ! 1401: assert(!(mbits & MACH_MSGH_BITS_OLD_FORMAT)); ! 1402: if (mbits & MACH_MSGH_BITS_COMPLEX) { ! 1403: mach_msg_body_t *body; ! 1404: ! 1405: body = (mach_msg_body_t *) (&kmsg->ikm_header + 1); ! 1406: ipc_kmsg_clean_body(kmsg, body->msgh_descriptor_count); ! 1407: } ! 1408: ! 1409: kmsg->ikm_header.msgh_size = sizeof (mach_msg_header_t); ! 1410: kmsg->ikm_header.msgh_reserved = 0; /* copied to msg_type */ ! 1411: mr = ipc_kmsg_copyout_compat(kmsg, space, VM_MAP_NULL); ! 1412: assert(mr == MACH_MSG_SUCCESS); ! 1413: ! 1414: return ipc_kmsg_put((mach_msg_header_t *)msg, kmsg, ! 1415: kmsg->ikm_header.msgh_size); ! 1416: } ! 1417: ! 1418: #endif MACH_IPC_COMPAT
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.