1/* 2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* 29 * @OSF_COPYRIGHT@ 30 */ 31/* 32 * Mach Operating System 33 * Copyright (c) 1991,1990 Carnegie Mellon University 34 * All Rights Reserved. 35 * 36 * Permission to use, copy, modify and distribute this software and its 37 * documentation is hereby granted, provided that both the copyright 38 * notice and this permission notice appear in all copies of the 39 * software, derivative works or modified versions, and any portions 40 * thereof, and that both notices appear in supporting documentation. 41 * 42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 45 * 46 * Carnegie Mellon requests users of this software to return to 47 * 48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 49 * School of Computer Science 50 * Carnegie Mellon University 51 * Pittsburgh PA 15213-3890 52 * 53 * any improvements or extensions that they make and grant Carnegie Mellon 54 * the rights to redistribute these changes. 55 */ 56/* 57 */ 58 59#include <mach/boolean.h> 60#include <mach/port.h> 61#include <mach/mig.h> 62#include <mach/mig_errors.h> 63#include <mach/mach_types.h> 64#include <mach/mach_traps.h> 65 66#include <kern/ipc_tt.h> 67#include <kern/ipc_mig.h> 68#include <kern/kalloc.h> 69#include <kern/task.h> 70#include <kern/thread.h> 71#include <kern/ipc_kobject.h> 72#include <kern/misc_protos.h> 73 74#include <ipc/port.h> 75#include <ipc/ipc_kmsg.h> 76#include <ipc/ipc_entry.h> 77#include <ipc/ipc_object.h> 78#include <ipc/ipc_mqueue.h> 79#include <ipc/ipc_space.h> 80#include <ipc/ipc_port.h> 81#include <ipc/ipc_pset.h> 82#include <vm/vm_map.h> 83 84/* 85 * Routine: mach_msg_send_from_kernel 86 * Purpose: 87 * Send a message from the kernel. 88 * 89 * This is used by the client side of KernelUser interfaces 90 * to implement SimpleRoutines. Currently, this includes 91 * memory_object messages. 92 * Conditions: 93 * Nothing locked. 94 * Returns: 95 * MACH_MSG_SUCCESS Sent the message. 96 * MACH_SEND_INVALID_DEST Bad destination port. 97 * MACH_MSG_SEND_NO_BUFFER Destination port had inuse fixed bufer 98 * or destination is above kernel limit 99 */ 100 101mach_msg_return_t 102mach_msg_send_from_kernel( 103 mach_msg_header_t *msg, 104 mach_msg_size_t send_size) 105{ 106 ipc_kmsg_t kmsg; 107 mach_msg_return_t mr; 108 109 if (!MACH_PORT_VALID((mach_port_name_t)msg->msgh_remote_port)) 110 return MACH_SEND_INVALID_DEST; 111 112 mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); 113 if (mr != MACH_MSG_SUCCESS) 114 return mr; 115 116 ipc_kmsg_copyin_from_kernel(kmsg); 117 118 mr = ipc_kmsg_send_always(kmsg); 119 if (mr != MACH_MSG_SUCCESS) { 120 ipc_kmsg_destroy(kmsg); 121 } 122 123 return mr; 124} 125 126mach_msg_return_t 127mach_msg_send_from_kernel_with_options( 128 mach_msg_header_t *msg, 129 mach_msg_size_t send_size, 130 mach_msg_option_t option, 131 mach_msg_timeout_t timeout_val) 132{ 133 ipc_kmsg_t kmsg; 134 mach_msg_return_t mr; 135 136 if (!MACH_PORT_VALID((mach_port_name_t)msg->msgh_remote_port)) 137 return MACH_SEND_INVALID_DEST; 138 139 mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); 140 if (mr != MACH_MSG_SUCCESS) 141 return mr; 142 143 ipc_kmsg_copyin_from_kernel(kmsg); 144 mr = ipc_kmsg_send(kmsg, option, timeout_val); 145 if (mr != MACH_MSG_SUCCESS) { 146 ipc_kmsg_destroy(kmsg); 147 } 148 149 return mr; 150} 151 152/* 153 * Routine: mach_msg_rpc_from_kernel 154 * Purpose: 155 * Send a message from the kernel and receive a reply. 156 * Uses ith_rpc_reply for the reply port. 157 * 158 * This is used by the client side of KernelUser interfaces 159 * to implement Routines. 160 * Conditions: 161 * Nothing locked. 162 * Returns: 163 * MACH_MSG_SUCCESS Sent the message. 164 * MACH_RCV_PORT_DIED The reply port was deallocated. 165 */ 166 167mach_msg_return_t 168mach_msg_rpc_from_kernel( 169 mach_msg_header_t *msg, 170 mach_msg_size_t send_size, 171 mach_msg_size_t rcv_size) 172{ 173 thread_t self = current_thread(); 174 ipc_port_t reply; 175 ipc_kmsg_t kmsg; 176 mach_port_seqno_t seqno; 177 mach_msg_return_t mr; 178 179 assert(MACH_PORT_VALID((mach_port_name_t)msg->msgh_remote_port)); 180 assert(msg->msgh_local_port == MACH_PORT_NULL); 181 182 mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); 183 if (mr != MACH_MSG_SUCCESS) 184 return mr; 185 186 reply = self->ith_rpc_reply; 187 if (reply == IP_NULL) { 188 reply = ipc_port_alloc_reply(); 189 if ((reply == IP_NULL) || 190 (self->ith_rpc_reply != IP_NULL)) 191 panic("mach_msg_rpc_from_kernel"); 192 self->ith_rpc_reply = reply; 193 } 194 195 /* insert send-once right for the reply port */ 196 kmsg->ikm_header->msgh_local_port = reply; 197 kmsg->ikm_header->msgh_bits |= 198 MACH_MSGH_BITS(0, MACH_MSG_TYPE_MAKE_SEND_ONCE); 199 200 ipc_port_reference(reply); 201 202 ipc_kmsg_copyin_from_kernel(kmsg); 203 204 mr = ipc_kmsg_send_always(kmsg); 205 if (mr != MACH_MSG_SUCCESS) { 206 ipc_kmsg_destroy(kmsg); 207 return mr; 208 } 209 210 for (;;) { 211 ipc_mqueue_t mqueue; 212 213 ip_lock(reply); 214 if ( !ip_active(reply)) { 215 ip_unlock(reply); 216 ipc_port_release(reply); 217 return MACH_RCV_PORT_DIED; 218 } 219 if (!self->active) { 220 ip_unlock(reply); 221 ipc_port_release(reply); 222 return MACH_RCV_INTERRUPTED; 223 } 224 225 assert(reply->ip_pset_count == 0); 226 mqueue = &reply->ip_messages; 227 ip_unlock(reply); 228 229 self->ith_continuation = (void (*)(mach_msg_return_t))0; 230 231 ipc_mqueue_receive(mqueue, 232 MACH_MSG_OPTION_NONE, 233 MACH_MSG_SIZE_MAX, 234 MACH_MSG_TIMEOUT_NONE, 235 THREAD_INTERRUPTIBLE); 236 237 mr = self->ith_state; 238 kmsg = self->ith_kmsg; 239 seqno = self->ith_seqno; 240 241 if (mr == MACH_MSG_SUCCESS) 242 { 243 break; 244 } 245 246 assert(mr == MACH_RCV_INTERRUPTED); 247 248 if (self->handlers) { 249 ipc_port_release(reply); 250 return(mr); 251 } 252 } 253 ipc_port_release(reply); 254 255 /* 256 * Check to see how much of the message/trailer can be received. 257 * We chose the maximum trailer that will fit, since we don't 258 * have options telling us which trailer elements the caller needed. 259 */ 260 if (rcv_size >= kmsg->ikm_header->msgh_size) { 261 mach_msg_format_0_trailer_t *trailer = (mach_msg_format_0_trailer_t *) 262 ((vm_offset_t)kmsg->ikm_header + kmsg->ikm_header->msgh_size); 263 264 if (rcv_size >= kmsg->ikm_header->msgh_size + MAX_TRAILER_SIZE) { 265 /* Enough room for a maximum trailer */ 266 trailer->msgh_trailer_size = MAX_TRAILER_SIZE; 267 } 268 else if (rcv_size < kmsg->ikm_header->msgh_size + 269 trailer->msgh_trailer_size) { 270 /* no room for even the basic (default) trailer */ 271 trailer->msgh_trailer_size = 0; 272 } 273 assert(trailer->msgh_trailer_type == MACH_MSG_TRAILER_FORMAT_0); 274 rcv_size = kmsg->ikm_header->msgh_size + trailer->msgh_trailer_size; 275 mr = MACH_MSG_SUCCESS; 276 } else { 277 mr = MACH_RCV_TOO_LARGE; 278 } 279 280 281 /* 282 * We want to preserve rights and memory in reply! 283 * We don't have to put them anywhere; just leave them 284 * as they are. 285 */ 286 ipc_kmsg_copyout_to_kernel(kmsg, ipc_space_reply); 287 ipc_kmsg_put_to_kernel(msg, kmsg, rcv_size); 288 return mr; 289} 290 291 292/************** These Calls are set up for kernel-loaded tasks/threads **************/ 293 294/* 295 * Routine: mach_msg_overwrite 296 * Purpose: 297 * Like mach_msg_overwrite_trap except that message buffers 298 * live in kernel space. Doesn't handle any options. 299 * 300 * This is used by in-kernel server threads to make 301 * kernel calls, to receive request messages, and 302 * to send reply messages. 303 * Conditions: 304 * Nothing locked. 305 * Returns: 306 */ 307 308mach_msg_return_t 309mach_msg_overwrite( 310 mach_msg_header_t *msg, 311 mach_msg_option_t option, 312 mach_msg_size_t send_size, 313 mach_msg_size_t rcv_size, 314 mach_port_name_t rcv_name, 315 __unused mach_msg_timeout_t msg_timeout, 316 __unused mach_port_name_t notify, 317 __unused mach_msg_header_t *rcv_msg, 318 __unused mach_msg_size_t rcv_msg_size) 319{ 320 ipc_space_t space = current_space(); 321 vm_map_t map = current_map(); 322 ipc_kmsg_t kmsg; 323 mach_port_seqno_t seqno; 324 mach_msg_return_t mr; 325 mach_msg_format_0_trailer_t *trailer; 326 327 if (option & MACH_SEND_MSG) { 328 mach_msg_size_t msg_and_trailer_size; 329 mach_msg_max_trailer_t *max_trailer; 330 331 if ((send_size < sizeof(mach_msg_header_t)) || (send_size & 3)) 332 return MACH_SEND_MSG_TOO_SMALL; 333 334 if (send_size > MACH_MSG_SIZE_MAX - MAX_TRAILER_SIZE) 335 return MACH_SEND_TOO_LARGE; 336 337 msg_and_trailer_size = send_size + MAX_TRAILER_SIZE; 338 kmsg = ipc_kmsg_alloc(msg_and_trailer_size); 339 340 if (kmsg == IKM_NULL) 341 return MACH_SEND_NO_BUFFER; 342 343 (void) memcpy((void *) kmsg->ikm_header, (const void *) msg, send_size); 344 345 kmsg->ikm_header->msgh_size = send_size; 346 347 /* 348 * Reserve for the trailer the largest space (MAX_TRAILER_SIZE) 349 * However, the internal size field of the trailer (msgh_trailer_size) 350 * is initialized to the minimum (sizeof(mach_msg_trailer_t)), to optimize 351 * the cases where no implicit data is requested. 352 */ 353 max_trailer = (mach_msg_max_trailer_t *) ((vm_offset_t)kmsg->ikm_header + send_size); 354 max_trailer->msgh_sender = current_thread()->task->sec_token; 355 max_trailer->msgh_audit = current_thread()->task->audit_token; 356 max_trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0; 357 max_trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE; 358 359 mr = ipc_kmsg_copyin(kmsg, space, map, MACH_PORT_NULL); 360 if (mr != MACH_MSG_SUCCESS) { 361 ipc_kmsg_free(kmsg); 362 return mr; 363 } 364 365 do 366 mr = ipc_kmsg_send(kmsg, MACH_MSG_OPTION_NONE, 367 MACH_MSG_TIMEOUT_NONE); 368 while (mr == MACH_SEND_INTERRUPTED); 369 assert(mr == MACH_MSG_SUCCESS); 370 } 371 372 if (option & MACH_RCV_MSG) { 373 thread_t self = current_thread(); 374 375 do { 376 ipc_object_t object; 377 ipc_mqueue_t mqueue; 378 379 mr = ipc_mqueue_copyin(space, rcv_name, 380 &mqueue, &object); 381 if (mr != MACH_MSG_SUCCESS) 382 return mr; 383 /* hold ref for object */ 384 385 self->ith_continuation = (void (*)(mach_msg_return_t))0; 386 ipc_mqueue_receive(mqueue, 387 MACH_MSG_OPTION_NONE, 388 MACH_MSG_SIZE_MAX, 389 MACH_MSG_TIMEOUT_NONE, 390 THREAD_ABORTSAFE); 391 mr = self->ith_state; 392 kmsg = self->ith_kmsg; 393 seqno = self->ith_seqno; 394 395 ipc_object_release(object); 396 397 } while (mr == MACH_RCV_INTERRUPTED); 398 if (mr != MACH_MSG_SUCCESS) 399 return mr; 400 401 trailer = (mach_msg_format_0_trailer_t *) 402 ((vm_offset_t)kmsg->ikm_header + kmsg->ikm_header->msgh_size); 403 if (option & MACH_RCV_TRAILER_MASK) { 404 trailer->msgh_seqno = seqno; 405 trailer->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option); 406 } 407 408 if (rcv_size < (kmsg->ikm_header->msgh_size + trailer->msgh_trailer_size)) { 409 ipc_kmsg_copyout_dest(kmsg, space); 410 (void) memcpy((void *) msg, (const void *) kmsg->ikm_header, sizeof *msg); 411 ipc_kmsg_free(kmsg); 412 return MACH_RCV_TOO_LARGE; 413 } 414 415 mr = ipc_kmsg_copyout(kmsg, space, map, MACH_PORT_NULL, 416 MACH_MSG_BODY_NULL); 417 if (mr != MACH_MSG_SUCCESS) { 418 if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) { 419 ipc_kmsg_put_to_kernel(msg, kmsg, 420 kmsg->ikm_header->msgh_size + trailer->msgh_trailer_size); 421 } else { 422 ipc_kmsg_copyout_dest(kmsg, space); 423 (void) memcpy((void *) msg, (const void *) kmsg->ikm_header, sizeof *msg); 424 ipc_kmsg_free(kmsg); 425 } 426 427 return mr; 428 } 429 430 (void) memcpy((void *) msg, (const void *) kmsg->ikm_header, 431 kmsg->ikm_header->msgh_size + trailer->msgh_trailer_size); 432 ipc_kmsg_free(kmsg); 433 } 434 435 return MACH_MSG_SUCCESS; 436} 437 438/* 439 * Routine: mig_get_reply_port 440 * Purpose: 441 * Called by client side interfaces living in the kernel 442 * to get a reply port. 443 */ 444mach_port_t 445mig_get_reply_port(void) 446{ 447 return (MACH_PORT_NULL); 448} 449 450/* 451 * Routine: mig_dealloc_reply_port 452 * Purpose: 453 * Called by client side interfaces to get rid of a reply port. 454 */ 455 456void 457mig_dealloc_reply_port( 458 __unused mach_port_t reply_port) 459{ 460 panic("mig_dealloc_reply_port"); 461} 462 463/* 464 * Routine: mig_put_reply_port 465 * Purpose: 466 * Called by client side interfaces after each RPC to 467 * let the client recycle the reply port if it wishes. 468 */ 469void 470mig_put_reply_port( 471 __unused mach_port_t reply_port) 472{ 473} 474 475/* 476 * mig_strncpy.c - by Joshua Block 477 * 478 * mig_strncp -- Bounded string copy. Does what the library routine strncpy 479 * OUGHT to do: Copies the (null terminated) string in src into dest, a 480 * buffer of length len. Assures that the copy is still null terminated 481 * and doesn't overflow the buffer, truncating the copy if necessary. 482 * 483 * Parameters: 484 * 485 * dest - Pointer to destination buffer. 486 * 487 * src - Pointer to source string. 488 * 489 * len - Length of destination buffer. 490 */ 491int 492mig_strncpy( 493 char *dest, 494 const char *src, 495 int len) 496{ 497 int i = 0; 498 499 if (len > 0) 500 if (dest != NULL) { 501 if (src != NULL) 502 for (i=1; i<len; i++) 503 if (! (*dest++ = *src++)) 504 return i; 505 *dest = '\0'; 506 } 507 return i; 508} 509 510char * 511mig_user_allocate( 512 vm_size_t size) 513{ 514 return (char *)kalloc(size); 515} 516 517void 518mig_user_deallocate( 519 char *data, 520 vm_size_t size) 521{ 522 kfree(data, size); 523} 524 525/* 526 * Routine: mig_object_init 527 * Purpose: 528 * Initialize the base class portion of a MIG object. We 529 * will lazy init the port, so just clear it for now. 530 */ 531kern_return_t 532mig_object_init( 533 mig_object_t mig_object, 534 const IMIGObject *interface) 535{ 536 if (mig_object == MIG_OBJECT_NULL) 537 return KERN_INVALID_ARGUMENT; 538 mig_object->pVtbl = (const IMIGObjectVtbl *)interface; 539 mig_object->port = MACH_PORT_NULL; 540 return KERN_SUCCESS; 541} 542 543/* 544 * Routine: mig_object_destroy 545 * Purpose: 546 * The object is being freed. This call lets us clean 547 * up any state we have have built up over the object's 548 * lifetime. 549 * Conditions: 550 * Since notifications and the port hold references on 551 * on the object, neither can exist when this is called. 552 * This is a good place to assert() that condition. 553 */ 554void 555mig_object_destroy( 556 __assert_only mig_object_t mig_object) 557{ 558 assert(mig_object->port == MACH_PORT_NULL); 559 return; 560} 561 562/* 563 * Routine: mig_object_reference 564 * Purpose: 565 * Pure virtual helper to invoke the MIG object's AddRef 566 * method. 567 * Conditions: 568 * MIG object port may be locked. 569 */ 570void 571mig_object_reference( 572 mig_object_t mig_object) 573{ 574 assert(mig_object != MIG_OBJECT_NULL); 575 mig_object->pVtbl->AddRef((IMIGObject *)mig_object); 576} 577 578/* 579 * Routine: mig_object_deallocate 580 * Purpose: 581 * Pure virtual helper to invoke the MIG object's Release 582 * method. 583 * Conditions: 584 * Nothing locked. 585 */ 586void 587mig_object_deallocate( 588 mig_object_t mig_object) 589{ 590 assert(mig_object != MIG_OBJECT_NULL); 591 mig_object->pVtbl->Release((IMIGObject *)mig_object); 592} 593 594/* 595 * Routine: convert_mig_object_to_port [interface] 596 * Purpose: 597 * Base implementation of MIG outtrans routine to convert from 598 * a mig object reference to a new send right on the object's 599 * port. The object reference is consumed. 600 * Returns: 601 * IP_NULL - Null MIG object supplied 602 * Otherwise, a newly made send right for the port 603 * Conditions: 604 * Nothing locked. 605 */ 606ipc_port_t 607convert_mig_object_to_port( 608 mig_object_t mig_object) 609{ 610 ipc_port_t port; 611 boolean_t deallocate = TRUE; 612 613 if (mig_object == MIG_OBJECT_NULL) 614 return IP_NULL; 615 616 port = mig_object->port; 617 while ((port == IP_NULL) || 618 ((port = ipc_port_make_send(port)) == IP_NULL)) { 619 ipc_port_t previous; 620 621 /* 622 * Either the port was never set up, or it was just 623 * deallocated out from under us by the no-senders 624 * processing. In either case, we must: 625 * Attempt to make one 626 * Arrange for no senders 627 * Try to atomically register it with the object 628 * Destroy it if we are raced. 629 */ 630 port = ipc_port_alloc_kernel(); 631 ip_lock(port); 632 ipc_kobject_set_atomically(port, 633 (ipc_kobject_t) mig_object, 634 IKOT_MIG); 635 636 /* make a sonce right for the notification */ 637 port->ip_sorights++; 638 ip_reference(port); 639 640 ipc_port_nsrequest(port, 1, port, &previous); 641 /* port unlocked */ 642 643 assert(previous == IP_NULL); 644 645 if (hw_compare_and_store((uint32_t)IP_NULL, (uint32_t)port, 646 (uint32_t *)&mig_object->port)) { 647 deallocate = FALSE; 648 } else { 649 ipc_port_dealloc_kernel(port); 650 port = mig_object->port; 651 } 652 } 653 654 if (deallocate) 655 mig_object->pVtbl->Release((IMIGObject *)mig_object); 656 657 return (port); 658} 659 660 661/* 662 * Routine: convert_port_to_mig_object [interface] 663 * Purpose: 664 * Base implementation of MIG intrans routine to convert from 665 * an incoming port reference to a new reference on the 666 * underlying object. A new reference must be created, because 667 * the port's reference could go away asynchronously. 668 * Returns: 669 * NULL - Not an active MIG object port or iid not supported 670 * Otherwise, a reference to the underlying MIG interface 671 * Conditions: 672 * Nothing locked. 673 */ 674mig_object_t 675convert_port_to_mig_object( 676 ipc_port_t port, 677 const MIGIID *iid) 678{ 679 mig_object_t mig_object; 680 void *ppv; 681 682 if (!IP_VALID(port)) 683 return NULL; 684 685 ip_lock(port); 686 if (!ip_active(port) || (ip_kotype(port) != IKOT_MIG)) { 687 ip_unlock(port); 688 return NULL; 689 } 690 691 /* 692 * Our port points to some MIG object interface. Now 693 * query it to get a reference to the desired interface. 694 */ 695 ppv = NULL; 696 mig_object = (mig_object_t)port->ip_kobject; 697 mig_object->pVtbl->QueryInterface((IMIGObject *)mig_object, iid, &ppv); 698 ip_unlock(port); 699 return (mig_object_t)ppv; 700} 701 702/* 703 * Routine: mig_object_no_senders [interface] 704 * Purpose: 705 * Base implementation of a no-senders notification handler 706 * for MIG objects. If there truly are no more senders, must 707 * destroy the port and drop its reference on the object. 708 * Returns: 709 * TRUE - port deallocate and reference dropped 710 * FALSE - more senders arrived, re-registered for notification 711 * Conditions: 712 * Nothing locked. 713 */ 714 715boolean_t 716mig_object_no_senders( 717 ipc_port_t port, 718 mach_port_mscount_t mscount) 719{ 720 mig_object_t mig_object; 721 722 ip_lock(port); 723 if (port->ip_mscount > mscount) { 724 ipc_port_t previous; 725 726 /* 727 * Somebody created new send rights while the 728 * notification was in-flight. Just create a 729 * new send-once right and re-register with 730 * the new (higher) mscount threshold. 731 */ 732 /* make a sonce right for the notification */ 733 port->ip_sorights++; 734 ip_reference(port); 735 ipc_port_nsrequest(port, mscount, port, &previous); 736 /* port unlocked */ 737 738 assert(previous == IP_NULL); 739 return (FALSE); 740 } 741 742 /* 743 * Clear the port pointer while we have it locked. 744 */ 745 mig_object = (mig_object_t)port->ip_kobject; 746 mig_object->port = IP_NULL; 747 748 /* 749 * Bring the sequence number and mscount in 750 * line with ipc_port_destroy assertion. 751 */ 752 port->ip_mscount = 0; 753 port->ip_messages.imq_seqno = 0; 754 ipc_port_destroy(port); /* releases lock */ 755 756 /* 757 * Release the port's reference on the object. 758 */ 759 mig_object->pVtbl->Release((IMIGObject *)mig_object); 760 return (TRUE); 761} 762 763/* 764 * Kernel implementation of the notification chain for MIG object 765 * is kept separate from the actual objects, since there are expected 766 * to be much fewer of them than actual objects. 767 * 768 * The implementation of this part of MIG objects is coming 769 * "Real Soon Now"(TM). 770 */ 771