|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* ! 26: * Copyright (c) 1995, 1994, 1993, 1992, 1991, 1990 ! 27: * Open Software Foundation, Inc. ! 28: * ! 29: * Permission to use, copy, modify, and distribute this software and ! 30: * its documentation for any purpose and without fee is hereby granted, ! 31: * provided that the above copyright notice appears in all copies and ! 32: * that both the copyright notice and this permission notice appear in ! 33: * supporting documentation, and that the name of ("OSF") or Open Software ! 34: * Foundation not be used in advertising or publicity pertaining to ! 35: * distribution of the software without specific, written prior permission. ! 36: * ! 37: * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE ! 38: * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ! 39: * FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL OSF BE LIABLE FOR ANY ! 40: * SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ! 41: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN ! 42: * ACTION OF CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING ! 43: * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE ! 44: */ ! 45: /* ! 46: * OSF Research Institute MK6.1 (unencumbered) 1/31/1995 ! 47: */ ! 48: /* ! 49: * Mach Operating System ! 50: * Copyright (c) 1991,1990,1989 Carnegie Mellon University ! 51: * All Rights Reserved. ! 52: * ! 53: * Permission to use, copy, modify and distribute this software and its ! 54: * documentation is hereby granted, provided that both the copyright ! 55: * notice and this permission notice appear in all copies of the ! 56: * software, derivative works or modified versions, and any portions ! 57: * thereof, and that both notices appear in supporting documentation. ! 58: * ! 59: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 60: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 61: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 62: * ! 63: * Carnegie Mellon requests users of this software to return to ! 64: * ! 65: * Software Distribution Coordinator or [email protected] ! 66: * School of Computer Science ! 67: * Carnegie Mellon University ! 68: * Pittsburgh PA 15213-3890 ! 69: * ! 70: * any improvements or extensions that they make and grant Carnegie Mellon ! 71: * the rights to redistribute these changes. ! 72: */ ! 73: /* ! 74: * File: ipc/ipc_port.c ! 75: * Author: Rich Draves ! 76: * Date: 1989 ! 77: * ! 78: * Functions to manipulate IPC ports. ! 79: */ ! 80: ! 81: #import <mach/features.h> ! 82: ! 83: #include <mach/port.h> ! 84: #include <mach/kern_return.h> ! 85: #include <kern/lock.h> ! 86: #include <kern/ipc_sched.h> ! 87: #include <kern/ipc_kobject.h> ! 88: #include <ipc/ipc_entry.h> ! 89: #include <ipc/ipc_space.h> ! 90: #include <ipc/ipc_object.h> ! 91: #include <ipc/ipc_port.h> ! 92: #include <ipc/ipc_pset.h> ! 93: #include <ipc/ipc_thread.h> ! 94: #include <ipc/ipc_mqueue.h> ! 95: #include <ipc/ipc_notify.h> ! 96: ! 97: decl_simple_lock_data(, ipc_port_multiple_lock_data) ! 98: ! 99: decl_simple_lock_data(, ipc_port_timestamp_lock_data) ! 100: ipc_port_timestamp_t ipc_port_timestamp_data; ! 101: ! 102: /* ! 103: * Routine: ipc_port_timestamp ! 104: * Purpose: ! 105: * Retrieve a timestamp value. ! 106: */ ! 107: ! 108: ipc_port_timestamp_t ! 109: ipc_port_timestamp(void) ! 110: { ! 111: ipc_port_timestamp_t timestamp; ! 112: ! 113: ipc_port_timestamp_lock(); ! 114: timestamp = ipc_port_timestamp_data++; ! 115: ipc_port_timestamp_unlock(); ! 116: ! 117: return timestamp; ! 118: } ! 119: ! 120: /* ! 121: * Routine: ipc_port_dnrequest ! 122: * Purpose: ! 123: * Try to allocate a dead-name request slot. ! 124: * If successful, returns the request index. ! 125: * Otherwise returns zero. ! 126: * Conditions: ! 127: * The port is locked and active. ! 128: * Returns: ! 129: * KERN_SUCCESS A request index was found. ! 130: * KERN_NO_SPACE No index allocated. ! 131: */ ! 132: ! 133: kern_return_t ! 134: ipc_port_dnrequest( ! 135: ipc_port_t port, ! 136: mach_port_t name, ! 137: ipc_port_t soright, ! 138: ipc_port_request_index_t *indexp) ! 139: { ! 140: ipc_port_request_t ipr, table; ! 141: ipc_port_request_index_t index; ! 142: ! 143: assert(ip_active(port)); ! 144: assert(name != MACH_PORT_NULL); ! 145: assert(soright != IP_NULL); ! 146: ! 147: table = port->ip_dnrequests; ! 148: if (table == IPR_NULL) ! 149: return KERN_NO_SPACE; ! 150: ! 151: index = table->ipr_next; ! 152: if (index == 0) ! 153: return KERN_NO_SPACE; ! 154: ! 155: ipr = &table[index]; ! 156: assert(ipr->ipr_name == MACH_PORT_NULL); ! 157: ! 158: table->ipr_next = ipr->ipr_next; ! 159: ipr->ipr_name = name; ! 160: ipr->ipr_soright = soright; ! 161: ! 162: *indexp = index; ! 163: return KERN_SUCCESS; ! 164: } ! 165: ! 166: /* ! 167: * Routine: ipc_port_dngrow ! 168: * Purpose: ! 169: * Grow a port's table of dead-name requests. ! 170: * Conditions: ! 171: * The port must be locked and active. ! 172: * Nothing else locked; will allocate memory. ! 173: * Upon return the port is unlocked. ! 174: * Returns: ! 175: * KERN_SUCCESS Grew the table. ! 176: * KERN_SUCCESS Somebody else grew the table. ! 177: * KERN_SUCCESS The port died. ! 178: * KERN_RESOURCE_SHORTAGE Couldn't allocate new table. ! 179: * KERN_NO_SPACE Couldn't grow to desired size ! 180: */ ! 181: ! 182: kern_return_t ! 183: ipc_port_dngrow( ! 184: ipc_port_t port, ! 185: int target_size) ! 186: { ! 187: ipc_table_size_t its; ! 188: ipc_port_request_t otable, ntable; ! 189: ! 190: assert(ip_active(port)); ! 191: ! 192: otable = port->ip_dnrequests; ! 193: if (otable == IPR_NULL) ! 194: its = &ipc_table_dnrequests[0]; ! 195: else ! 196: its = otable->ipr_size + 1; ! 197: ! 198: if (target_size != ITS_SIZE_NONE) { ! 199: if ((otable != IPR_NULL) && ! 200: (target_size <= otable->ipr_size->its_size)) { ! 201: ip_unlock(port); ! 202: return KERN_SUCCESS; ! 203: } ! 204: while ((its->its_size) && (its->its_size < target_size)) { ! 205: its++; ! 206: } ! 207: if (its->its_size == 0) { ! 208: ip_unlock(port); ! 209: return KERN_NO_SPACE; ! 210: } ! 211: } ! 212: ! 213: ip_reference(port); ! 214: ip_unlock(port); ! 215: ! 216: if ((its->its_size == 0) || ! 217: ((ntable = it_dnrequests_alloc(its)) == IPR_NULL)) { ! 218: ipc_port_release(port); ! 219: return KERN_RESOURCE_SHORTAGE; ! 220: } ! 221: ! 222: ip_lock(port); ! 223: ip_release(port); ! 224: ! 225: /* ! 226: * Check that port is still active and that nobody else ! 227: * has slipped in and grown the table on us. Note that ! 228: * just checking port->ip_dnrequests == otable isn't ! 229: * sufficient; must check ipr_size. ! 230: */ ! 231: ! 232: if (ip_active(port) && ! 233: (port->ip_dnrequests == otable) && ! 234: ((otable == IPR_NULL) || (otable->ipr_size+1 == its))) { ! 235: ipc_table_size_t oits; ! 236: ipc_table_elems_t osize, nsize; ! 237: ipc_port_request_index_t free, i; ! 238: ! 239: /* copy old table to new table */ ! 240: ! 241: if (otable != IPR_NULL) { ! 242: oits = otable->ipr_size; ! 243: osize = oits->its_size; ! 244: free = otable->ipr_next; ! 245: ! 246: bcopy((char *)(otable + 1), (char *)(ntable + 1), ! 247: (osize - 1) * sizeof(struct ipc_port_request)); ! 248: } else { ! 249: osize = 1; ! 250: free = 0; ! 251: } ! 252: ! 253: nsize = its->its_size; ! 254: assert(nsize > osize); ! 255: ! 256: /* add new elements to the new table's free list */ ! 257: ! 258: for (i = osize; i < nsize; i++) { ! 259: ipc_port_request_t ipr = &ntable[i]; ! 260: ! 261: ipr->ipr_name = MACH_PORT_NULL; ! 262: ipr->ipr_next = free; ! 263: free = i; ! 264: } ! 265: ! 266: ntable->ipr_next = free; ! 267: ntable->ipr_size = its; ! 268: port->ip_dnrequests = ntable; ! 269: ip_unlock(port); ! 270: ! 271: if (otable != IPR_NULL) ! 272: it_dnrequests_free(oits, otable); ! 273: } else { ! 274: ip_check_unlock(port); ! 275: it_dnrequests_free(its, ntable); ! 276: } ! 277: ! 278: return KERN_SUCCESS; ! 279: } ! 280: ! 281: /* ! 282: * Routine: ipc_port_dncancel ! 283: * Purpose: ! 284: * Cancel a dead-name request and return the send-once right. ! 285: * Conditions: ! 286: * The port must locked and active. ! 287: */ ! 288: ! 289: ipc_port_t ! 290: ipc_port_dncancel( ! 291: ipc_port_t port, ! 292: mach_port_t name, ! 293: ipc_port_request_index_t index) ! 294: { ! 295: ipc_port_request_t ipr, table; ! 296: ipc_port_t dnrequest; ! 297: ! 298: assert(ip_active(port)); ! 299: assert(name != MACH_PORT_NULL); ! 300: assert(index != 0); ! 301: ! 302: table = port->ip_dnrequests; ! 303: assert(table != IPR_NULL); ! 304: ! 305: ipr = &table[index]; ! 306: dnrequest = ipr->ipr_soright; ! 307: assert(ipr->ipr_name == name); ! 308: ! 309: /* return ipr to the free list inside the table */ ! 310: ! 311: ipr->ipr_name = MACH_PORT_NULL; ! 312: ipr->ipr_next = table->ipr_next; ! 313: table->ipr_next = index; ! 314: ! 315: return dnrequest; ! 316: } ! 317: ! 318: /* ! 319: * Routine: ipc_port_pdrequest ! 320: * Purpose: ! 321: * Make a port-deleted request, returning the ! 322: * previously registered send-once right. ! 323: * Just cancels the previous request if notify is IP_NULL. ! 324: * Conditions: ! 325: * The port is locked and active. It is unlocked. ! 326: * Consumes a ref for notify (if non-null), and ! 327: * returns previous with a ref (if non-null). ! 328: */ ! 329: ! 330: void ! 331: ipc_port_pdrequest( ! 332: ipc_port_t port, ! 333: ipc_port_t notify, ! 334: ipc_port_t *previousp) ! 335: { ! 336: ipc_port_t previous; ! 337: ! 338: assert(ip_active(port)); ! 339: ! 340: previous = port->ip_pdrequest; ! 341: port->ip_pdrequest = notify; ! 342: ip_unlock(port); ! 343: ! 344: *previousp = previous; ! 345: } ! 346: ! 347: /* ! 348: * Routine: ipc_port_nsrequest ! 349: * Purpose: ! 350: * Make a no-senders request, returning the ! 351: * previously registered send-once right. ! 352: * Just cancels the previous request if notify is IP_NULL. ! 353: * Conditions: ! 354: * The port is locked and active. It is unlocked. ! 355: * Consumes a ref for notify (if non-null), and ! 356: * returns previous with a ref (if non-null). ! 357: */ ! 358: ! 359: void ! 360: ipc_port_nsrequest( ! 361: ipc_port_t port, ! 362: mach_port_mscount_t sync, ! 363: ipc_port_t notify, ! 364: ipc_port_t *previousp) ! 365: { ! 366: ipc_port_t previous; ! 367: mach_port_mscount_t mscount; ! 368: ! 369: assert(ip_active(port)); ! 370: ! 371: previous = port->ip_nsrequest; ! 372: mscount = port->ip_mscount; ! 373: ! 374: if ((port->ip_srights == 0) && ! 375: (sync <= mscount) && ! 376: (notify != IP_NULL)) { ! 377: port->ip_nsrequest = IP_NULL; ! 378: ip_unlock(port); ! 379: ipc_notify_no_senders(notify, mscount); ! 380: } else { ! 381: port->ip_nsrequest = notify; ! 382: ip_unlock(port); ! 383: } ! 384: ! 385: *previousp = previous; ! 386: } ! 387: ! 388: /* ! 389: * Routine: ipc_port_set_qlimit ! 390: * Purpose: ! 391: * Changes a port's queue limit; the maximum number ! 392: * of messages which may be queued to the port. ! 393: * Conditions: ! 394: * The port is locked and active. ! 395: */ ! 396: ! 397: void ! 398: ipc_port_set_qlimit( ! 399: ipc_port_t port, ! 400: mach_port_msgcount_t qlimit) ! 401: { ! 402: assert(ip_active(port)); ! 403: assert(qlimit <= MACH_PORT_QLIMIT_MAX); ! 404: ! 405: /* wake up senders allowed by the new qlimit */ ! 406: ! 407: if (qlimit > port->ip_qlimit) { ! 408: mach_port_msgcount_t i, wakeup; ! 409: ! 410: /* caution: wakeup, qlimit are unsigned */ ! 411: ! 412: wakeup = qlimit - port->ip_qlimit; ! 413: ! 414: for (i = 0; i < wakeup; i++) { ! 415: ipc_thread_t th; ! 416: ! 417: th = ipc_thread_dequeue(&port->ip_blocked); ! 418: if (th == ITH_NULL) ! 419: break; ! 420: ! 421: th->ith_state = MACH_MSG_SUCCESS; ! 422: thread_go(th); ! 423: } ! 424: } ! 425: ! 426: port->ip_qlimit = qlimit; ! 427: } ! 428: ! 429: /* ! 430: * Routine: ipc_port_set_seqno ! 431: * Purpose: ! 432: * Changes a port's sequence number. ! 433: * Conditions: ! 434: * The port is locked and active. ! 435: */ ! 436: ! 437: void ! 438: ipc_port_set_seqno( ! 439: ipc_port_t port, ! 440: mach_port_seqno_t seqno) ! 441: { ! 442: if (port->ip_pset != IPS_NULL) { ! 443: ipc_pset_t pset = port->ip_pset; ! 444: ! 445: ips_lock(pset); ! 446: if (!ips_active(pset)) { ! 447: ipc_pset_remove(pset, port); ! 448: ips_check_unlock(pset); ! 449: goto no_port_set; ! 450: } else { ! 451: imq_lock(&pset->ips_messages); ! 452: port->ip_seqno = seqno; ! 453: imq_unlock(&pset->ips_messages); ! 454: } ! 455: } else { ! 456: no_port_set: ! 457: imq_lock(&port->ip_messages); ! 458: port->ip_seqno = seqno; ! 459: imq_unlock(&port->ip_messages); ! 460: } ! 461: } ! 462: ! 463: /* ! 464: * Routine: ipc_port_clear_receiver ! 465: * Purpose: ! 466: * Prepares a receive right for transmission/destruction. ! 467: * Conditions: ! 468: * The port is locked and active. ! 469: */ ! 470: ! 471: void ! 472: ipc_port_clear_receiver( ! 473: ipc_port_t port) ! 474: { ! 475: ipc_pset_t pset; ! 476: ! 477: assert(ip_active(port)); ! 478: ! 479: pset = port->ip_pset; ! 480: if (pset != IPS_NULL) { ! 481: /* No threads receiving from port, but must remove from set. */ ! 482: ! 483: ips_lock(pset); ! 484: ipc_pset_remove(pset, port); ! 485: ips_check_unlock(pset); ! 486: } else { ! 487: /* Else, wake up all receivers, indicating why. */ ! 488: ! 489: imq_lock(&port->ip_messages); ! 490: ipc_mqueue_changed(&port->ip_messages, MACH_RCV_PORT_DIED); ! 491: imq_unlock(&port->ip_messages); ! 492: } ! 493: ! 494: ipc_port_set_mscount(port, 0); ! 495: imq_lock(&port->ip_messages); ! 496: port->ip_seqno = 0; ! 497: imq_unlock(&port->ip_messages); ! 498: } ! 499: ! 500: /* ! 501: * Routine: ipc_port_init ! 502: * Purpose: ! 503: * Initializes a newly-allocated port. ! 504: * Doesn't touch the ip_object fields. ! 505: */ ! 506: ! 507: void ! 508: ipc_port_init( ! 509: ipc_port_t port, ! 510: ipc_space_t space, ! 511: mach_port_t name) ! 512: { ! 513: /* port->ip_kobject doesn't have to be initialized */ ! 514: ! 515: port->ip_receiver = space; ! 516: port->ip_receiver_name = name; ! 517: ! 518: port->ip_mscount = 0; ! 519: port->ip_srights = 0; ! 520: port->ip_sorights = 0; ! 521: ! 522: port->ip_nsrequest = IP_NULL; ! 523: port->ip_pdrequest = IP_NULL; ! 524: port->ip_dnrequests = IPR_NULL; ! 525: ! 526: port->ip_pset = IPS_NULL; ! 527: port->ip_seqno = 0; ! 528: port->ip_msgcount = 0; ! 529: port->ip_qlimit = MACH_PORT_QLIMIT_DEFAULT; ! 530: ! 531: ipc_mqueue_init(&port->ip_messages); ! 532: ipc_thread_queue_init(&port->ip_blocked); ! 533: } ! 534: ! 535: /* ! 536: * Routine: ipc_port_alloc ! 537: * Purpose: ! 538: * Allocate a port. ! 539: * Conditions: ! 540: * Nothing locked. If successful, the port is returned ! 541: * locked. (The caller doesn't have a reference.) ! 542: * Returns: ! 543: * KERN_SUCCESS The port is allocated. ! 544: * KERN_INVALID_TASK The space is dead. ! 545: * KERN_NO_SPACE No room for an entry in the space. ! 546: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. ! 547: */ ! 548: ! 549: kern_return_t ! 550: ipc_port_alloc( ! 551: ipc_space_t space, ! 552: mach_port_t *namep, ! 553: ipc_port_t *portp) ! 554: { ! 555: ipc_port_t port; ! 556: mach_port_t name; ! 557: kern_return_t kr; ! 558: ! 559: kr = ipc_object_alloc(space, IOT_PORT, ! 560: MACH_PORT_TYPE_RECEIVE, 0, ! 561: &name, (ipc_object_t *) &port); ! 562: if (kr != KERN_SUCCESS) ! 563: return kr; ! 564: /* port is locked */ ! 565: ! 566: ipc_port_init(port, space, name); ! 567: ! 568: *namep = name; ! 569: *portp = port; ! 570: return KERN_SUCCESS; ! 571: } ! 572: ! 573: /* ! 574: * Routine: ipc_port_alloc_name ! 575: * Purpose: ! 576: * Allocate a port, with a specific name. ! 577: * Conditions: ! 578: * Nothing locked. If successful, the port is returned ! 579: * locked. (The caller doesn't have a reference.) ! 580: * Returns: ! 581: * KERN_SUCCESS The port is allocated. ! 582: * KERN_INVALID_TASK The space is dead. ! 583: * KERN_NAME_EXISTS The name already denotes a right. ! 584: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. ! 585: */ ! 586: ! 587: kern_return_t ! 588: ipc_port_alloc_name( ! 589: ipc_space_t space, ! 590: mach_port_t name, ! 591: ipc_port_t *portp) ! 592: { ! 593: ipc_port_t port; ! 594: kern_return_t kr; ! 595: ! 596: kr = ipc_object_alloc_name(space, IOT_PORT, ! 597: MACH_PORT_TYPE_RECEIVE, 0, ! 598: name, (ipc_object_t *) &port); ! 599: if (kr != KERN_SUCCESS) ! 600: return kr; ! 601: /* port is locked */ ! 602: ! 603: ipc_port_init(port, space, name); ! 604: ! 605: *portp = port; ! 606: return KERN_SUCCESS; ! 607: } ! 608: ! 609: #if MACH_IPC_COMPAT ! 610: /* ! 611: * Routine: ipc_port_delete_compat ! 612: * Purpose: ! 613: * Find and destroy a compat entry for a dead port. ! 614: * If successful, generate a port-deleted notification. ! 615: * Conditions: ! 616: * Nothing locked; the port is dead. ! 617: * Frees a ref for the space. ! 618: */ ! 619: ! 620: void ! 621: ipc_port_delete_compat( ! 622: ipc_port_t port, ! 623: ipc_space_t space, ! 624: mach_port_t name) ! 625: { ! 626: ipc_entry_t entry; ! 627: kern_return_t kr; ! 628: ! 629: assert(!ip_active(port)); ! 630: ! 631: kr = ipc_right_lookup_write(space, name, &entry); ! 632: if (kr == KERN_SUCCESS) { ! 633: ipc_port_t sright; ! 634: ! 635: /* space is write-locked and active */ ! 636: ! 637: if ((ipc_port_t) entry->ie_object == port) { ! 638: assert(entry->ie_bits & IE_BITS_COMPAT); ! 639: ! 640: sright = ipc_space_make_notify(space); ! 641: ! 642: kr = ipc_right_destroy(space, name, entry); ! 643: /* space is unlocked */ ! 644: assert(kr == KERN_INVALID_NAME); ! 645: } else { ! 646: is_write_unlock(space); ! 647: sright = IP_NULL; ! 648: } ! 649: ! 650: if (IP_VALID(sright)) ! 651: ipc_notify_port_deleted_compat(sright, name); ! 652: } ! 653: ! 654: is_release(space); ! 655: } ! 656: #endif /* MACH_IPC_COMPAT */ ! 657: ! 658: /* ! 659: * Routine: ipc_port_destroy ! 660: * Purpose: ! 661: * Destroys a port. Cleans up queued messages. ! 662: * ! 663: * If the port has a backup, it doesn't get destroyed, ! 664: * but is sent in a port-destroyed notification to the backup. ! 665: * Conditions: ! 666: * The port is locked and alive; nothing else locked. ! 667: * The caller has a reference, which is consumed. ! 668: * Afterwards, the port is unlocked and dead. ! 669: */ ! 670: ! 671: void ! 672: ipc_port_destroy( ! 673: ipc_port_t port) ! 674: { ! 675: ipc_port_t pdrequest, nsrequest; ! 676: ipc_mqueue_t mqueue; ! 677: ipc_kmsg_queue_t kmqueue; ! 678: ipc_kmsg_t kmsg; ! 679: ipc_thread_t sender; ! 680: ipc_port_request_t dnrequests; ! 681: ! 682: assert(ip_active(port)); ! 683: /* port->ip_receiver_name is garbage */ ! 684: /* port->ip_receiver/port->ip_destination is garbage */ ! 685: assert(port->ip_pset == IPS_NULL); ! 686: assert(port->ip_mscount == 0); ! 687: assert(port->ip_seqno == 0); ! 688: ! 689: /* first check for a backup port */ ! 690: ! 691: pdrequest = port->ip_pdrequest; ! 692: if (pdrequest != IP_NULL) { ! 693: /* we assume the ref for pdrequest */ ! 694: port->ip_pdrequest = IP_NULL; ! 695: ! 696: /* make port be in limbo */ ! 697: port->ip_receiver_name = MACH_PORT_NULL; ! 698: port->ip_destination = IP_NULL; ! 699: ip_unlock(port); ! 700: ! 701: #if MACH_IPC_COMPAT ! 702: /* ! 703: * pdrequest might actually be a send right instead ! 704: * of a send-once right, indicated by the low bit ! 705: * of the pointer value. If this is the case, ! 706: * we must use ipc_notify_port_destroyed_compat. ! 707: */ ! 708: ! 709: if (ip_pdsendp(pdrequest)) { ! 710: ipc_port_t sright = ip_pdsend(pdrequest); ! 711: ! 712: if (!ipc_port_check_circularity(port, sright)) { ! 713: /* consumes our refs for port and sright */ ! 714: ipc_notify_port_destroyed_compat(sright, port); ! 715: return; ! 716: } else { ! 717: /* consume sright and destroy port */ ! 718: ipc_port_release_send(sright); ! 719: } ! 720: } else ! 721: #endif /* MACH_IPC_COMPAT */ ! 722: ! 723: if (!ipc_port_check_circularity(port, pdrequest)) { ! 724: /* consumes our refs for port and pdrequest */ ! 725: ipc_notify_port_destroyed(pdrequest, port); ! 726: return; ! 727: } else { ! 728: /* consume pdrequest and destroy port */ ! 729: ipc_port_release_sonce(pdrequest); ! 730: } ! 731: ! 732: ip_lock(port); ! 733: assert(ip_active(port)); ! 734: assert(port->ip_pset == IPS_NULL); ! 735: assert(port->ip_mscount == 0); ! 736: assert(port->ip_seqno == 0); ! 737: assert(port->ip_pdrequest == IP_NULL); ! 738: assert(port->ip_receiver_name == MACH_PORT_NULL); ! 739: assert(port->ip_destination == IP_NULL); ! 740: ! 741: /* fall through and destroy the port */ ! 742: } ! 743: ! 744: /* ! 745: * rouse all blocked senders ! 746: * ! 747: * This must be done with the port locked, because ! 748: * ipc_mqueue_send can play with the ip_blocked queue ! 749: * of a dead port. ! 750: */ ! 751: ! 752: while ((sender = ipc_thread_dequeue(&port->ip_blocked)) != ITH_NULL) { ! 753: sender->ith_state = MACH_MSG_SUCCESS; ! 754: thread_go(sender); ! 755: } ! 756: ! 757: /* once port is dead, we don't need to keep it locked */ ! 758: ! 759: port->ip_object.io_bits &= ~IO_BITS_ACTIVE; ! 760: port->ip_timestamp = ipc_port_timestamp(); ! 761: ip_unlock(port); ! 762: ! 763: /* throw away no-senders request */ ! 764: ! 765: nsrequest = port->ip_nsrequest; ! 766: if (nsrequest != IP_NULL) ! 767: ipc_notify_send_once(nsrequest); /* consumes ref */ ! 768: ! 769: /* destroy any queued messages */ ! 770: ! 771: mqueue = &port->ip_messages; ! 772: imq_lock(mqueue); ! 773: assert(ipc_thread_queue_empty(&mqueue->imq_threads)); ! 774: kmqueue = &mqueue->imq_messages; ! 775: ! 776: while ((kmsg = ipc_kmsg_dequeue(kmqueue)) != IKM_NULL) { ! 777: imq_unlock(mqueue); ! 778: ! 779: assert(kmsg->ikm_header.msgh_remote_port == ! 780: (mach_port_t) port); ! 781: ! 782: ipc_port_release(port); ! 783: kmsg->ikm_header.msgh_remote_port = MACH_PORT_NULL; ! 784: ipc_kmsg_destroy(kmsg); ! 785: ! 786: imq_lock(mqueue); ! 787: } ! 788: ! 789: imq_unlock(mqueue); ! 790: ! 791: /* generate dead-name notifications */ ! 792: ! 793: dnrequests = port->ip_dnrequests; ! 794: if (dnrequests != IPR_NULL) { ! 795: ipc_table_size_t its = dnrequests->ipr_size; ! 796: ipc_table_elems_t size = its->its_size; ! 797: ipc_port_request_index_t index; ! 798: ! 799: for (index = 1; index < size; index++) { ! 800: ipc_port_request_t ipr = &dnrequests[index]; ! 801: mach_port_t name = ipr->ipr_name; ! 802: ipc_port_t soright; ! 803: ! 804: if (name == MACH_PORT_NULL) ! 805: continue; ! 806: ! 807: soright = ipr->ipr_soright; ! 808: assert(soright != IP_NULL); ! 809: ! 810: #if MACH_IPC_COMPAT ! 811: if (ipr_spacep(soright)) { ! 812: ipc_port_delete_compat(port, ! 813: ipr_space(soright), name); ! 814: continue; ! 815: } ! 816: #endif /* MACH_IPC_COMPAT */ ! 817: ! 818: ipc_notify_dead_name(soright, name); ! 819: } ! 820: ! 821: it_dnrequests_free(its, dnrequests); ! 822: } ! 823: ! 824: if (ip_kotype(port) != IKOT_NONE) ! 825: ipc_kobject_destroy(port); ! 826: ! 827: ipc_port_release(port); /* consume caller's ref */ ! 828: } ! 829: ! 830: /* ! 831: * Routine: ipc_port_check_circularity ! 832: * Purpose: ! 833: * Check if queueing "port" in a message for "dest" ! 834: * would create a circular group of ports and messages. ! 835: * ! 836: * If no circularity (FALSE returned), then "port" ! 837: * is changed from "in limbo" to "in transit". ! 838: * ! 839: * That is, we want to set port->ip_destination == dest, ! 840: * but guaranteeing that this doesn't create a circle ! 841: * port->ip_destination->ip_destination->... == port ! 842: * Conditions: ! 843: * No ports locked. References held for "port" and "dest". ! 844: */ ! 845: ! 846: boolean_t ! 847: ipc_port_check_circularity( ! 848: ipc_port_t port, ! 849: ipc_port_t dest) ! 850: { ! 851: ipc_port_t base; ! 852: ! 853: assert(port != IP_NULL); ! 854: assert(dest != IP_NULL); ! 855: ! 856: if (port == dest) ! 857: return TRUE; ! 858: base = dest; ! 859: ! 860: /* ! 861: * First try a quick check that can run in parallel. ! 862: * No circularity if dest is not in transit. ! 863: */ ! 864: ! 865: ip_lock(port); ! 866: if (ip_lock_try(dest)) { ! 867: if (!ip_active(dest) || ! 868: (dest->ip_receiver_name != MACH_PORT_NULL) || ! 869: (dest->ip_destination == IP_NULL)) ! 870: goto not_circular; ! 871: ! 872: /* dest is in transit; further checking necessary */ ! 873: ! 874: ip_unlock(dest); ! 875: } ! 876: ip_unlock(port); ! 877: ! 878: ipc_port_multiple_lock(); /* massive serialization */ ! 879: ! 880: /* ! 881: * Search for the end of the chain (a port not in transit), ! 882: * acquiring locks along the way. ! 883: */ ! 884: ! 885: for (;;) { ! 886: ip_lock(base); ! 887: ! 888: if (!ip_active(base) || ! 889: (base->ip_receiver_name != MACH_PORT_NULL) || ! 890: (base->ip_destination == IP_NULL)) ! 891: break; ! 892: ! 893: base = base->ip_destination; ! 894: } ! 895: ! 896: /* all ports in chain from dest to base, inclusive, are locked */ ! 897: ! 898: if (port == base) { ! 899: /* circularity detected! */ ! 900: ! 901: ipc_port_multiple_unlock(); ! 902: ! 903: /* port (== base) is in limbo */ ! 904: ! 905: assert(ip_active(port)); ! 906: assert(port->ip_receiver_name == MACH_PORT_NULL); ! 907: assert(port->ip_destination == IP_NULL); ! 908: ! 909: while (dest != IP_NULL) { ! 910: ipc_port_t next; ! 911: ! 912: /* dest is in transit or in limbo */ ! 913: ! 914: assert(ip_active(dest)); ! 915: assert(dest->ip_receiver_name == MACH_PORT_NULL); ! 916: ! 917: next = dest->ip_destination; ! 918: ip_unlock(dest); ! 919: dest = next; ! 920: } ! 921: ! 922: return TRUE; ! 923: } ! 924: ! 925: /* ! 926: * The guarantee: lock port while the entire chain is locked. ! 927: * Once port is locked, we can take a reference to dest, ! 928: * add port to the chain, and unlock everything. ! 929: */ ! 930: ! 931: ip_lock(port); ! 932: ipc_port_multiple_unlock(); ! 933: ! 934: not_circular: ! 935: ! 936: /* port is in limbo */ ! 937: ! 938: assert(ip_active(port)); ! 939: assert(port->ip_receiver_name == MACH_PORT_NULL); ! 940: assert(port->ip_destination == IP_NULL); ! 941: ! 942: ip_reference(dest); ! 943: port->ip_destination = dest; ! 944: ! 945: /* now unlock chain */ ! 946: ! 947: while (port != base) { ! 948: ipc_port_t next; ! 949: ! 950: /* port is in transit */ ! 951: ! 952: assert(ip_active(port)); ! 953: assert(port->ip_receiver_name == MACH_PORT_NULL); ! 954: assert(port->ip_destination != IP_NULL); ! 955: ! 956: next = port->ip_destination; ! 957: ip_unlock(port); ! 958: port = next; ! 959: } ! 960: ! 961: /* base is not in transit */ ! 962: ! 963: assert(!ip_active(base) || ! 964: (base->ip_receiver_name != MACH_PORT_NULL) || ! 965: (base->ip_destination == IP_NULL)); ! 966: ip_unlock(base); ! 967: ! 968: return FALSE; ! 969: } ! 970: ! 971: /* ! 972: * Routine: ipc_port_lookup_notify ! 973: * Purpose: ! 974: * Make a send-once notify port from a receive right. ! 975: * Returns IP_NULL if name doesn't denote a receive right. ! 976: * Conditions: ! 977: * The space must be locked (read or write) and active. ! 978: */ ! 979: ! 980: ipc_port_t ! 981: ipc_port_lookup_notify( ! 982: ipc_space_t space, ! 983: mach_port_t name) ! 984: { ! 985: ipc_port_t port; ! 986: ipc_entry_t entry; ! 987: ! 988: assert(space->is_active); ! 989: ! 990: entry = ipc_entry_lookup(space, name); ! 991: if (entry == IE_NULL) ! 992: return IP_NULL; ! 993: ! 994: if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0) ! 995: return IP_NULL; ! 996: ! 997: port = (ipc_port_t) entry->ie_object; ! 998: assert(port != IP_NULL); ! 999: ! 1000: ip_lock(port); ! 1001: assert(ip_active(port)); ! 1002: assert(port->ip_receiver_name == name); ! 1003: assert(port->ip_receiver == space); ! 1004: ! 1005: ip_reference(port); ! 1006: port->ip_sorights++; ! 1007: ip_unlock(port); ! 1008: ! 1009: return port; ! 1010: } ! 1011: ! 1012: /* ! 1013: * Routine: ipc_port_make_send ! 1014: * Purpose: ! 1015: * Make a naked send right from a receive right. ! 1016: * Conditions: ! 1017: * The port is not locked but it is active. ! 1018: */ ! 1019: ! 1020: ipc_port_t ! 1021: ipc_port_make_send( ! 1022: ipc_port_t port) ! 1023: { ! 1024: assert(IP_VALID(port)); ! 1025: ! 1026: ip_lock(port); ! 1027: assert(ip_active(port)); ! 1028: port->ip_mscount++; ! 1029: port->ip_srights++; ! 1030: ip_reference(port); ! 1031: ip_unlock(port); ! 1032: ! 1033: return port; ! 1034: } ! 1035: ! 1036: /* ! 1037: * Routine: ipc_port_copy_send ! 1038: * Purpose: ! 1039: * Make a naked send right from another naked send right. ! 1040: * IP_NULL -> IP_NULL ! 1041: * IP_DEAD -> IP_DEAD ! 1042: * dead port -> IP_DEAD ! 1043: * live port -> port + ref ! 1044: * Conditions: ! 1045: * Nothing locked except possibly a space. ! 1046: */ ! 1047: ! 1048: ipc_port_t ! 1049: ipc_port_copy_send( ! 1050: ipc_port_t port) ! 1051: { ! 1052: ipc_port_t sright; ! 1053: ! 1054: if (!IP_VALID(port)) ! 1055: return port; ! 1056: ! 1057: ip_lock(port); ! 1058: if (ip_active(port)) { ! 1059: assert(port->ip_srights > 0); ! 1060: ! 1061: ip_reference(port); ! 1062: port->ip_srights++; ! 1063: sright = port; ! 1064: } else ! 1065: sright = IP_DEAD; ! 1066: ip_unlock(port); ! 1067: ! 1068: return sright; ! 1069: } ! 1070: ! 1071: /* ! 1072: * Routine: ipc_port_copyout_send ! 1073: * Purpose: ! 1074: * Copyout a naked send right (possibly null/dead), ! 1075: * or if that fails, destroy the right. ! 1076: * Conditions: ! 1077: * Nothing locked. ! 1078: */ ! 1079: ! 1080: mach_port_t ! 1081: ipc_port_copyout_send( ! 1082: ipc_port_t sright, ! 1083: ipc_space_t space) ! 1084: { ! 1085: mach_port_t name; ! 1086: ! 1087: if (IP_VALID(sright)) { ! 1088: kern_return_t kr; ! 1089: ! 1090: kr = ipc_object_copyout(space, (ipc_object_t) sright, ! 1091: MACH_MSG_TYPE_PORT_SEND, TRUE, &name); ! 1092: if (kr != KERN_SUCCESS) { ! 1093: ipc_port_release_send(sright); ! 1094: ! 1095: if (kr == KERN_INVALID_CAPABILITY) ! 1096: name = MACH_PORT_DEAD; ! 1097: else ! 1098: name = MACH_PORT_NULL; ! 1099: } ! 1100: } else ! 1101: name = (mach_port_t) sright; ! 1102: ! 1103: return name; ! 1104: } ! 1105: ! 1106: /* ! 1107: * Routine: ipc_port_release_send ! 1108: * Purpose: ! 1109: * Release a (valid) naked send right. ! 1110: * Consumes a ref for the port. ! 1111: * Conditions: ! 1112: * Nothing locked. ! 1113: */ ! 1114: ! 1115: void ! 1116: ipc_port_release_send( ! 1117: ipc_port_t port) ! 1118: { ! 1119: ipc_port_t nsrequest = IP_NULL; ! 1120: mach_port_mscount_t mscount; ! 1121: ! 1122: assert(IP_VALID(port)); ! 1123: ! 1124: ip_lock(port); ! 1125: ip_release(port); ! 1126: ! 1127: if (!ip_active(port)) { ! 1128: ip_check_unlock(port); ! 1129: return; ! 1130: } ! 1131: ! 1132: assert(port->ip_srights > 0); ! 1133: ! 1134: if (--port->ip_srights == 0) { ! 1135: nsrequest = port->ip_nsrequest; ! 1136: if (nsrequest != IP_NULL) { ! 1137: port->ip_nsrequest = IP_NULL; ! 1138: mscount = port->ip_mscount; ! 1139: } ! 1140: } ! 1141: ! 1142: ip_unlock(port); ! 1143: ! 1144: if (nsrequest != IP_NULL) ! 1145: ipc_notify_no_senders(nsrequest, mscount); ! 1146: } ! 1147: ! 1148: /* ! 1149: * Routine: ipc_port_make_sonce ! 1150: * Purpose: ! 1151: * Make a naked send-once right from a receive right. ! 1152: * Conditions: ! 1153: * The port is not locked but it is active. ! 1154: */ ! 1155: ! 1156: ipc_port_t ! 1157: ipc_port_make_sonce( ! 1158: ipc_port_t port) ! 1159: { ! 1160: assert(IP_VALID(port)); ! 1161: ! 1162: ip_lock(port); ! 1163: assert(ip_active(port)); ! 1164: port->ip_sorights++; ! 1165: ip_reference(port); ! 1166: ip_unlock(port); ! 1167: ! 1168: return port; ! 1169: } ! 1170: ! 1171: /* ! 1172: * Routine: ipc_port_release_sonce ! 1173: * Purpose: ! 1174: * Release a naked send-once right. ! 1175: * Consumes a ref for the port. ! 1176: * ! 1177: * In normal situations, this is never used. ! 1178: * Send-once rights are only consumed when ! 1179: * a message (possibly a send-once notification) ! 1180: * is sent to them. ! 1181: * Conditions: ! 1182: * Nothing locked except possibly a space. ! 1183: */ ! 1184: ! 1185: void ! 1186: ipc_port_release_sonce( ! 1187: ipc_port_t port) ! 1188: { ! 1189: assert(IP_VALID(port)); ! 1190: ! 1191: ip_lock(port); ! 1192: ip_release(port); ! 1193: ! 1194: if (!ip_active(port)) { ! 1195: ip_check_unlock(port); ! 1196: return; ! 1197: } ! 1198: ! 1199: assert(port->ip_sorights > 0); ! 1200: ! 1201: port->ip_sorights--; ! 1202: ip_unlock(port); ! 1203: } ! 1204: ! 1205: /* ! 1206: * Routine: ipc_port_release_receive ! 1207: * Purpose: ! 1208: * Release a naked (in limbo or in transit) receive right. ! 1209: * Consumes a ref for the port; destroys the port. ! 1210: * Conditions: ! 1211: * Nothing locked. ! 1212: */ ! 1213: ! 1214: void ! 1215: ipc_port_release_receive( ! 1216: ipc_port_t port) ! 1217: { ! 1218: ipc_port_t dest; ! 1219: ! 1220: assert(IP_VALID(port)); ! 1221: ! 1222: ip_lock(port); ! 1223: assert(ip_active(port)); ! 1224: assert(port->ip_receiver_name == MACH_PORT_NULL); ! 1225: dest = port->ip_destination; ! 1226: ! 1227: ipc_port_destroy(port); /* consumes ref, unlocks */ ! 1228: ! 1229: if (dest != IP_NULL) ! 1230: ipc_port_release(dest); ! 1231: } ! 1232: ! 1233: /* ! 1234: * Routine: ipc_port_alloc_special ! 1235: * Purpose: ! 1236: * Allocate a port in a special space. ! 1237: * The new port is returned with one ref. ! 1238: * If unsuccessful, IP_NULL is returned. ! 1239: * Conditions: ! 1240: * Nothing locked. ! 1241: */ ! 1242: ! 1243: ipc_port_t ! 1244: ipc_port_alloc_special( ! 1245: ipc_space_t space) ! 1246: { ! 1247: ipc_port_t port; ! 1248: ! 1249: port = (ipc_port_t) io_alloc(IOT_PORT); ! 1250: if (port == IP_NULL) ! 1251: return IP_NULL; ! 1252: ! 1253: io_lock_init(&port->ip_object); ! 1254: port->ip_references = 1; ! 1255: port->ip_object.io_bits = io_makebits(TRUE, IOT_PORT, 0); ! 1256: ! 1257: /* ! 1258: * The actual values of ip_receiver_name aren't important, ! 1259: * as long as they are valid (not null/dead). ! 1260: */ ! 1261: ! 1262: ipc_port_init(port, space, 1); ! 1263: ! 1264: return port; ! 1265: } ! 1266: ! 1267: /* ! 1268: * Routine: ipc_port_dealloc_special ! 1269: * Purpose: ! 1270: * Deallocate a port in a special space. ! 1271: * Consumes one ref for the port. ! 1272: * Conditions: ! 1273: * Nothing locked. ! 1274: */ ! 1275: ! 1276: void ! 1277: ipc_port_dealloc_special( ! 1278: ipc_port_t port, ! 1279: ipc_space_t space) ! 1280: { ! 1281: ip_lock(port); ! 1282: assert(ip_active(port)); ! 1283: assert(port->ip_receiver_name != MACH_PORT_NULL); ! 1284: assert(port->ip_receiver == space); ! 1285: ! 1286: /* ! 1287: * We clear ip_receiver_name and ip_receiver to simplify ! 1288: * the ipc_space_kernel check in ipc_mqueue_send. ! 1289: */ ! 1290: ! 1291: port->ip_receiver_name = MACH_PORT_NULL; ! 1292: port->ip_receiver = IS_NULL; ! 1293: ! 1294: /* ! 1295: * For ipc_space_kernel, all ipc_port_clear_receiver does ! 1296: * is clean things up for the assertions in ipc_port_destroy. ! 1297: * For ipc_space_reply, there might be a waiting receiver. ! 1298: */ ! 1299: ! 1300: ipc_port_clear_receiver(port); ! 1301: ipc_port_destroy(port); ! 1302: } ! 1303: ! 1304: #if MACH_IPC_COMPAT ! 1305: ! 1306: /* ! 1307: * Routine: ipc_port_alloc_compat ! 1308: * Purpose: ! 1309: * Allocate a port. ! 1310: * Conditions: ! 1311: * Nothing locked. If successful, the port is returned ! 1312: * locked. (The caller doesn't have a reference.) ! 1313: * ! 1314: * Like ipc_port_alloc, except that the new entry ! 1315: * is IE_BITS_COMPAT. ! 1316: * Returns: ! 1317: * KERN_SUCCESS The port is allocated. ! 1318: * KERN_INVALID_TASK The space is dead. ! 1319: * KERN_NO_SPACE No room for an entry in the space. ! 1320: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. ! 1321: */ ! 1322: ! 1323: kern_return_t ! 1324: ipc_port_alloc_compat( ! 1325: ipc_space_t space, ! 1326: mach_port_t *namep, ! 1327: ipc_port_t *portp) ! 1328: { ! 1329: ipc_port_t port; ! 1330: ipc_entry_t entry; ! 1331: mach_port_t name; ! 1332: ipc_table_size_t its; ! 1333: ipc_port_request_t table; ! 1334: ipc_table_elems_t size; ! 1335: ipc_port_request_index_t free, i; ! 1336: kern_return_t kr; ! 1337: ! 1338: port = ip_alloc(); ! 1339: if (port == IP_NULL) ! 1340: return KERN_RESOURCE_SHORTAGE; ! 1341: ! 1342: its = &ipc_table_dnrequests[0]; ! 1343: table = it_dnrequests_alloc(its); ! 1344: if (table == IPR_NULL) { ! 1345: ip_free(port); ! 1346: return KERN_RESOURCE_SHORTAGE; ! 1347: } ! 1348: ! 1349: kr = ipc_entry_alloc(space, &name, &entry); ! 1350: if (kr != KERN_SUCCESS) { ! 1351: ip_free(port); ! 1352: it_dnrequests_free(its, table); ! 1353: return kr; ! 1354: } ! 1355: /* space is write-locked */ ! 1356: ! 1357: entry->ie_object = (ipc_object_t) port; ! 1358: entry->ie_request = 1; ! 1359: entry->ie_bits |= IE_BITS_COMPAT|MACH_PORT_TYPE_RECEIVE; ! 1360: ! 1361: ip_lock_init(port); ! 1362: ip_lock(port); ! 1363: is_write_unlock(space); ! 1364: ! 1365: port->ip_references = 1; /* for entry, not caller */ ! 1366: port->ip_bits = io_makebits(TRUE, IOT_PORT, 0); ! 1367: ! 1368: ipc_port_init(port, space, name); ! 1369: ! 1370: size = its->its_size; ! 1371: assert(size > 1); ! 1372: free = 0; ! 1373: ! 1374: for (i = 2; i < size; i++) { ! 1375: ipc_port_request_t ipr = &table[i]; ! 1376: ! 1377: ipr->ipr_name = MACH_PORT_NULL; ! 1378: ipr->ipr_next = free; ! 1379: free = i; ! 1380: } ! 1381: ! 1382: table->ipr_next = free; ! 1383: table->ipr_size = its; ! 1384: port->ip_dnrequests = table; ! 1385: ! 1386: table[1].ipr_name = name; ! 1387: table[1].ipr_soright = ipr_spacem(space); ! 1388: is_reference(space); ! 1389: ! 1390: *namep = name; ! 1391: *portp = port; ! 1392: return KERN_SUCCESS; ! 1393: } ! 1394: ! 1395: /* ! 1396: * Routine: ipc_port_copyout_send_compat ! 1397: * Purpose: ! 1398: * Copyout a naked send right (possibly null/dead), ! 1399: * or if that fails, destroy the right. ! 1400: * Like ipc_port_copyout_send, except that if a ! 1401: * new translation is created it has the compat bit. ! 1402: * Conditions: ! 1403: * Nothing locked. ! 1404: */ ! 1405: ! 1406: mach_port_t ! 1407: ipc_port_copyout_send_compat( ! 1408: ipc_port_t sright, ! 1409: ipc_space_t space) ! 1410: { ! 1411: mach_port_t name; ! 1412: ! 1413: if (IP_VALID(sright)) { ! 1414: kern_return_t kr; ! 1415: ! 1416: kr = ipc_object_copyout_compat(space, (ipc_object_t) sright, ! 1417: MACH_MSG_TYPE_PORT_SEND, &name); ! 1418: if (kr != KERN_SUCCESS) { ! 1419: ipc_port_release_send(sright); ! 1420: name = MACH_PORT_NULL; ! 1421: } ! 1422: } else ! 1423: name = (mach_port_t) sright; ! 1424: ! 1425: return name; ! 1426: } ! 1427: ! 1428: /* ! 1429: * Routine: ipc_port_copyout_receiver ! 1430: * Purpose: ! 1431: * Copyout a port reference (possibly null) ! 1432: * by giving the caller his name for the port, ! 1433: * if he is the receiver. ! 1434: * Conditions: ! 1435: * Nothing locked. Consumes a ref for the port. ! 1436: */ ! 1437: ! 1438: mach_port_t ! 1439: ipc_port_copyout_receiver( ! 1440: ipc_port_t port, ! 1441: ipc_space_t space) ! 1442: { ! 1443: mach_port_t name; ! 1444: ! 1445: if (!IP_VALID(port)) ! 1446: return MACH_PORT_NULL; ! 1447: ! 1448: ip_lock(port); ! 1449: if (port->ip_receiver == space) { ! 1450: name = port->ip_receiver_name; ! 1451: assert(MACH_PORT_VALID(name)); ! 1452: } else ! 1453: name = MACH_PORT_NULL; ! 1454: ! 1455: ip_release(port); ! 1456: ip_check_unlock(port); ! 1457: ! 1458: return name; ! 1459: } ! 1460: ! 1461: #endif /* MACH_IPC_COMPAT */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.