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