|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * @OSF_COPYRIGHT@ ! 24: */ ! 25: /* ! 26: * Mach Operating System ! 27: * Copyright (c) 1991,1990,1989 Carnegie Mellon University ! 28: * All Rights Reserved. ! 29: * ! 30: * Permission to use, copy, modify and distribute this software and its ! 31: * documentation is hereby granted, provided that both the copyright ! 32: * notice and this permission notice appear in all copies of the ! 33: * software, derivative works or modified versions, and any portions ! 34: * thereof, and that both notices appear in supporting documentation. ! 35: * ! 36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 39: * ! 40: * Carnegie Mellon requests users of this software to return to ! 41: * ! 42: * Software Distribution Coordinator or [email protected] ! 43: * School of Computer Science ! 44: * Carnegie Mellon University ! 45: * Pittsburgh PA 15213-3890 ! 46: * ! 47: * any improvements or extensions that they make and grant Carnegie Mellon ! 48: * the rights to redistribute these changes. ! 49: */ ! 50: /* ! 51: */ ! 52: /* ! 53: * File: ipc/mach_msg.c ! 54: * Author: Rich Draves ! 55: * Date: 1989 ! 56: * ! 57: * Exported message traps. See mach/message.h. ! 58: */ ! 59: ! 60: #include <cpus.h> ! 61: #include <dipc.h> ! 62: #include <mach_rt.h> ! 63: ! 64: #include <mach/kern_return.h> ! 65: #include <mach/port.h> ! 66: #include <mach/message.h> ! 67: #include <mach/mig_errors.h> ! 68: #include <kern/assert.h> ! 69: #include <kern/counters.h> ! 70: #include <kern/cpu_number.h> ! 71: #include <kern/task.h> ! 72: #include <kern/thread.h> ! 73: #include <kern/lock.h> ! 74: #include <kern/sched_prim.h> ! 75: #include <kern/exception.h> ! 76: #include <kern/misc_protos.h> ! 77: #include <vm/vm_map.h> ! 78: #include <ipc/ipc_kmsg.h> ! 79: #include <ipc/ipc_mqueue.h> ! 80: #include <ipc/ipc_object.h> ! 81: #include <ipc/ipc_notify.h> ! 82: #include <ipc/ipc_port.h> ! 83: #include <ipc/ipc_pset.h> ! 84: #include <ipc/ipc_space.h> ! 85: #include <ipc/ipc_entry.h> ! 86: #include <kern/kalloc.h> ! 87: #include <kern/thread_swap.h> ! 88: #include <kern/processor.h> ! 89: #include <kern/rtmalloc.h> ! 90: ! 91: #include <kern/sf.h> ! 92: #include <kern/mk_sp.h> /* JMM - to support handoff hack */ ! 93: ! 94: ! 95: /* ! 96: * Forward declarations ! 97: */ ! 98: ! 99: mach_msg_return_t mach_msg_send( ! 100: mach_msg_header_t *msg, ! 101: mach_msg_option_t option, ! 102: mach_msg_size_t send_size, ! 103: mach_msg_timeout_t timeout, ! 104: mach_port_name_t notify); ! 105: ! 106: mach_msg_return_t mach_msg_receive( ! 107: mach_msg_header_t *msg, ! 108: mach_msg_option_t option, ! 109: mach_msg_size_t rcv_size, ! 110: mach_port_name_t rcv_name, ! 111: mach_msg_timeout_t timeout, ! 112: mach_port_name_t notify, ! 113: mach_msg_size_t slist_size); ! 114: ! 115: mach_msg_return_t msg_receive_error( ! 116: ipc_kmsg_t kmsg, ! 117: mach_msg_header_t *msg, ! 118: mach_msg_option_t option, ! 119: mach_port_seqno_t seqno, ! 120: ipc_space_t space); ! 121: ! 122: /* the size of each trailer has to be listed here for copyout purposes */ ! 123: mach_msg_trailer_size_t trailer_size[] = { ! 124: sizeof(mach_msg_trailer_t), ! 125: sizeof(mach_msg_seqno_trailer_t), ! 126: sizeof(mach_msg_security_trailer_t) }; ! 127: ! 128: security_token_t KERNEL_SECURITY_TOKEN = KERNEL_SECURITY_TOKEN_VALUE; ! 129: ! 130: mach_msg_format_0_trailer_t trailer_template = { ! 131: /* mach_msg_trailer_type_t */ MACH_MSG_TRAILER_FORMAT_0, ! 132: /* mach_msg_trailer_size_t */ MACH_MSG_TRAILER_MINIMUM_SIZE, ! 133: /* mach_port_seqno_t */ 0, ! 134: /* security_token_t */ KERNEL_SECURITY_TOKEN_VALUE ! 135: }; ! 136: ! 137: /* ! 138: * Routine: mach_msg_send ! 139: * Purpose: ! 140: * Send a message. ! 141: * Conditions: ! 142: * Nothing locked. ! 143: * Returns: ! 144: * MACH_MSG_SUCCESS Sent the message. ! 145: * MACH_SEND_MSG_TOO_SMALL Message smaller than a header. ! 146: * MACH_SEND_NO_BUFFER Couldn't allocate buffer. ! 147: * MACH_SEND_INVALID_DATA Couldn't copy message data. ! 148: * MACH_SEND_INVALID_HEADER ! 149: * Illegal value in the message header bits. ! 150: * MACH_SEND_INVALID_DEST The space is dead. ! 151: * MACH_SEND_INVALID_NOTIFY Bad notify port. ! 152: * MACH_SEND_INVALID_DEST Can't copyin destination port. ! 153: * MACH_SEND_INVALID_REPLY Can't copyin reply port. ! 154: * MACH_SEND_TIMED_OUT Timeout expired without delivery. ! 155: * MACH_SEND_INTERRUPTED Delivery interrupted. ! 156: * MACH_SEND_NO_NOTIFY Can't allocate a msg-accepted request. ! 157: * MACH_SEND_WILL_NOTIFY Msg-accepted notif. requested. ! 158: * MACH_SEND_NOTIFY_IN_PROGRESS ! 159: * This space has already forced a message to this port. ! 160: */ ! 161: ! 162: mach_msg_return_t ! 163: mach_msg_send( ! 164: mach_msg_header_t *msg, ! 165: mach_msg_option_t option, ! 166: mach_msg_size_t send_size, ! 167: mach_msg_timeout_t timeout, ! 168: mach_port_name_t notify) ! 169: { ! 170: ipc_space_t space = current_space(); ! 171: vm_map_t map = current_map(); ! 172: ipc_kmsg_t kmsg; ! 173: mach_msg_return_t mr; ! 174: ! 175: mr = ipc_kmsg_get(msg, send_size, &kmsg, space); ! 176: ! 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_kmsg_send(kmsg, option & MACH_SEND_TIMEOUT, timeout); ! 193: ! 194: if (mr != MACH_MSG_SUCCESS) { ! 195: mr |= ipc_kmsg_copyout_pseudo(kmsg, space, map, MACH_MSG_BODY_NULL); ! 196: (void) ipc_kmsg_put(msg, kmsg, kmsg->ikm_header.msgh_size); ! 197: } ! 198: ! 199: return mr; ! 200: } ! 201: ! 202: #define FREE_SCATTER_LIST(s, l, rt) \ ! 203: MACRO_BEGIN \ ! 204: if((s) != MACH_MSG_BODY_NULL) { \ ! 205: KFREE(((vm_offset_t)(s)), (l), rt); \ ! 206: } \ ! 207: MACRO_END ! 208: ! 209: /* ! 210: * Routine: mach_msg_receive ! 211: * Purpose: ! 212: * Receive a message. ! 213: * Conditions: ! 214: * Nothing locked. ! 215: * Returns: ! 216: * MACH_MSG_SUCCESS Received a message. ! 217: * MACH_RCV_INVALID_NAME The name doesn't denote a right, ! 218: * or the denoted right is not receive or port set. ! 219: * MACH_RCV_IN_SET Receive right is a member of a set. ! 220: * MACH_RCV_TOO_LARGE Message wouldn't fit into buffer. ! 221: * MACH_RCV_TIMED_OUT Timeout expired without a message. ! 222: * MACH_RCV_INTERRUPTED Reception interrupted. ! 223: * MACH_RCV_PORT_DIED Port/set died while receiving. ! 224: * MACH_RCV_PORT_CHANGED Port moved into set while receiving. ! 225: * MACH_RCV_INVALID_DATA Couldn't copy to user buffer. ! 226: * MACH_RCV_INVALID_NOTIFY Bad notify port. ! 227: * MACH_RCV_HEADER_ERROR ! 228: */ ! 229: ! 230: mach_msg_return_t ! 231: mach_msg_receive( ! 232: mach_msg_header_t *msg, ! 233: mach_msg_option_t option, ! 234: mach_msg_size_t rcv_size, ! 235: mach_port_name_t rcv_name, ! 236: mach_msg_timeout_t timeout, ! 237: mach_port_name_t notify, ! 238: mach_msg_size_t slist_size) ! 239: { ! 240: thread_t self = current_thread(); ! 241: ipc_space_t space = current_space(); ! 242: vm_map_t map = current_map(); ! 243: ipc_object_t object; ! 244: ipc_mqueue_t mqueue; ! 245: ipc_kmsg_t kmsg; ! 246: mach_port_seqno_t seqno; ! 247: mach_msg_return_t mr; ! 248: mach_msg_body_t *slist; ! 249: mach_msg_format_0_trailer_t *trailer; ! 250: #if MACH_RT ! 251: boolean_t slist_rt; ! 252: #endif /* MACH_RT */ ! 253: ! 254: mr = ipc_mqueue_copyin(space, rcv_name, &mqueue, &object); ! 255: if (mr != MACH_MSG_SUCCESS) { ! 256: return mr; ! 257: } ! 258: /* hold ref for object; mqueue is locked */ ! 259: ! 260: #if MACH_RT ! 261: /* NOTE: This only works for true ports, and not port sets */ ! 262: slist_rt = ipc_object_is_rt(object); ! 263: #endif /* MACH_RT */ ! 264: ! 265: /* ! 266: * If MACH_RCV_OVERWRITE was specified, both receive_msg (msg) ! 267: * and receive_msg_size (slist_size) need to be non NULL. ! 268: */ ! 269: if (option & MACH_RCV_OVERWRITE) { ! 270: if (slist_size < sizeof(mach_msg_base_t)) { ! 271: ipc_object_release(object); ! 272: return MACH_RCV_SCATTER_SMALL; ! 273: } else { ! 274: slist_size -= sizeof(mach_msg_header_t); ! 275: slist = (mach_msg_body_t *)KALLOC(slist_size, slist_rt); ! 276: if (slist == MACH_MSG_BODY_NULL || ! 277: copyin((char *) (msg + 1), (char *)slist, ! 278: slist_size)) { ! 279: ipc_object_release(object); ! 280: return MACH_RCV_INVALID_DATA; ! 281: } ! 282: if ((slist->msgh_descriptor_count* ! 283: sizeof(mach_msg_descriptor_t) ! 284: + sizeof(mach_msg_size_t)) > slist_size) { ! 285: FREE_SCATTER_LIST(slist, slist_size, slist_rt); ! 286: ipc_object_release(object); ! 287: return MACH_RCV_INVALID_TYPE; ! 288: } ! 289: } ! 290: } else { ! 291: slist = MACH_MSG_BODY_NULL; ! 292: } ! 293: ! 294: self->ith_option = option; ! 295: self->ith_scatter_list = slist; ! 296: self->ith_scatter_list_size = slist_size; ! 297: ! 298: mr = ipc_mqueue_receive(mqueue, option, rcv_size, ! 299: timeout, THREAD_ABORTSAFE, ! 300: &kmsg, &seqno); ! 301: ! 302: ipc_object_release(object); ! 303: ! 304: if (mr != MACH_MSG_SUCCESS) { ! 305: ! 306: if (mr == MACH_RCV_TOO_LARGE || mr == MACH_RCV_SCATTER_SMALL) { ! 307: if (option & MACH_RCV_LARGE) { ! 308: /* ! 309: * We need to inform the user-level code that it needs more ! 310: * space. The value for how much space was returned in the ! 311: * kmsg pointer instead of the message (which was left on the ! 312: * queue). ! 313: */ ! 314: if (copyout((char *) &kmsg, ! 315: (char *) &msg->msgh_size, ! 316: sizeof(mach_msg_size_t))) ! 317: mr = MACH_RCV_INVALID_DATA; ! 318: return mr; ! 319: } ! 320: ! 321: if (msg_receive_error(kmsg, msg, option, seqno, space) ! 322: == MACH_RCV_INVALID_DATA) ! 323: mr = MACH_RCV_INVALID_DATA; ! 324: } ! 325: ! 326: FREE_SCATTER_LIST(slist, slist_size, slist_rt); ! 327: return mr; ! 328: } ! 329: ! 330: trailer = (mach_msg_format_0_trailer_t *) ! 331: ((vm_offset_t)&kmsg->ikm_header + ! 332: round_msg(kmsg->ikm_header.msgh_size)); ! 333: if (option & MACH_RCV_TRAILER_MASK) { ! 334: trailer->msgh_seqno = seqno; ! 335: trailer->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option); ! 336: } ! 337: ! 338: if (option & MACH_RCV_NOTIFY) { ! 339: if (notify == MACH_PORT_NULL) ! 340: mr = MACH_RCV_INVALID_NOTIFY; ! 341: else ! 342: mr = ipc_kmsg_copyout(kmsg, space, map, notify, slist); ! 343: } else { ! 344: mr = ipc_kmsg_copyout(kmsg, space, map, MACH_PORT_NULL, slist); ! 345: } ! 346: if (mr != MACH_MSG_SUCCESS) { ! 347: if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) { ! 348: if (ipc_kmsg_put(msg, kmsg, kmsg->ikm_header.msgh_size + ! 349: trailer->msgh_trailer_size) == MACH_RCV_INVALID_DATA) ! 350: mr = MACH_RCV_INVALID_DATA; ! 351: } ! 352: else { ! 353: if (msg_receive_error(kmsg, msg, option, seqno, space) ! 354: == MACH_RCV_INVALID_DATA) ! 355: mr = MACH_RCV_INVALID_DATA; ! 356: } ! 357: ! 358: FREE_SCATTER_LIST(slist, slist_size, slist_rt); ! 359: return mr; ! 360: } ! 361: mr = ipc_kmsg_put(msg, kmsg, ! 362: kmsg->ikm_header.msgh_size + trailer->msgh_trailer_size); ! 363: FREE_SCATTER_LIST(slist, slist_size, slist_rt); ! 364: ! 365: return mr; ! 366: } ! 367: ! 368: ! 369: /* ! 370: * Toggle this to compile the hotpath in/out ! 371: * If compiled in, the run-time toggle "enable_hotpath" below ! 372: * eases testing & debugging ! 373: */ ! 374: #define ENABLE_HOTPATH 1 /* Hacked on for now */ ! 375: ! 376: #ifndef ENABLE_HOTPATH ! 377: #if NCPUS == 1 && !MACH_RT ! 378: #define ENABLE_HOTPATH 1 ! 379: #else /* NCPUS == 1 && !MACH_RT */ ! 380: #define ENABLE_HOTPATH 0 ! 381: #endif /* NCPUS == 1 && !MACH_RT */ ! 382: #endif ! 383: ! 384: #if ENABLE_HOTPATH ! 385: /* ! 386: * These counters allow tracing of hotpath behavior under test loads. ! 387: * A couple key counters are unconditional (see below). ! 388: */ ! 389: #define HOTPATH_DEBUG 0 /* Toggle to include lots of counters */ ! 390: #if HOTPATH_DEBUG ! 391: #define HOT(expr) expr ! 392: ! 393: unsigned int c_mmot_FIRST = 0; /* Unused First Counter */ ! 394: unsigned int c_mmot_combined_S_R = 0; /* hotpath candidates */ ! 395: unsigned int c_mach_msg_trap_switch_fast = 0; /* hotpath successes */ ! 396: unsigned int c_mmot_ikm_cache_miss = 0; /* Reasons to Fall Off: */ ! 397: unsigned int c_mmot_kernel_send = 0; /* kernel server */ ! 398: unsigned int c_mmot_cold_000 = 0; /* see below ... */ ! 399: unsigned int c_mmot_smallsendsize = 0; ! 400: unsigned int c_mmot_oddsendsize = 0; ! 401: unsigned int c_mmot_bigsendsize = 0; ! 402: unsigned int c_mmot_copyinmsg_fail = 0; ! 403: unsigned int c_mmot_g_slow_copyin3 = 0; ! 404: unsigned int c_mmot_cold_006 = 0; ! 405: unsigned int c_mmot_cold_007 = 0; ! 406: unsigned int c_mmot_cold_008 = 0; ! 407: unsigned int c_mmot_cold_009 = 0; ! 408: unsigned int c_mmot_cold_010 = 0; ! 409: unsigned int c_mmot_cold_012 = 0; ! 410: unsigned int c_mmot_cold_013 = 0; ! 411: unsigned int c_mmot_cold_014 = 0; ! 412: unsigned int c_mmot_cold_016 = 0; ! 413: unsigned int c_mmot_cold_018 = 0; ! 414: unsigned int c_mmot_cold_019 = 0; ! 415: unsigned int c_mmot_cold_020 = 0; ! 416: unsigned int c_mmot_cold_021 = 0; ! 417: unsigned int c_mmot_cold_022 = 0; ! 418: unsigned int c_mmot_cold_023 = 0; ! 419: unsigned int c_mmot_cold_024 = 0; ! 420: unsigned int c_mmot_cold_025 = 0; ! 421: unsigned int c_mmot_cold_026 = 0; ! 422: unsigned int c_mmot_cold_027 = 0; ! 423: unsigned int c_mmot_hot_fSR_ok = 0; ! 424: unsigned int c_mmot_cold_029 = 0; ! 425: unsigned int c_mmot_cold_030 = 0; ! 426: unsigned int c_mmot_cold_031 = 0; ! 427: unsigned int c_mmot_cold_032 = 0; ! 428: unsigned int c_mmot_cold_033 = 0; ! 429: unsigned int c_mmot_bad_rcvr = 0; ! 430: unsigned int c_mmot_rcvr_swapped = 0; ! 431: unsigned int c_mmot_rcvr_locked = 0; ! 432: unsigned int c_mmot_rcvr_tswapped = 0; ! 433: unsigned int c_mmot_rcvr_freed = 0; ! 434: unsigned int c_mmot_g_slow_copyout6 = 0; ! 435: unsigned int c_mmot_g_slow_copyout5 = 0; ! 436: unsigned int c_mmot_cold_037 = 0; ! 437: unsigned int c_mmot_cold_038 = 0; ! 438: unsigned int c_mmot_cold_039 = 0; ! 439: unsigned int c_mmot_g_slow_copyout4 = 0; ! 440: unsigned int c_mmot_g_slow_copyout3 = 0; ! 441: unsigned int c_mmot_hot_ok1 = 0; ! 442: unsigned int c_mmot_hot_ok2 = 0; ! 443: unsigned int c_mmot_hot_ok3 = 0; ! 444: unsigned int c_mmot_g_slow_copyout1 = 0; ! 445: unsigned int c_mmot_g_slow_copyout2 = 0; ! 446: unsigned int c_mmot_getback_fast_copyin = 0; ! 447: unsigned int c_mmot_cold_048 = 0; ! 448: unsigned int c_mmot_getback_FastSR = 0; ! 449: unsigned int c_mmot_cold_050 = 0; ! 450: unsigned int c_mmot_cold_051 = 0; ! 451: unsigned int c_mmot_cold_052 = 0; ! 452: unsigned int c_mmot_cold_053 = 0; ! 453: unsigned int c_mmot_fastkernelreply = 0; ! 454: unsigned int c_mmot_cold_055 = 0; ! 455: unsigned int c_mmot_getback_fast_put = 0; ! 456: unsigned int c_mmot_LAST = 0; /* End Marker - Unused */ ! 457: ! 458: void db_mmot_zero_counters(void); /* forward; */ ! 459: void db_mmot_show_counters(void); /* forward; */ ! 460: ! 461: void /* Call from the debugger to clear all counters */ ! 462: db_mmot_zero_counters(void) ! 463: { ! 464: register unsigned int *ip = &c_mmot_FIRST; ! 465: while (ip <= &c_mmot_LAST) ! 466: *ip++ = 0; ! 467: } ! 468: ! 469: void /* Call from the debugger to show all counters */ ! 470: db_mmot_show_counters(void) ! 471: { ! 472: #define xx(str) printf("%s: %d\n", # str, str); ! 473: ! 474: xx(c_mmot_combined_S_R); ! 475: xx(c_mach_msg_trap_switch_fast); ! 476: xx(c_mmot_ikm_cache_miss); ! 477: xx(c_mmot_kernel_send); ! 478: xx(c_mmot_cold_000); ! 479: xx(c_mmot_smallsendsize); ! 480: xx(c_mmot_oddsendsize); ! 481: xx(c_mmot_bigsendsize); ! 482: xx(c_mmot_copyinmsg_fail); ! 483: xx(c_mmot_g_slow_copyin3); ! 484: xx(c_mmot_cold_006); ! 485: xx(c_mmot_cold_007); ! 486: xx(c_mmot_cold_008); ! 487: xx(c_mmot_cold_009); ! 488: xx(c_mmot_cold_010); ! 489: xx(c_mmot_cold_012); ! 490: xx(c_mmot_cold_013); ! 491: xx(c_mmot_cold_014); ! 492: xx(c_mmot_cold_016); ! 493: xx(c_mmot_cold_018); ! 494: xx(c_mmot_cold_019); ! 495: xx(c_mmot_cold_020); ! 496: xx(c_mmot_cold_021); ! 497: xx(c_mmot_cold_022); ! 498: xx(c_mmot_cold_023); ! 499: xx(c_mmot_cold_024); ! 500: xx(c_mmot_cold_025); ! 501: xx(c_mmot_cold_026); ! 502: xx(c_mmot_cold_027); ! 503: xx(c_mmot_hot_fSR_ok); ! 504: xx(c_mmot_cold_029); ! 505: xx(c_mmot_cold_030); ! 506: xx(c_mmot_cold_031); ! 507: xx(c_mmot_cold_032); ! 508: xx(c_mmot_cold_033); ! 509: xx(c_mmot_bad_rcvr); ! 510: xx(c_mmot_rcvr_swapped); ! 511: xx(c_mmot_rcvr_locked); ! 512: xx(c_mmot_rcvr_tswapped); ! 513: xx(c_mmot_rcvr_freed); ! 514: xx(c_mmot_g_slow_copyout6); ! 515: xx(c_mmot_g_slow_copyout5); ! 516: xx(c_mmot_cold_037); ! 517: xx(c_mmot_cold_038); ! 518: xx(c_mmot_cold_039); ! 519: xx(c_mmot_g_slow_copyout4); ! 520: xx(c_mmot_g_slow_copyout3); ! 521: xx(c_mmot_g_slow_copyout1); ! 522: xx(c_mmot_hot_ok3); ! 523: xx(c_mmot_hot_ok2); ! 524: xx(c_mmot_hot_ok1); ! 525: xx(c_mmot_g_slow_copyout2); ! 526: xx(c_mmot_getback_fast_copyin); ! 527: xx(c_mmot_cold_048); ! 528: xx(c_mmot_getback_FastSR); ! 529: xx(c_mmot_cold_050); ! 530: xx(c_mmot_cold_051); ! 531: xx(c_mmot_cold_052); ! 532: xx(c_mmot_cold_053); ! 533: xx(c_mmot_fastkernelreply); ! 534: xx(c_mmot_cold_055); ! 535: xx(c_mmot_getback_fast_put); ! 536: ! 537: #undef xx ! 538: } ! 539: ! 540: #else /* !HOTPATH_DEBUG */ ! 541: ! 542: /* ! 543: * Duplicate just these few so we can always do a quick sanity check ! 544: */ ! 545: unsigned int c_mmot_combined_S_R = 0; /* hotpath candidates */ ! 546: unsigned int c_mach_msg_trap_switch_fast = 0; /* hotpath successes */ ! 547: unsigned int c_mmot_kernel_send = 0; /* kernel server calls */ ! 548: #define HOT(expr) /* no optional counters */ ! 549: ! 550: #endif /* !HOTPATH_DEBUG */ ! 551: ! 552: boolean_t enable_hotpath = TRUE; /* Patchable, just in case ... */ ! 553: #endif /* HOTPATH_ENABLE */ ! 554: ! 555: /* ! 556: * Routine: mach_msg_overwrite_trap [mach trap] ! 557: * Purpose: ! 558: * Possibly send a message; possibly receive a message. ! 559: * Conditions: ! 560: * Nothing locked. ! 561: * Returns: ! 562: * All of mach_msg_send and mach_msg_receive error codes. ! 563: */ ! 564: ! 565: mach_msg_return_t ! 566: mach_msg_overwrite_trap( ! 567: mach_msg_header_t *msg, ! 568: mach_msg_option_t option, ! 569: mach_msg_size_t send_size, ! 570: mach_msg_size_t rcv_size, ! 571: mach_port_name_t rcv_name, ! 572: mach_msg_timeout_t timeout, ! 573: mach_port_name_t notify, ! 574: mach_msg_header_t *rcv_msg, ! 575: mach_msg_size_t scatter_list_size) ! 576: { ! 577: register mach_msg_header_t *hdr; ! 578: mach_msg_return_t mr = MACH_MSG_SUCCESS; ! 579: /* mask out some of the options before entering the hot path */ ! 580: mach_msg_option_t masked_option = ! 581: option & ~(MACH_SEND_TRAILER|MACH_RCV_TRAILER_MASK|MACH_RCV_LARGE); ! 582: int i; ! 583: ! 584: #if ENABLE_HOTPATH ! 585: /* BEGINNING OF HOT PATH */ ! 586: if ((masked_option == (MACH_SEND_MSG|MACH_RCV_MSG)) && enable_hotpath) { ! 587: register thread_t self = current_thread(); ! 588: register mach_msg_format_0_trailer_t *trailer; ! 589: ! 590: ipc_space_t space = current_act()->task->itk_space; ! 591: ipc_kmsg_t kmsg; ! 592: register ipc_port_t dest_port; ! 593: ipc_object_t rcv_object; ! 594: register ipc_mqueue_t rcv_mqueue; ! 595: mach_msg_size_t reply_size; ! 596: ipc_kmsg_t rcv_kmsg; ! 597: ! 598: c_mmot_combined_S_R++; ! 599: self->ith_scatter_list = MACH_MSG_BODY_NULL; ! 600: ! 601: /* ! 602: * This case is divided into ten sections, each ! 603: * with a label. There are five optimized ! 604: * sections and six unoptimized sections, which ! 605: * do the same thing but handle all possible ! 606: * cases and are slower. ! 607: * ! 608: * The five sections for an RPC are ! 609: * 1) Get request message into a buffer. ! 610: * (fast_get or slow_get) ! 611: * 2) Copyin request message and rcv_name. ! 612: * (fast_copyin or slow_copyin) ! 613: * 3) Enqueue request and dequeue reply. ! 614: * (fast_send_receive or ! 615: * slow_send and slow_receive) ! 616: * 4) Copyout reply message. ! 617: * (fast_copyout or slow_copyout) ! 618: * 5) Put reply message to user's buffer. ! 619: * (fast_put or slow_put) ! 620: * ! 621: * Keep the locking hierarchy firmly in mind. ! 622: * (First spaces, then ports, then port sets, ! 623: * then message queues.) Only a non-blocking ! 624: * attempt can be made to acquire locks out of ! 625: * order, or acquire two locks on the same level. ! 626: * Acquiring two locks on the same level will ! 627: * fail if the objects are really the same, ! 628: * unless simple locking is disabled. This is OK, ! 629: * because then the extra unlock does nothing. ! 630: * ! 631: * There are two major reasons these RPCs can't use ! 632: * ipc_thread_switch, and use slow_send/slow_receive: ! 633: * 1) Kernel RPCs. ! 634: * 2) Servers fall behind clients, so ! 635: * client doesn't find a blocked server thread and ! 636: * server finds waiting messages and can't block. ! 637: */ ! 638: ! 639: fast_get: ! 640: /* ! 641: * optimized ipc_kmsg_get ! 642: * ! 643: * No locks, references, or messages held. ! 644: * We must clear ikm_cache before copyinmsg. ! 645: */ ! 646: ! 647: if ((send_size < sizeof(mach_msg_header_t)) || ! 648: (send_size & 3) || ! 649: (send_size > (IKM_SAVED_MSG_SIZE - MAX_TRAILER_SIZE)) || ! 650: !ikm_cache_get(&kmsg)) { ! 651: #if HOTPATH_DEBUG ! 652: if (send_size < sizeof(mach_msg_header_t)) { ! 653: HOT(c_mmot_smallsendsize++); ! 654: } else if (send_size & 3) { ! 655: HOT(c_mmot_oddsendsize++); ! 656: } else if (send_size > ! 657: (IKM_SAVED_MSG_SIZE - MAX_TRAILER_SIZE)) { ! 658: HOT(c_mmot_bigsendsize++); ! 659: } else if (!kmsg) { ! 660: HOT(c_mmot_ikm_cache_miss++); ! 661: } ! 662: #endif ! 663: goto slow_get; ! 664: } ! 665: ! 666: ikm_check_initialized(kmsg, IKM_SAVED_KMSG_SIZE); ! 667: ! 668: hdr = &kmsg->ikm_header; ! 669: if (copyinmsg((char *) msg, (char *) hdr, send_size)) { ! 670: if (kmsg->ikm_size != IKM_SAVED_KMSG_SIZE || ! 671: KMSG_IS_RT(kmsg) || !ikm_cache_put(kmsg)) ! 672: ikm_free(kmsg); ! 673: HOT(c_mmot_copyinmsg_fail++); ! 674: goto slow_get; ! 675: } ! 676: ! 677: hdr->msgh_size = send_size; ! 678: ! 679: /* naturally align the message before tacking on the trailer */ ! 680: trailer = (mach_msg_format_0_trailer_t *) ((vm_offset_t) hdr + ! 681: send_size); ! 682: bcopy((char *)&trailer_template, (char *)trailer, ! 683: sizeof(trailer_template)); ! 684: trailer->msgh_sender = current_act()->task->sec_token; ! 685: ! 686: fast_copyin: ! 687: /* ! 688: * optimized ipc_kmsg_copyin/ipc_mqueue_copyin ! 689: * ! 690: * We have the request message data in kmsg. ! 691: * Must still do copyin, send, receive, etc. ! 692: * ! 693: * If the message isn't simple, we can't combine ! 694: * ipc_kmsg_copyin_header and ipc_mqueue_copyin, ! 695: * because copyin of the message body might ! 696: * affect rcv_name. ! 697: */ ! 698: ! 699: switch (hdr->msgh_bits) { ! 700: case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, ! 701: MACH_MSG_TYPE_MAKE_SEND_ONCE): { ! 702: register ipc_entry_t table; ! 703: register ipc_entry_num_t size; ! 704: register ipc_port_t reply_port; ! 705: ! 706: /* sending a request message */ ! 707: ! 708: { ! 709: register mach_port_index_t index; ! 710: register mach_port_gen_t gen; ! 711: ! 712: { ! 713: register mach_port_name_t reply_name = ! 714: (mach_port_name_t)hdr->msgh_local_port; ! 715: ! 716: if (reply_name != rcv_name) { ! 717: HOT(c_mmot_g_slow_copyin3++); ! 718: goto slow_copyin; ! 719: } ! 720: ! 721: /* optimized ipc_entry_lookup of reply_name */ ! 722: ! 723: index = MACH_PORT_INDEX(reply_name); ! 724: gen = MACH_PORT_GEN(reply_name); ! 725: ! 726: is_read_lock(space); ! 727: assert(space->is_active); ! 728: ! 729: size = space->is_table_size; ! 730: table = space->is_table; ! 731: ! 732: { ! 733: register ipc_entry_t entry; ! 734: register ipc_entry_bits_t bits; ! 735: ! 736: if (index < size) { ! 737: entry = &table[index]; ! 738: bits = entry->ie_bits; ! 739: if (IE_BITS_GEN(bits) != gen || ! 740: (bits & IE_BITS_COLLISION)) { ! 741: entry = IE_NULL; ! 742: } ! 743: } else { ! 744: entry = IE_NULL; ! 745: } ! 746: if (entry == IE_NULL) { ! 747: entry = ipc_entry_lookup(space, reply_name); ! 748: if (entry == IE_NULL) { ! 749: HOT(c_mmot_cold_006++); ! 750: goto abort_request_copyin; ! 751: } ! 752: bits = entry->ie_bits; ! 753: } ! 754: ! 755: /* check type bit */ ! 756: ! 757: if (! (bits & MACH_PORT_TYPE_RECEIVE)) { ! 758: HOT(c_mmot_cold_007++); ! 759: goto abort_request_copyin; ! 760: } ! 761: ! 762: reply_port = (ipc_port_t) entry->ie_object; ! 763: assert(reply_port != IP_NULL); ! 764: } ! 765: } ! 766: } ! 767: ! 768: /* optimized ipc_entry_lookup of dest_name */ ! 769: ! 770: { ! 771: register mach_port_index_t index; ! 772: register mach_port_gen_t gen; ! 773: ! 774: { ! 775: register mach_port_name_t dest_name = ! 776: (mach_port_name_t)hdr->msgh_remote_port; ! 777: ! 778: index = MACH_PORT_INDEX(dest_name); ! 779: gen = MACH_PORT_GEN(dest_name); ! 780: ! 781: { ! 782: register ipc_entry_t entry; ! 783: register ipc_entry_bits_t bits; ! 784: ! 785: if (index < size) { ! 786: entry = &table[index]; ! 787: bits = entry->ie_bits; ! 788: if (IE_BITS_GEN(bits) != gen || ! 789: (bits & IE_BITS_COLLISION)) { ! 790: entry = IE_NULL; ! 791: } ! 792: } else { ! 793: entry = IE_NULL; ! 794: } ! 795: if (entry == IE_NULL) { ! 796: entry = ipc_entry_lookup(space, dest_name); ! 797: if (entry == IE_NULL) { ! 798: HOT(c_mmot_cold_008++); ! 799: goto abort_request_copyin; ! 800: } ! 801: bits = entry->ie_bits; ! 802: } ! 803: ! 804: /* check type bit */ ! 805: ! 806: if (! (bits & MACH_PORT_TYPE_SEND)) { ! 807: HOT(c_mmot_cold_009++); ! 808: goto abort_request_copyin; ! 809: } ! 810: ! 811: assert(IE_BITS_UREFS(bits) > 0); ! 812: ! 813: dest_port = (ipc_port_t) entry->ie_object; ! 814: assert(dest_port != IP_NULL); ! 815: } ! 816: } ! 817: } ! 818: ! 819: /* ! 820: * To do an atomic copyin, need simultaneous ! 821: * locks on both ports and the space. If ! 822: * dest_port == reply_port, and simple locking is ! 823: * enabled, then we will abort. Otherwise it's ! 824: * OK to unlock twice. ! 825: */ ! 826: ! 827: ip_lock(dest_port); ! 828: if (!ip_active(dest_port) || ! 829: !ip_lock_try(reply_port)) { ! 830: ip_unlock(dest_port); ! 831: HOT(c_mmot_cold_010++); ! 832: goto abort_request_copyin; ! 833: } ! 834: is_read_unlock(space); ! 835: ! 836: assert(dest_port->ip_srights > 0); ! 837: dest_port->ip_srights++; ! 838: ip_reference(dest_port); ! 839: ! 840: assert(ip_active(reply_port)); ! 841: assert(reply_port->ip_receiver_name == ! 842: (mach_port_name_t)hdr->msgh_local_port); ! 843: assert(reply_port->ip_receiver == space); ! 844: ! 845: reply_port->ip_sorights++; ! 846: ip_reference(reply_port); ! 847: ! 848: hdr->msgh_bits = ! 849: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, ! 850: MACH_MSG_TYPE_PORT_SEND_ONCE); ! 851: hdr->msgh_remote_port = dest_port; ! 852: hdr->msgh_local_port = reply_port; ! 853: ! 854: /* make sure we can queue to the destination */ ! 855: ! 856: if (dest_port->ip_receiver == ipc_space_kernel) { ! 857: /* ! 858: * The kernel server has a reference to ! 859: * the reply port, which it hands back ! 860: * to us in the reply message. We do ! 861: * not need to keep another reference to ! 862: * it. ! 863: */ ! 864: ip_unlock(reply_port); ! 865: ! 866: assert(ip_active(dest_port)); ! 867: dest_port->ip_messages.imq_seqno++; ! 868: ip_unlock(dest_port); ! 869: goto kernel_send; ! 870: } ! 871: ! 872: if (imq_full(&dest_port->ip_messages)) { ! 873: HOT(c_mmot_cold_013++); ! 874: goto abort_request_send_receive; ! 875: } ! 876: ! 877: /* optimized ipc_mqueue_copyin */ ! 878: ! 879: if (reply_port->ip_pset_count != 0) { ! 880: HOT(c_mmot_cold_014++); ! 881: goto abort_request_send_receive; ! 882: } ! 883: ! 884: rcv_object = (ipc_object_t) reply_port; ! 885: io_reference(rcv_object); ! 886: rcv_mqueue = &reply_port->ip_messages; ! 887: imq_lock(rcv_mqueue); ! 888: io_unlock(rcv_object); ! 889: HOT(c_mmot_hot_fSR_ok++); ! 890: goto fast_send_receive; ! 891: ! 892: abort_request_copyin: ! 893: is_read_unlock(space); ! 894: goto slow_copyin; ! 895: ! 896: abort_request_send_receive: ! 897: ip_unlock(dest_port); ! 898: ip_unlock(reply_port); ! 899: goto slow_send; ! 900: } ! 901: ! 902: case MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0): { ! 903: register ipc_entry_num_t size; ! 904: register ipc_entry_t table; ! 905: ! 906: /* sending a reply message */ ! 907: ! 908: { ! 909: register mach_port_name_t reply_name = ! 910: (mach_port_name_t)hdr->msgh_local_port; ! 911: ! 912: if (reply_name != MACH_PORT_NULL) { ! 913: HOT(c_mmot_cold_018++); ! 914: goto slow_copyin; ! 915: } ! 916: } ! 917: ! 918: is_write_lock(space); ! 919: assert(space->is_active); ! 920: ! 921: /* optimized ipc_entry_lookup */ ! 922: ! 923: size = space->is_table_size; ! 924: table = space->is_table; ! 925: ! 926: { ! 927: register ipc_entry_t entry; ! 928: register mach_port_gen_t gen; ! 929: register mach_port_index_t index; ! 930: ipc_table_index_t *requests; ! 931: ! 932: { ! 933: register mach_port_name_t dest_name = ! 934: (mach_port_name_t)hdr->msgh_remote_port; ! 935: ! 936: index = MACH_PORT_INDEX(dest_name); ! 937: gen = MACH_PORT_GEN(dest_name); ! 938: } ! 939: ! 940: if (index >= size) { ! 941: HOT(c_mmot_cold_019++); ! 942: goto abort_reply_dest_copyin; ! 943: } ! 944: ! 945: entry = &table[index]; ! 946: ! 947: /* check generation, collision bit, and type bit */ ! 948: ! 949: if ((entry->ie_bits & (IE_BITS_GEN_MASK| ! 950: IE_BITS_COLLISION| ! 951: MACH_PORT_TYPE_SEND_ONCE)) != ! 952: (gen | MACH_PORT_TYPE_SEND_ONCE)) { ! 953: HOT(c_mmot_cold_020++); ! 954: goto abort_reply_dest_copyin; ! 955: } ! 956: ! 957: /* optimized ipc_right_copyin */ ! 958: ! 959: assert(IE_BITS_TYPE(entry->ie_bits) == ! 960: MACH_PORT_TYPE_SEND_ONCE); ! 961: assert(IE_BITS_UREFS(entry->ie_bits) == 1); ! 962: ! 963: if (entry->ie_request != 0) { ! 964: HOT(c_mmot_cold_021++); ! 965: goto abort_reply_dest_copyin; ! 966: } ! 967: ! 968: dest_port = (ipc_port_t) entry->ie_object; ! 969: assert(dest_port != IP_NULL); ! 970: ! 971: ip_lock(dest_port); ! 972: if (!ip_active(dest_port)) { ! 973: ip_unlock(dest_port); ! 974: HOT(c_mmot_cold_022++); ! 975: goto abort_reply_dest_copyin; ! 976: } ! 977: ! 978: assert(dest_port->ip_sorights > 0); ! 979: ! 980: /* optimized ipc_entry_dealloc */ ! 981: ! 982: ! 983: entry->ie_bits = gen; ! 984: entry->ie_next = table->ie_next; ! 985: table->ie_next = index; ! 986: entry->ie_object = IO_NULL; ! 987: } ! 988: ! 989: hdr->msgh_bits = ! 990: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, ! 991: 0); ! 992: hdr->msgh_remote_port = dest_port; ! 993: ! 994: /* make sure we can queue to the destination */ ! 995: ! 996: assert(dest_port->ip_receiver != ipc_space_kernel); ! 997: ! 998: /* optimized ipc_entry_lookup/ipc_mqueue_copyin */ ! 999: ! 1000: { ! 1001: register ipc_entry_t entry; ! 1002: register ipc_entry_bits_t bits; ! 1003: ! 1004: { ! 1005: register mach_port_index_t index; ! 1006: register mach_port_gen_t gen; ! 1007: ! 1008: index = MACH_PORT_INDEX(rcv_name); ! 1009: gen = MACH_PORT_GEN(rcv_name); ! 1010: ! 1011: if (index < size) { ! 1012: entry = &table[index]; ! 1013: bits = entry->ie_bits; ! 1014: if (IE_BITS_GEN(bits) != gen || ! 1015: (bits & IE_BITS_COLLISION)) { ! 1016: entry = IE_NULL; ! 1017: } ! 1018: } else { ! 1019: entry = IE_NULL; ! 1020: } ! 1021: if (entry == IE_NULL) { ! 1022: entry = ipc_entry_lookup(space, rcv_name); ! 1023: if (entry == IE_NULL) { ! 1024: HOT(c_mmot_cold_024++); ! 1025: goto abort_reply_rcv_copyin; ! 1026: } ! 1027: bits = entry->ie_bits; ! 1028: } ! 1029: ! 1030: } ! 1031: ! 1032: /* check type bits; looking for receive or set */ ! 1033: ! 1034: if (bits & MACH_PORT_TYPE_PORT_SET) { ! 1035: register ipc_pset_t rcv_pset; ! 1036: ! 1037: rcv_pset = (ipc_pset_t) entry->ie_object; ! 1038: assert(rcv_pset != IPS_NULL); ! 1039: ! 1040: ips_lock(rcv_pset); ! 1041: assert(ips_active(rcv_pset)); ! 1042: ! 1043: rcv_object = (ipc_object_t) rcv_pset; ! 1044: rcv_mqueue = &rcv_pset->ips_messages; ! 1045: } else if (bits & MACH_PORT_TYPE_RECEIVE) { ! 1046: register ipc_port_t rcv_port; ! 1047: ! 1048: rcv_port = (ipc_port_t) entry->ie_object; ! 1049: assert(rcv_port != IP_NULL); ! 1050: ! 1051: if (!ip_lock_try(rcv_port)) { ! 1052: HOT(c_mmot_cold_025++); ! 1053: goto abort_reply_rcv_copyin; ! 1054: } ! 1055: assert(ip_active(rcv_port)); ! 1056: ! 1057: if (rcv_port->ip_pset_count != 0) { ! 1058: ip_unlock(rcv_port); ! 1059: HOT(c_mmot_cold_026++); ! 1060: goto abort_reply_rcv_copyin; ! 1061: } ! 1062: ! 1063: rcv_object = (ipc_object_t) rcv_port; ! 1064: rcv_mqueue = &rcv_port->ip_messages; ! 1065: } else { ! 1066: HOT(c_mmot_cold_027++); ! 1067: goto abort_reply_rcv_copyin; ! 1068: } ! 1069: } ! 1070: ! 1071: is_write_unlock(space); ! 1072: io_reference(rcv_object); ! 1073: imq_lock(rcv_mqueue); ! 1074: io_unlock(rcv_object); ! 1075: HOT(c_mmot_hot_fSR_ok++); ! 1076: goto fast_send_receive; ! 1077: ! 1078: abort_reply_dest_copyin: ! 1079: is_write_unlock(space); ! 1080: HOT(c_mmot_cold_029++); ! 1081: goto slow_copyin; ! 1082: ! 1083: abort_reply_rcv_copyin: ! 1084: ip_unlock(dest_port); ! 1085: is_write_unlock(space); ! 1086: HOT(c_mmot_cold_030++); ! 1087: goto slow_send; ! 1088: } ! 1089: ! 1090: default: ! 1091: HOT(c_mmot_cold_031++); ! 1092: goto slow_copyin; ! 1093: } ! 1094: /*NOTREACHED*/ ! 1095: ! 1096: fast_send_receive: ! 1097: /* ! 1098: * optimized ipc_mqueue_send/ipc_mqueue_receive ! 1099: * ! 1100: * Finished get/copyin of kmsg and copyin of rcv_name. ! 1101: * space is unlocked, dest_port is locked, ! 1102: * we can queue kmsg to dest_port, ! 1103: * rcv_mqueue is locked, rcv_object holds a ref, ! 1104: * if rcv_object is a port it isn't in a port set ! 1105: */ ! 1106: ! 1107: assert(ip_active(dest_port)); ! 1108: assert(dest_port->ip_receiver != ipc_space_kernel); ! 1109: assert(!imq_full(&dest_port->ip_messages) || ! 1110: (MACH_MSGH_BITS_REMOTE(hdr->msgh_bits) == ! 1111: MACH_MSG_TYPE_PORT_SEND_ONCE)); ! 1112: assert((hdr->msgh_bits & MACH_MSGH_BITS_CIRCULAR) == 0); ! 1113: ! 1114: { ! 1115: register ipc_mqueue_t dest_mqueue; ! 1116: wait_queue_t waitq; ! 1117: thread_t receiver; ! 1118: spl_t s; ! 1119: #if THREAD_SWAPPER ! 1120: thread_act_t rcv_act; ! 1121: #endif ! 1122: ! 1123: dest_mqueue = &dest_port->ip_messages; ! 1124: ! 1125: if (!imq_lock_try(dest_mqueue)) { ! 1126: abort_send_receive: ! 1127: ip_unlock(dest_port); ! 1128: imq_unlock(rcv_mqueue); ! 1129: ipc_object_release(rcv_object); ! 1130: HOT(c_mmot_cold_032++); ! 1131: goto slow_send; ! 1132: } ! 1133: if (ipc_kmsg_queue_first(&rcv_mqueue->imq_messages) != IKM_NULL) { ! 1134: imq_unlock(dest_mqueue); ! 1135: HOT(c_mmot_cold_033++); ! 1136: goto abort_send_receive; ! 1137: } ! 1138: ! 1139: waitq = &dest_mqueue->imq_wait_queue; ! 1140: s = splsched(); ! 1141: wait_queue_peek_locked(waitq, IPC_MQUEUE_RECEIVE, &receiver, &waitq); ! 1142: /* queue still locked, thread locked - but still on q */ ! 1143: ! 1144: if (receiver == THREAD_NULL) { ! 1145: splx(s); ! 1146: imq_unlock(dest_mqueue); ! 1147: HOT(c_mmot_cold_033++); ! 1148: goto abort_send_receive; ! 1149: } ! 1150: ! 1151: assert(receiver->wait_queue == waitq); ! 1152: assert(receiver->wait_event == IPC_MQUEUE_RECEIVE); ! 1153: ! 1154: /* ! 1155: * See if it is still running on another processor (trying to ! 1156: * block itself). If so, fall off. ! 1157: * ! 1158: * JMM - We have an opportunity here. Since the thread is locked ! 1159: * and we find it runnable, it must still be trying to get into ! 1160: * thread_block on itself. We could just "hand him the message" ! 1161: * and let him go (thread_go_locked()) and then fall down into a ! 1162: * slow receive for ourselves. Only his RECEIVE_TOO_LARGE handling ! 1163: * runs afoul of that. Clean this up! ! 1164: */ ! 1165: if ((receiver->state & TH_RUN) != TH_WAIT) { ! 1166: assert(NCPUS > 1); ! 1167: HOT(c_mmot_cold_033++); ! 1168: fall_off: ! 1169: thread_unlock(receiver); ! 1170: if (waitq != &dest_mqueue->imq_wait_queue) ! 1171: wait_queue_unlock(waitq); ! 1172: splx(s); ! 1173: imq_unlock(dest_mqueue); ! 1174: goto abort_send_receive; ! 1175: } ! 1176: ! 1177: /* ! 1178: * Check that the receiver can stay on the hot path. ! 1179: */ ! 1180: if ((send_size + REQUESTED_TRAILER_SIZE(receiver->ith_option) ! 1181: > receiver->ith_msize) || ! 1182: (receiver->ith_option & MACH_RCV_NOTIFY) || ! 1183: (receiver->ith_scatter_list != MACH_MSG_BODY_NULL)) { ! 1184: /* ! 1185: * The receiver can't accept the message. ! 1186: */ ! 1187: HOT(c_mmot_bad_rcvr++); ! 1188: goto fall_off; ! 1189: } ! 1190: ! 1191: #if THREAD_SWAPPER ! 1192: /* ! 1193: * Receiver looks okay -- is it swapped in? ! 1194: */ ! 1195: rpc_lock(receiver); ! 1196: rcv_act = receiver->top_act; ! 1197: if (rcv_act->swap_state != TH_SW_IN && ! 1198: rcv_act->swap_state != TH_SW_UNSWAPPABLE) { ! 1199: rpc_unlock(receiver); ! 1200: HOT(c_mmot_rcvr_swapped++); ! 1201: goto fall_off; ! 1202: } ! 1203: ! 1204: /* ! 1205: * Make sure receiver stays swapped in (if we can). ! 1206: */ ! 1207: if (!act_lock_try(rcv_act)) { /* out of order! */ ! 1208: rpc_unlock(receiver); ! 1209: HOT(c_mmot_rcvr_locked++); ! 1210: goto fall_off; ! 1211: } ! 1212: ! 1213: /* ! 1214: * Check for task swapping in progress affecting ! 1215: * receiver. Since rcv_act is attached to a shuttle, ! 1216: * its swap_state is covered by shuttle's thread_lock() ! 1217: * (sigh). ! 1218: */ ! 1219: if ((rcv_act->swap_state != TH_SW_IN && ! 1220: rcv_act->swap_state != TH_SW_UNSWAPPABLE) || ! 1221: rcv_act->ast & AST_SWAPOUT) { ! 1222: act_unlock(rcv_act); ! 1223: rpc_unlock(receiver); ! 1224: HOT(c_mmot_rcvr_tswapped++); ! 1225: goto fall_off; ! 1226: } ! 1227: ! 1228: /* ! 1229: * We don't need to make receiver unswappable here -- holding ! 1230: * act_lock() of rcv_act is sufficient to prevent either thread ! 1231: * or task swapping from changing its state (see swapout_scan(), ! 1232: * task_swapout()). Don't release lock till receiver's state ! 1233: * is consistent. Its task may then be marked for swapout, ! 1234: * but that's life. ! 1235: */ ! 1236: rpc_unlock(receiver); ! 1237: /* ! 1238: * NB: act_lock(rcv_act) still held ! 1239: */ ! 1240: #endif /* THREAD_SWAPPER */ ! 1241: ! 1242: /* At this point we are committed to do the "handoff". */ ! 1243: c_mach_msg_trap_switch_fast++; ! 1244: ! 1245: /* ! 1246: * JMM - Go ahead and pull the receiver from the runq. If the ! 1247: * runq wasn't the one for the mqueue, unlock it. ! 1248: */ ! 1249: wait_queue_pull_thread_locked(waitq, ! 1250: receiver, ! 1251: (waitq != &dest_mqueue->imq_wait_queue)); ! 1252: ! 1253: /* ! 1254: * Store the kmsg and seqno where the receiver can pick it up. ! 1255: */ ! 1256: receiver->ith_state = MACH_MSG_SUCCESS; ! 1257: receiver->ith_kmsg = kmsg; ! 1258: receiver->ith_seqno = dest_mqueue->imq_seqno++; ! 1259: ipc_mqueue_release_msgcount(dest_mqueue); ! 1260: imq_unlock(dest_mqueue); ! 1261: ip_unlock(dest_port); ! 1262: ! 1263: ! 1264: /* ! 1265: * Put sender on reply port's queue. ! 1266: * Also save state that the sender of ! 1267: * our reply message needs to determine if it ! 1268: * can hand off directly back to us. ! 1269: */ ! 1270: ! 1271: self->ith_state = MACH_RCV_IN_PROGRESS; ! 1272: self->ith_msize = rcv_size; ! 1273: ! 1274: self->ith_option = option; ! 1275: self->ith_scatter_list = MACH_MSG_BODY_NULL; ! 1276: self->ith_scatter_list_size = scatter_list_size; ! 1277: ! 1278: waitq = &rcv_mqueue->imq_wait_queue; ! 1279: wait_queue_assert_wait_locked(waitq, ! 1280: IPC_MQUEUE_RECEIVE, ! 1281: THREAD_ABORTSAFE, ! 1282: TRUE); /* unlock? */ ! 1283: /* rcv_mqueue is unlocked */ ! 1284: ! 1285: current_task()->messages_sent++; ! 1286: ! 1287: /* ! 1288: * Switch directly to receiving thread, and block ! 1289: * this thread as though it had called ipc_mqueue_receive. ! 1290: */ ! 1291: { ! 1292: extern unsigned sched_tick; /* kern/sched_prim.c */ ! 1293: ! 1294: /* from thread_block_reason() */ ! 1295: ast_off(AST_QUANTUM|AST_BLOCK|AST_URGENT); ! 1296: ! 1297: /* ! 1298: * JMM - Hacked in version of setrun scheduler op ! 1299: * that doesn't try to put thread on a runq. Safe ! 1300: * for now because we only do this for sp_mk threads. ! 1301: */ ! 1302: { ! 1303: mk_sp_info_t sched_info; ! 1304: ! 1305: assert(receiver->sp_info != SP_INFO_NULL); ! 1306: sched_info = (mk_sp_info_t)receiver->sp_info; ! 1307: sched_info->th_state = MK_SP_RUNNABLE; ! 1308: } ! 1309: ! 1310: assert((receiver->state & (TH_RUN|TH_WAIT)) == TH_WAIT); ! 1311: assert(receiver != self); ! 1312: ! 1313: receiver->state &= ~(TH_WAIT|TH_UNINT); ! 1314: ! 1315: receiver->state |= TH_RUN; ! 1316: receiver->wait_result = THREAD_AWAKENED; ! 1317: #if NCPUS > 1 /* from thread_invoke inline */ ! 1318: mp_disable_preemption(); ! 1319: receiver->last_processor = current_processor(); ! 1320: mp_enable_preemption(); ! 1321: #endif /* NCPUS > 1 */ ! 1322: thread_unlock(receiver); ! 1323: assert( receiver != self ); ! 1324: #if THREAD_SWAPPER ! 1325: act_unlock(rcv_act); ! 1326: #endif /* THREAD_SWAPPER */ ! 1327: ! 1328: /* ! 1329: * Prepare self (the sender) to block. ! 1330: */ ! 1331: thread_lock(self); ! 1332: ! 1333: assert(!(self->state & TH_ABORT)); ! 1334: assert(self->wait_result = -1); /* for assertions */ ! 1335: assert(self->state & TH_RUN); ! 1336: self->state |= TH_WAIT; ! 1337: self->reason = 0; /* inline thread_invoke */ ! 1338: thread_unlock(self); ! 1339: ! 1340: /* ! 1341: * Switch to the receiver now. ! 1342: * Inlined: thread_invoke(self, receiver, 0); ! 1343: */ ! 1344: { ! 1345: thread_t old_thread; ! 1346: sched_policy_t *policy; ! 1347: sf_return_t sfr; ! 1348: ! 1349: mp_disable_preemption(); ! 1350: ast_context(receiver->top_act, cpu_number()); ! 1351: timer_switch(&receiver->system_timer); ! 1352: ! 1353: current_task()->csw++; ! 1354: ! 1355: policy = &sched_policy[self->policy]; ! 1356: sfr = policy->sp_ops.sp_thread_done(policy, self); ! 1357: assert(sfr == SF_SUCCESS); ! 1358: ! 1359: old_thread = switch_context(self, 0, receiver); ! 1360: ! 1361: /* We're back! */ ! 1362: assert(current_thread() == self); ! 1363: policy = &sched_policy[self->policy]; ! 1364: sfr = policy->sp_ops.sp_thread_begin(policy, self); ! 1365: assert(sfr == SF_SUCCESS); ! 1366: ! 1367: assert(old_thread != self); ! 1368: thread_dispatch(old_thread); ! 1369: enable_preemption(); ! 1370: } ! 1371: ! 1372: splx(s); ! 1373: } ! 1374: ! 1375: switch (self->wait_result) { ! 1376: ! 1377: case THREAD_INTERRUPTED: ! 1378: ipc_object_release(rcv_object); ! 1379: return MACH_RCV_INTERRUPTED; ! 1380: ! 1381: case THREAD_RESTART: ! 1382: /* ! 1383: * something bad happened to the port/set. If the port ! 1384: * is still active, it must have just changed membership. ! 1385: */ ! 1386: if (!io_active(rcv_object)) { ! 1387: ipc_object_release(rcv_object); ! 1388: return MACH_RCV_PORT_DIED; ! 1389: } else { ! 1390: ipc_object_release(rcv_object); ! 1391: return MACH_RCV_PORT_CHANGED; ! 1392: } ! 1393: ! 1394: case THREAD_AWAKENED: ! 1395: ipc_object_release(rcv_object); ! 1396: break; ! 1397: ! 1398: default: ! 1399: panic("mmot_hotpath: bad wait result"); ! 1400: } ! 1401: ! 1402: ! 1403: /* ! 1404: * If we allowed for just a receive too large indication ! 1405: * and we got one, copy out the size (stored in our kmsg ! 1406: * pointer) instead of the message. If we got the error, ! 1407: * but didn't set the flag, we just need to try the copy ! 1408: * out of the message and see where that takes us. ! 1409: */ ! 1410: if ((option & MACH_RCV_LARGE) && ! 1411: (self->ith_state == MACH_RCV_TOO_LARGE)) { ! 1412: mach_msg_header_t *out_msg; ! 1413: ! 1414: out_msg = (rcv_msg != MACH_MSG_NULL)?rcv_msg:msg; ! 1415: if (copyout((char *) &self->ith_kmsg, ! 1416: (char *) &msg->msgh_size, ! 1417: sizeof(mach_msg_size_t))) ! 1418: return MACH_RCV_INVALID_DATA; ! 1419: return MACH_RCV_TOO_LARGE; ! 1420: } ! 1421: ! 1422: ! 1423: /* ! 1424: * Restore state saved in sending thread's send path. ! 1425: */ ! 1426: kmsg = self->ith_kmsg; ! 1427: assert(kmsg != IKM_NULL); ! 1428: dest_port = (ipc_port_t)kmsg->ikm_header.msgh_remote_port; ! 1429: ! 1430: { ! 1431: ip_lock(dest_port); ! 1432: assert(dest_port->ip_messages.imq_msgcount > 0); ! 1433: dest_port->ip_messages.imq_msgcount--; ! 1434: ip_unlock(dest_port); ! 1435: } ! 1436: ! 1437: hdr = &kmsg->ikm_header; ! 1438: send_size = hdr->msgh_size; ! 1439: trailer = (mach_msg_format_0_trailer_t *) ((vm_offset_t) hdr + ! 1440: round_msg(send_size)); ! 1441: ! 1442: if (option & MACH_RCV_TRAILER_MASK) { ! 1443: trailer->msgh_seqno = self->ith_seqno; ! 1444: trailer->msgh_trailer_size = ! 1445: REQUESTED_TRAILER_SIZE(option); ! 1446: } ! 1447: } ! 1448: ! 1449: fast_copyout: ! 1450: /* ! 1451: * Nothing locked and no references held, except ! 1452: * we have kmsg with msgh_seqno filled in. Must ! 1453: * still check against rcv_size and do ! 1454: * ipc_kmsg_copyout/ipc_kmsg_put. ! 1455: */ ! 1456: ! 1457: reply_size = send_size + trailer->msgh_trailer_size; ! 1458: if (rcv_size < reply_size) { ! 1459: HOT(c_mmot_g_slow_copyout6++); ! 1460: goto slow_copyout; ! 1461: } ! 1462: ! 1463: /* optimized ipc_kmsg_copyout/ipc_kmsg_copyout_header */ ! 1464: ! 1465: switch (hdr->msgh_bits) { ! 1466: case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, ! 1467: MACH_MSG_TYPE_PORT_SEND_ONCE): { ! 1468: ipc_port_t reply_port = ! 1469: (ipc_port_t) hdr->msgh_local_port; ! 1470: mach_port_name_t dest_name, reply_name; ! 1471: ! 1472: /* receiving a request message */ ! 1473: ! 1474: if (!IP_VALID(reply_port)) { ! 1475: HOT(c_mmot_g_slow_copyout5++); ! 1476: goto slow_copyout; ! 1477: } ! 1478: ! 1479: is_write_lock(space); ! 1480: assert(space->is_active); ! 1481: ! 1482: /* ! 1483: * To do an atomic copyout, need simultaneous ! 1484: * locks on both ports and the space. If ! 1485: * dest_port == reply_port, and simple locking is ! 1486: * enabled, then we will abort. Otherwise it's ! 1487: * OK to unlock twice. ! 1488: */ ! 1489: ! 1490: ip_lock(dest_port); ! 1491: if (!ip_active(dest_port) || ! 1492: !ip_lock_try(reply_port)) { ! 1493: HOT(c_mmot_cold_037++); ! 1494: goto abort_request_copyout; ! 1495: } ! 1496: ! 1497: if (!ip_active(reply_port)) { ! 1498: ip_unlock(reply_port); ! 1499: HOT(c_mmot_cold_038++); ! 1500: goto abort_request_copyout; ! 1501: } ! 1502: ! 1503: assert(reply_port->ip_sorights > 0); ! 1504: ip_unlock(reply_port); ! 1505: ! 1506: { ! 1507: register ipc_entry_t table; ! 1508: register ipc_entry_t entry; ! 1509: register mach_port_index_t index; ! 1510: ! 1511: /* optimized ipc_entry_get */ ! 1512: ! 1513: table = space->is_table; ! 1514: index = table->ie_next; ! 1515: ! 1516: if (index == 0) { ! 1517: HOT(c_mmot_cold_039++); ! 1518: goto abort_request_copyout; ! 1519: } ! 1520: ! 1521: entry = &table[index]; ! 1522: table->ie_next = entry->ie_next; ! 1523: entry->ie_request = 0; ! 1524: ! 1525: { ! 1526: register mach_port_gen_t gen; ! 1527: ! 1528: assert((entry->ie_bits &~ IE_BITS_GEN_MASK) == 0); ! 1529: gen = IE_BITS_NEW_GEN(entry->ie_bits); ! 1530: ! 1531: reply_name = MACH_PORT_MAKE(index, gen); ! 1532: ! 1533: /* optimized ipc_right_copyout */ ! 1534: ! 1535: entry->ie_bits = gen | (MACH_PORT_TYPE_SEND_ONCE | 1); ! 1536: } ! 1537: ! 1538: assert(MACH_PORT_VALID(reply_name)); ! 1539: entry->ie_object = (ipc_object_t) reply_port; ! 1540: is_write_unlock(space); ! 1541: } ! 1542: ! 1543: /* optimized ipc_object_copyout_dest */ ! 1544: ! 1545: assert(dest_port->ip_srights > 0); ! 1546: ip_release(dest_port); ! 1547: ! 1548: if (dest_port->ip_receiver == space) ! 1549: dest_name = dest_port->ip_receiver_name; ! 1550: else ! 1551: dest_name = MACH_PORT_NULL; ! 1552: ! 1553: if ((--dest_port->ip_srights == 0) && ! 1554: (dest_port->ip_nsrequest != IP_NULL)) { ! 1555: ipc_port_t nsrequest; ! 1556: mach_port_mscount_t mscount; ! 1557: ! 1558: /* a rather rare case */ ! 1559: ! 1560: nsrequest = dest_port->ip_nsrequest; ! 1561: mscount = dest_port->ip_mscount; ! 1562: dest_port->ip_nsrequest = IP_NULL; ! 1563: ip_unlock(dest_port); ! 1564: ipc_notify_no_senders(nsrequest, mscount); ! 1565: } else ! 1566: ip_unlock(dest_port); ! 1567: ! 1568: hdr->msgh_bits = ! 1569: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, ! 1570: MACH_MSG_TYPE_PORT_SEND); ! 1571: hdr->msgh_remote_port = (mach_port_t)reply_name; ! 1572: hdr->msgh_local_port = (mach_port_t)dest_name; ! 1573: HOT(c_mmot_hot_ok1++); ! 1574: goto fast_put; ! 1575: ! 1576: abort_request_copyout: ! 1577: ip_unlock(dest_port); ! 1578: is_write_unlock(space); ! 1579: HOT(c_mmot_g_slow_copyout4++); ! 1580: goto slow_copyout; ! 1581: } ! 1582: ! 1583: case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0): { ! 1584: register mach_port_name_t dest_name; ! 1585: ! 1586: /* receiving a reply message */ ! 1587: ! 1588: ip_lock(dest_port); ! 1589: if (!ip_active(dest_port)) { ! 1590: ip_unlock(dest_port); ! 1591: HOT(c_mmot_g_slow_copyout3++); ! 1592: goto slow_copyout; ! 1593: } ! 1594: ! 1595: /* optimized ipc_object_copyout_dest */ ! 1596: ! 1597: assert(dest_port->ip_sorights > 0); ! 1598: ! 1599: if (dest_port->ip_receiver == space) { ! 1600: ip_release(dest_port); ! 1601: dest_port->ip_sorights--; ! 1602: dest_name = dest_port->ip_receiver_name; ! 1603: ip_unlock(dest_port); ! 1604: } else { ! 1605: ip_unlock(dest_port); ! 1606: ! 1607: ipc_notify_send_once(dest_port); ! 1608: dest_name = MACH_PORT_NULL; ! 1609: } ! 1610: ! 1611: hdr->msgh_bits = MACH_MSGH_BITS(0, ! 1612: MACH_MSG_TYPE_PORT_SEND_ONCE); ! 1613: hdr->msgh_remote_port = MACH_PORT_NULL; ! 1614: hdr->msgh_local_port = (ipc_port_t)dest_name; ! 1615: HOT(c_mmot_hot_ok2++); ! 1616: goto fast_put; ! 1617: } ! 1618: ! 1619: case MACH_MSGH_BITS_COMPLEX| ! 1620: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0): { ! 1621: register mach_port_name_t dest_name; ! 1622: ! 1623: /* receiving a complex reply message */ ! 1624: ! 1625: ip_lock(dest_port); ! 1626: if (!ip_active(dest_port)) { ! 1627: ip_unlock(dest_port); ! 1628: HOT(c_mmot_g_slow_copyout1++); ! 1629: goto slow_copyout; ! 1630: } ! 1631: ! 1632: /* optimized ipc_object_copyout_dest */ ! 1633: ! 1634: assert(dest_port->ip_sorights > 0); ! 1635: ! 1636: if (dest_port->ip_receiver == space) { ! 1637: ip_release(dest_port); ! 1638: dest_port->ip_sorights--; ! 1639: dest_name = dest_port->ip_receiver_name; ! 1640: ip_unlock(dest_port); ! 1641: } else { ! 1642: ip_unlock(dest_port); ! 1643: ! 1644: ipc_notify_send_once(dest_port); ! 1645: dest_name = MACH_PORT_NULL; ! 1646: } ! 1647: ! 1648: hdr->msgh_bits = ! 1649: MACH_MSGH_BITS_COMPLEX | ! 1650: MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND_ONCE); ! 1651: hdr->msgh_remote_port = MACH_PORT_NULL; ! 1652: hdr->msgh_local_port = (mach_port_t)dest_name; ! 1653: ! 1654: mr = ipc_kmsg_copyout_body(kmsg, space, ! 1655: current_map(), ! 1656: MACH_MSG_BODY_NULL); ! 1657: if (mr != MACH_MSG_SUCCESS) { ! 1658: if (ipc_kmsg_put(msg, kmsg, hdr->msgh_size + ! 1659: trailer->msgh_trailer_size) == ! 1660: MACH_RCV_INVALID_DATA) ! 1661: return MACH_RCV_INVALID_DATA; ! 1662: else ! 1663: return mr | MACH_RCV_BODY_ERROR; ! 1664: } ! 1665: HOT(c_mmot_hot_ok3++); ! 1666: goto fast_put; ! 1667: } ! 1668: ! 1669: default: ! 1670: HOT(c_mmot_g_slow_copyout2++); ! 1671: goto slow_copyout; ! 1672: } ! 1673: /*NOTREACHED*/ panic("happy birthday rwd"); ! 1674: ! 1675: fast_put: ! 1676: /* ! 1677: * We have the reply message data in kmsg, ! 1678: * and the reply message size (plus trailer size) ! 1679: * in reply_size. Just need to copy it out to the ! 1680: * user and free kmsg. Must check ikm_cache after ! 1681: * copyoutmsg. Inlined ipc_kmsg_put() here. ! 1682: */ ! 1683: mr = MACH_MSG_SUCCESS; ! 1684: if (copyoutmsg((char *) &kmsg->ikm_header, ! 1685: (char *)(rcv_msg ? rcv_msg : msg), ! 1686: hdr->msgh_size + trailer->msgh_trailer_size)) ! 1687: mr = MACH_RCV_INVALID_DATA; ! 1688: else ! 1689: current_task()->messages_received++; ! 1690: ! 1691: if ((kmsg->ikm_size != IKM_SAVED_KMSG_SIZE) || ! 1692: KMSG_IS_RT(kmsg) || !ikm_cache_put(kmsg)) { ! 1693: ikm_free(kmsg); ! 1694: } ! 1695: ! 1696: return(mr); ! 1697: ! 1698: ! 1699: /* BEGINNING OF WARM PATH */ ! 1700: ! 1701: /* ! 1702: * The slow path has a few non-register temporary ! 1703: * variables used only for call-by-reference. ! 1704: */ ! 1705: ! 1706: { ! 1707: ipc_kmsg_t temp_kmsg; ! 1708: mach_port_seqno_t temp_seqno; ! 1709: ipc_object_t temp_rcv_object; ! 1710: ipc_mqueue_t temp_rcv_mqueue; ! 1711: ! 1712: slow_get: ! 1713: /* ! 1714: * No locks, references, or messages held. ! 1715: * Still have to get the request, send it, ! 1716: * receive reply, etc. ! 1717: */ ! 1718: ! 1719: mr = ipc_kmsg_get(msg, send_size, &temp_kmsg, current_space()); ! 1720: if (mr != MACH_MSG_SUCCESS) { ! 1721: return(mr); ! 1722: /*NOTREACHED*/ ! 1723: } ! 1724: kmsg = temp_kmsg; ! 1725: hdr = &kmsg->ikm_header; ! 1726: /* naturally align the message before tacking on the trailer */ ! 1727: trailer = (mach_msg_format_0_trailer_t *) ((vm_offset_t) hdr + ! 1728: send_size); ! 1729: /* try to get back on optimized path */ ! 1730: HOT(c_mmot_getback_fast_copyin++); ! 1731: goto fast_copyin; ! 1732: ! 1733: slow_copyin: ! 1734: /* ! 1735: * We have the message data in kmsg, but ! 1736: * we still need to copyin, send it, ! 1737: * receive a reply, and do copyout. ! 1738: */ ! 1739: ! 1740: mr = ipc_kmsg_copyin(kmsg, space, current_map(), ! 1741: MACH_PORT_NULL); ! 1742: if (mr != MACH_MSG_SUCCESS) { ! 1743: if (kmsg->ikm_size != IKM_SAVED_KMSG_SIZE || ! 1744: KMSG_IS_RT(kmsg) || !ikm_cache_put(kmsg)) ! 1745: ikm_free(kmsg); ! 1746: return(mr); ! 1747: } ! 1748: ! 1749: /* try to get back on optimized path */ ! 1750: ! 1751: if (hdr->msgh_bits & MACH_MSGH_BITS_CIRCULAR) { ! 1752: HOT(c_mmot_cold_048++); ! 1753: goto slow_send; ! 1754: } ! 1755: ! 1756: dest_port = (ipc_port_t) hdr->msgh_remote_port; ! 1757: assert(IP_VALID(dest_port)); ! 1758: ! 1759: ip_lock(dest_port); ! 1760: if (!ip_active(dest_port)) { ! 1761: ip_unlock(dest_port); ! 1762: goto slow_send; ! 1763: } ! 1764: ! 1765: if (dest_port->ip_receiver == ipc_space_kernel) { ! 1766: dest_port->ip_messages.imq_seqno++; ! 1767: ip_unlock(dest_port); ! 1768: goto kernel_send; ! 1769: } ! 1770: ! 1771: if (!imq_full(&dest_port->ip_messages) || ! 1772: (MACH_MSGH_BITS_REMOTE(hdr->msgh_bits) == ! 1773: MACH_MSG_TYPE_PORT_SEND_ONCE)) ! 1774: { ! 1775: /* ! 1776: * Try an optimized ipc_mqueue_copyin. ! 1777: * It will work if this is a request message. ! 1778: */ ! 1779: ! 1780: register ipc_port_t reply_port; ! 1781: ! 1782: reply_port = (ipc_port_t) hdr->msgh_local_port; ! 1783: if (IP_VALID(reply_port)) { ! 1784: if (ip_lock_try(reply_port)) { ! 1785: if (ip_active(reply_port) && ! 1786: reply_port->ip_receiver == space && ! 1787: reply_port->ip_receiver_name == rcv_name && ! 1788: reply_port->ip_pset_count == 0) ! 1789: { ! 1790: /* Grab a reference to the reply port. */ ! 1791: rcv_object = (ipc_object_t) reply_port; ! 1792: io_reference(rcv_object); ! 1793: rcv_mqueue = &reply_port->ip_messages; ! 1794: imq_lock(rcv_mqueue); ! 1795: io_unlock(rcv_object); ! 1796: HOT(c_mmot_getback_FastSR++); ! 1797: goto fast_send_receive; ! 1798: } ! 1799: ip_unlock(reply_port); ! 1800: } ! 1801: } ! 1802: } ! 1803: ! 1804: ip_unlock(dest_port); ! 1805: HOT(c_mmot_cold_050++); ! 1806: goto slow_send; ! 1807: ! 1808: kernel_send: ! 1809: /* ! 1810: * Special case: send message to kernel services. ! 1811: * The request message has been copied into the ! 1812: * kmsg. Nothing is locked. ! 1813: */ ! 1814: ! 1815: { ! 1816: register ipc_port_t reply_port; ! 1817: mach_port_seqno_t local_seqno; ! 1818: ! 1819: /* ! 1820: * Perform the kernel function. ! 1821: */ ! 1822: c_mmot_kernel_send++; ! 1823: ! 1824: current_task()->messages_sent++; ! 1825: ! 1826: kmsg = ipc_kobject_server(kmsg); ! 1827: if (kmsg == IKM_NULL) { ! 1828: /* ! 1829: * No reply. Take the ! 1830: * slow receive path. ! 1831: */ ! 1832: HOT(c_mmot_cold_051++); ! 1833: goto slow_get_rcv_port; ! 1834: } ! 1835: ! 1836: /* ! 1837: * Check that: ! 1838: * the reply port is alive ! 1839: * we hold the receive right ! 1840: * the name has not changed. ! 1841: * the port is not in a set ! 1842: * If any of these are not true, ! 1843: * we cannot directly receive the reply ! 1844: * message. ! 1845: */ ! 1846: hdr = &kmsg->ikm_header; ! 1847: send_size = hdr->msgh_size; ! 1848: trailer = (mach_msg_format_0_trailer_t *) ((vm_offset_t) hdr + ! 1849: round_msg(send_size)); ! 1850: reply_port = (ipc_port_t) hdr->msgh_remote_port; ! 1851: ip_lock(reply_port); ! 1852: ! 1853: if ((!ip_active(reply_port)) || ! 1854: (reply_port->ip_receiver != space) || ! 1855: (reply_port->ip_receiver_name != rcv_name) || ! 1856: (reply_port->ip_pset_count != 0)) ! 1857: { ! 1858: ip_unlock(reply_port); ! 1859: ipc_kmsg_send_always(kmsg); ! 1860: HOT(c_mmot_cold_052++); ! 1861: goto slow_get_rcv_port; ! 1862: } ! 1863: ! 1864: rcv_mqueue = &reply_port->ip_messages; ! 1865: imq_lock(rcv_mqueue); ! 1866: /* keep port locked, and don`t change ref count yet */ ! 1867: ! 1868: /* ! 1869: * If there are messages on the port ! 1870: * or other threads waiting for a message, ! 1871: * we cannot directly receive the reply. ! 1872: */ ! 1873: if (!wait_queue_empty(&rcv_mqueue->imq_wait_queue) || ! 1874: (ipc_kmsg_queue_first(&rcv_mqueue->imq_messages) != IKM_NULL)) ! 1875: { ! 1876: imq_unlock(rcv_mqueue); ! 1877: ip_unlock(reply_port); ! 1878: ipc_kmsg_send_always(kmsg); ! 1879: HOT(c_mmot_cold_053++); ! 1880: goto slow_get_rcv_port; ! 1881: } ! 1882: ! 1883: /* ! 1884: * We can directly receive this reply. ! 1885: * Since there were no messages queued ! 1886: * on the reply port, there should be ! 1887: * no threads blocked waiting to send. ! 1888: */ ! 1889: dest_port = reply_port; ! 1890: local_seqno = rcv_mqueue->imq_seqno++; ! 1891: imq_unlock(rcv_mqueue); ! 1892: ! 1893: /* ! 1894: * inline ipc_object_release. ! 1895: * Port is still locked. ! 1896: * Reference count was not incremented. ! 1897: */ ! 1898: ip_check_unlock(reply_port); ! 1899: ! 1900: if (option & MACH_RCV_TRAILER_MASK) { ! 1901: trailer->msgh_seqno = local_seqno; ! 1902: trailer->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option); ! 1903: } ! 1904: /* copy out the kernel reply */ ! 1905: HOT(c_mmot_fastkernelreply++); ! 1906: goto fast_copyout; ! 1907: } ! 1908: ! 1909: slow_send: ! 1910: /* ! 1911: * Nothing is locked. We have acquired kmsg, but ! 1912: * we still need to send it and receive a reply. ! 1913: */ ! 1914: ! 1915: mr = ipc_kmsg_send(kmsg, MACH_MSG_OPTION_NONE, ! 1916: MACH_MSG_TIMEOUT_NONE); ! 1917: if (mr != MACH_MSG_SUCCESS) { ! 1918: mr |= ipc_kmsg_copyout_pseudo(kmsg, space, ! 1919: current_map(), ! 1920: MACH_MSG_BODY_NULL); ! 1921: ! 1922: (void) ipc_kmsg_put(msg, kmsg, hdr->msgh_size); ! 1923: return(mr); ! 1924: } ! 1925: ! 1926: slow_get_rcv_port: ! 1927: /* ! 1928: * We have sent the message. Copy in the receive port. ! 1929: */ ! 1930: mr = ipc_mqueue_copyin(space, rcv_name, ! 1931: &temp_rcv_mqueue, &temp_rcv_object); ! 1932: if (mr != MACH_MSG_SUCCESS) { ! 1933: return(mr); ! 1934: } ! 1935: rcv_mqueue = temp_rcv_mqueue; ! 1936: rcv_object = temp_rcv_object; ! 1937: /* hold ref for rcv_object */ ! 1938: ! 1939: slow_receive: ! 1940: /* ! 1941: * Now we have sent the request and copied in rcv_name, ! 1942: * so rcv_mqueue is locked and hold ref for rcv_object. ! 1943: * Just receive a reply and try to get back to fast path. ! 1944: */ ! 1945: ! 1946: self->ith_option = option; ! 1947: self->ith_scatter_list = MACH_MSG_BODY_NULL; ! 1948: self->ith_scatter_list_size = scatter_list_size; ! 1949: ! 1950: mr = ipc_mqueue_receive(rcv_mqueue, ! 1951: MACH_MSG_OPTION_NONE, ! 1952: MACH_MSG_SIZE_MAX, ! 1953: MACH_MSG_TIMEOUT_NONE, ! 1954: THREAD_ABORTSAFE, ! 1955: &temp_kmsg, &temp_seqno); ! 1956: ipc_object_release(rcv_object); ! 1957: ! 1958: if (mr != MACH_MSG_SUCCESS) { ! 1959: return(mr); ! 1960: } ! 1961: ! 1962: kmsg = temp_kmsg; ! 1963: hdr = &kmsg->ikm_header; ! 1964: send_size = hdr->msgh_size; ! 1965: trailer = (mach_msg_format_0_trailer_t *) ((vm_offset_t) hdr + ! 1966: round_msg(send_size)); ! 1967: if (option & MACH_RCV_TRAILER_MASK) { ! 1968: trailer->msgh_seqno = temp_seqno; ! 1969: trailer->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option); ! 1970: } ! 1971: dest_port = (ipc_port_t) hdr->msgh_remote_port; ! 1972: HOT(c_mmot_cold_055++); ! 1973: goto fast_copyout; ! 1974: ! 1975: slow_copyout: ! 1976: /* ! 1977: * Nothing locked and no references held, except ! 1978: * we have kmsg with msgh_seqno filled in. Must ! 1979: * still check against rcv_size and do ! 1980: * ipc_kmsg_copyout/ipc_kmsg_put. ! 1981: */ ! 1982: ! 1983: reply_size = send_size + trailer->msgh_trailer_size; ! 1984: if (rcv_size < reply_size) { ! 1985: if (msg_receive_error(kmsg, msg, option, temp_seqno, ! 1986: space) == MACH_RCV_INVALID_DATA) { ! 1987: mr = MACH_RCV_INVALID_DATA; ! 1988: return(mr); ! 1989: } ! 1990: else { ! 1991: mr = MACH_RCV_TOO_LARGE; ! 1992: return(mr); ! 1993: } ! 1994: } ! 1995: ! 1996: mr = ipc_kmsg_copyout(kmsg, space, current_map(), ! 1997: MACH_PORT_NULL, MACH_MSG_BODY_NULL); ! 1998: if (mr != MACH_MSG_SUCCESS) { ! 1999: if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) { ! 2000: if (ipc_kmsg_put(msg, kmsg, reply_size) == ! 2001: MACH_RCV_INVALID_DATA) ! 2002: mr = MACH_RCV_INVALID_DATA; ! 2003: } ! 2004: else { ! 2005: if (msg_receive_error(kmsg, msg, option, ! 2006: temp_seqno, space) == MACH_RCV_INVALID_DATA) ! 2007: mr = MACH_RCV_INVALID_DATA; ! 2008: } ! 2009: ! 2010: return(mr); ! 2011: } ! 2012: ! 2013: /* try to get back on optimized path */ ! 2014: HOT(c_mmot_getback_fast_put++); ! 2015: goto fast_put; ! 2016: ! 2017: slow_put: ! 2018: mr = ipc_kmsg_put((rcv_msg != MACH_MSG_NULL)?rcv_msg:msg, ! 2019: kmsg, ! 2020: hdr->msgh_size + trailer->msgh_trailer_size); ! 2021: return(mr); ! 2022: /*NOTREACHED*/ ! 2023: } ! 2024: } /* END OF HOT PATH */ ! 2025: #endif /* ENABLE_HOTPATH */ ! 2026: ! 2027: if (option & MACH_SEND_MSG) { ! 2028: mr = mach_msg_send(msg, option, send_size, ! 2029: timeout, notify); ! 2030: if (mr != MACH_MSG_SUCCESS) { ! 2031: return mr; ! 2032: } ! 2033: } ! 2034: ! 2035: if (option & MACH_RCV_MSG) { ! 2036: mach_msg_header_t *rcv; ! 2037: ! 2038: /* ! 2039: * 1. MACH_RCV_OVERWRITE is on, and rcv_msg is our scatter list ! 2040: * and receive buffer ! 2041: * 2. MACH_RCV_OVERWRITE is off, and rcv_msg might be the ! 2042: * alternate receive buffer (separate send and receive buffers). ! 2043: */ ! 2044: if (option & MACH_RCV_OVERWRITE) ! 2045: rcv = rcv_msg; ! 2046: else if (rcv_msg != MACH_MSG_NULL) ! 2047: rcv = rcv_msg; ! 2048: else ! 2049: rcv = msg; ! 2050: mr = mach_msg_receive(rcv, option, rcv_size, rcv_name, ! 2051: timeout, notify, scatter_list_size); ! 2052: if (mr != MACH_MSG_SUCCESS) { ! 2053: return mr; ! 2054: } ! 2055: } ! 2056: ! 2057: return MACH_MSG_SUCCESS; ! 2058: } ! 2059: ! 2060: /* ! 2061: * Routine: msg_receive_error [internal] ! 2062: * Purpose: ! 2063: * Builds a minimal header/trailer and copies it to ! 2064: * the user message buffer. Invoked when in the case of a ! 2065: * MACH_RCV_TOO_LARGE or MACH_RCV_BODY_ERROR error. ! 2066: * Conditions: ! 2067: * Nothing locked. ! 2068: * Returns: ! 2069: * MACH_MSG_SUCCESS minimal header/trailer copied ! 2070: * MACH_RCV_INVALID_DATA copyout to user buffer failed ! 2071: */ ! 2072: ! 2073: mach_msg_return_t ! 2074: msg_receive_error( ! 2075: ipc_kmsg_t kmsg, ! 2076: mach_msg_header_t *msg, ! 2077: mach_msg_option_t option, ! 2078: mach_port_seqno_t seqno, ! 2079: ipc_space_t space) ! 2080: { ! 2081: mach_msg_format_0_trailer_t *trailer; ! 2082: ! 2083: /* ! 2084: * Copy out the destination port in the message. ! 2085: * Destroy all other rights and memory in the message. ! 2086: */ ! 2087: ipc_kmsg_copyout_dest(kmsg, space); ! 2088: ! 2089: /* ! 2090: * Build a minimal message with the requested trailer. ! 2091: */ ! 2092: trailer = (mach_msg_format_0_trailer_t *) ! 2093: ((vm_offset_t)&kmsg->ikm_header + ! 2094: round_msg(sizeof(mach_msg_header_t))); ! 2095: kmsg->ikm_header.msgh_size = sizeof(mach_msg_header_t); ! 2096: bcopy( (char *)&trailer_template, ! 2097: (char *)trailer, ! 2098: sizeof(trailer_template)); ! 2099: if (option & MACH_RCV_TRAILER_MASK) { ! 2100: trailer->msgh_seqno = seqno; ! 2101: trailer->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option); ! 2102: } ! 2103: ! 2104: /* ! 2105: * Copy the message to user space ! 2106: */ ! 2107: if (ipc_kmsg_put(msg, kmsg, kmsg->ikm_header.msgh_size + ! 2108: trailer->msgh_trailer_size) == MACH_RCV_INVALID_DATA) ! 2109: return(MACH_RCV_INVALID_DATA); ! 2110: else ! 2111: return(MACH_MSG_SUCCESS); ! 2112: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.