|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * @OSF_COPYRIGHT@ ! 24: */ ! 25: /* ! 26: * Mach Operating System ! 27: * Copyright (c) 1991,1990,1989 Carnegie Mellon University ! 28: * All Rights Reserved. ! 29: * ! 30: * Permission to use, copy, modify and distribute this software and its ! 31: * documentation is hereby granted, provided that both the copyright ! 32: * notice and this permission notice appear in all copies of the ! 33: * software, derivative works or modified versions, and any portions ! 34: * thereof, and that both notices appear in supporting documentation. ! 35: * ! 36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 39: * ! 40: * Carnegie Mellon requests users of this software to return to ! 41: * ! 42: * Software Distribution Coordinator or [email protected] ! 43: * School of Computer Science ! 44: * Carnegie Mellon University ! 45: * Pittsburgh PA 15213-3890 ! 46: * ! 47: * any improvements or extensions that they make and grant Carnegie Mellon ! 48: * the rights to redistribute these changes. ! 49: */ ! 50: /* ! 51: */ ! 52: /* ! 53: * File: ipc/mach_port.c ! 54: * Author: Rich Draves ! 55: * Date: 1989 ! 56: * ! 57: * Exported kernel calls. See mach/mach_port.defs. ! 58: */ ! 59: ! 60: #include <mach_debug.h> ! 61: #include <mach_rt.h> ! 62: ! 63: #include <mach/port.h> ! 64: #include <mach/kern_return.h> ! 65: #include <mach/notify.h> ! 66: #include <mach/mach_param.h> ! 67: #include <mach/vm_param.h> ! 68: #include <mach/vm_prot.h> ! 69: #include <kern/task.h> ! 70: #include <kern/counters.h> ! 71: #include <kern/thread_act.h> ! 72: #include <kern/thread_pool.h> ! 73: #include <mach/mach_port_server.h> ! 74: #include <vm/vm_map.h> ! 75: #include <vm/vm_kern.h> ! 76: #include <vm/vm_user.h> ! 77: #include <ipc/ipc_entry.h> ! 78: #include <ipc/ipc_space.h> ! 79: #include <ipc/ipc_object.h> ! 80: #include <ipc/ipc_notify.h> ! 81: #include <ipc/ipc_port.h> ! 82: #include <ipc/ipc_pset.h> ! 83: #include <ipc/ipc_right.h> ! 84: #include <kern/misc_protos.h> ! 85: ! 86: /* ! 87: * Forward declarations ! 88: */ ! 89: void mach_port_names_helper( ! 90: ipc_port_timestamp_t timestamp, ! 91: ipc_entry_t entry, ! 92: mach_port_name_t name, ! 93: mach_port_name_t *names, ! 94: mach_port_type_t *types, ! 95: ipc_entry_num_t *actualp, ! 96: ipc_space_t space); ! 97: ! 98: void mach_port_gst_helper( ! 99: ipc_pset_t pset, ! 100: ipc_port_t port, ! 101: ipc_entry_num_t maxnames, ! 102: mach_port_name_t *names, ! 103: ipc_entry_num_t *actualp); ! 104: ! 105: ! 106: /* Zeroed template of qos flags */ ! 107: ! 108: static mach_port_qos_t qos_template; ! 109: ! 110: /* ! 111: * Routine: mach_port_names_helper ! 112: * Purpose: ! 113: * A helper function for mach_port_names. ! 114: */ ! 115: ! 116: void ! 117: mach_port_names_helper( ! 118: ipc_port_timestamp_t timestamp, ! 119: ipc_entry_t entry, ! 120: mach_port_name_t name, ! 121: mach_port_name_t *names, ! 122: mach_port_type_t *types, ! 123: ipc_entry_num_t *actualp, ! 124: ipc_space_t space) ! 125: { ! 126: ipc_entry_bits_t bits; ! 127: ipc_port_request_index_t request; ! 128: mach_port_type_t type; ! 129: ipc_entry_num_t actual; ! 130: ! 131: bits = entry->ie_bits; ! 132: request = entry->ie_request; ! 133: if (bits & MACH_PORT_TYPE_SEND_RIGHTS) { ! 134: ipc_port_t port; ! 135: boolean_t died; ! 136: ! 137: port = (ipc_port_t) entry->ie_object; ! 138: assert(port != IP_NULL); ! 139: ! 140: /* ! 141: * The timestamp serializes mach_port_names ! 142: * with ipc_port_destroy. If the port died, ! 143: * but after mach_port_names started, pretend ! 144: * that it isn't dead. ! 145: */ ! 146: ! 147: ip_lock(port); ! 148: died = (!ip_active(port) && ! 149: IP_TIMESTAMP_ORDER(port->ip_timestamp, timestamp)); ! 150: ip_unlock(port); ! 151: ! 152: if (died) { ! 153: /* pretend this is a dead-name entry */ ! 154: ! 155: bits &= ~(IE_BITS_TYPE_MASK); ! 156: bits |= MACH_PORT_TYPE_DEAD_NAME; ! 157: if (request != 0) ! 158: bits++; ! 159: request = 0; ! 160: } ! 161: } ! 162: ! 163: type = IE_BITS_TYPE(bits); ! 164: if (request != 0) ! 165: type |= MACH_PORT_TYPE_DNREQUEST; ! 166: ! 167: actual = *actualp; ! 168: names[actual] = name; ! 169: types[actual] = type; ! 170: *actualp = actual+1; ! 171: } ! 172: ! 173: /* ! 174: * Routine: mach_port_names [kernel call] ! 175: * Purpose: ! 176: * Retrieves a list of the rights present in the space, ! 177: * along with type information. (Same as returned ! 178: * by mach_port_type.) The names are returned in ! 179: * no particular order, but they (and the type info) ! 180: * are an accurate snapshot of the space. ! 181: * Conditions: ! 182: * Nothing locked. ! 183: * Returns: ! 184: * KERN_SUCCESS Arrays of names and types returned. ! 185: * KERN_INVALID_TASK The space is null. ! 186: * KERN_INVALID_TASK The space is dead. ! 187: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. ! 188: */ ! 189: ! 190: kern_return_t ! 191: mach_port_names( ! 192: ipc_space_t space, ! 193: mach_port_name_t **namesp, ! 194: mach_msg_type_number_t *namesCnt, ! 195: mach_port_type_t **typesp, ! 196: mach_msg_type_number_t *typesCnt) ! 197: { ! 198: ipc_entry_bits_t *capability; ! 199: ipc_tree_entry_t tentry; ! 200: ipc_entry_t table; ! 201: ipc_entry_num_t tsize; ! 202: mach_port_index_t index; ! 203: ipc_entry_num_t actual; /* this many names */ ! 204: ipc_port_timestamp_t timestamp; /* logical time of this operation */ ! 205: mach_port_name_t *names; ! 206: mach_port_type_t *types; ! 207: kern_return_t kr; ! 208: ! 209: vm_size_t size; /* size of allocated memory */ ! 210: vm_offset_t addr1; /* allocated memory, for names */ ! 211: vm_offset_t addr2; /* allocated memory, for types */ ! 212: vm_map_copy_t memory1; /* copied-in memory, for names */ ! 213: vm_map_copy_t memory2; /* copied-in memory, for types */ ! 214: ! 215: /* safe simplifying assumption */ ! 216: assert_static(sizeof(mach_port_name_t) == sizeof(mach_port_type_t)); ! 217: ! 218: if (space == IS_NULL) ! 219: return KERN_INVALID_TASK; ! 220: ! 221: size = 0; ! 222: ! 223: for (;;) { ! 224: ipc_entry_num_t bound; ! 225: vm_size_t size_needed; ! 226: ! 227: is_read_lock(space); ! 228: if (!space->is_active) { ! 229: is_read_unlock(space); ! 230: if (size != 0) { ! 231: kmem_free(ipc_kernel_map, addr1, size); ! 232: kmem_free(ipc_kernel_map, addr2, size); ! 233: } ! 234: return KERN_INVALID_TASK; ! 235: } ! 236: ! 237: /* upper bound on number of names in the space */ ! 238: ! 239: bound = space->is_table_size + space->is_tree_total; ! 240: size_needed = round_page(bound * sizeof(mach_port_name_t)); ! 241: ! 242: if (size_needed <= size) ! 243: break; ! 244: ! 245: is_read_unlock(space); ! 246: ! 247: if (size != 0) { ! 248: kmem_free(ipc_kernel_map, addr1, size); ! 249: kmem_free(ipc_kernel_map, addr2, size); ! 250: } ! 251: size = size_needed; ! 252: ! 253: kr = vm_allocate(ipc_kernel_map, &addr1, size, TRUE); ! 254: if (kr != KERN_SUCCESS) ! 255: return KERN_RESOURCE_SHORTAGE; ! 256: ! 257: kr = vm_allocate(ipc_kernel_map, &addr2, size, TRUE); ! 258: if (kr != KERN_SUCCESS) { ! 259: kmem_free(ipc_kernel_map, addr1, size); ! 260: return KERN_RESOURCE_SHORTAGE; ! 261: } ! 262: ! 263: /* can't fault while we hold locks */ ! 264: ! 265: kr = vm_map_wire(ipc_kernel_map, addr1, addr1 + size, ! 266: VM_PROT_READ|VM_PROT_WRITE, FALSE); ! 267: assert(kr == KERN_SUCCESS); ! 268: ! 269: kr = vm_map_wire(ipc_kernel_map, addr2, addr2 + size, ! 270: VM_PROT_READ|VM_PROT_WRITE, FALSE); ! 271: assert(kr == KERN_SUCCESS); ! 272: } ! 273: /* space is read-locked and active */ ! 274: ! 275: names = (mach_port_name_t *) addr1; ! 276: types = (mach_port_type_t *) addr2; ! 277: actual = 0; ! 278: ! 279: timestamp = ipc_port_timestamp(); ! 280: ! 281: table = space->is_table; ! 282: tsize = space->is_table_size; ! 283: ! 284: for (index = 0; index < tsize; index++) { ! 285: ipc_entry_t entry = &table[index]; ! 286: ipc_entry_bits_t bits = entry->ie_bits; ! 287: ! 288: if (IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE) { ! 289: mach_port_name_t name; ! 290: ! 291: name = MACH_PORT_MAKE(index, IE_BITS_GEN(bits)); ! 292: mach_port_names_helper(timestamp, entry, name, names, ! 293: types, &actual, space); ! 294: } ! 295: } ! 296: ! 297: for (tentry = ipc_splay_traverse_start(&space->is_tree); ! 298: tentry != ITE_NULL; ! 299: tentry = ipc_splay_traverse_next(&space->is_tree, FALSE)) { ! 300: ipc_entry_t entry = &tentry->ite_entry; ! 301: mach_port_name_t name = tentry->ite_name; ! 302: ! 303: assert(IE_BITS_TYPE(tentry->ite_bits) != MACH_PORT_TYPE_NONE); ! 304: mach_port_names_helper(timestamp, entry, name, names, ! 305: types, &actual, space); ! 306: } ! 307: ipc_splay_traverse_finish(&space->is_tree); ! 308: is_read_unlock(space); ! 309: ! 310: if (actual == 0) { ! 311: memory1 = VM_MAP_COPY_NULL; ! 312: memory2 = VM_MAP_COPY_NULL; ! 313: ! 314: if (size != 0) { ! 315: kmem_free(ipc_kernel_map, addr1, size); ! 316: kmem_free(ipc_kernel_map, addr2, size); ! 317: } ! 318: } else { ! 319: vm_size_t size_used; ! 320: vm_size_t vm_size_used; ! 321: ! 322: size_used = actual * sizeof(mach_port_name_t); ! 323: vm_size_used = round_page(size_used); ! 324: ! 325: /* ! 326: * Make used memory pageable and get it into ! 327: * copied-in form. Free any unused memory. ! 328: */ ! 329: ! 330: kr = vm_map_unwire(ipc_kernel_map, ! 331: addr1, addr1 + vm_size_used, FALSE); ! 332: assert(kr == KERN_SUCCESS); ! 333: ! 334: kr = vm_map_unwire(ipc_kernel_map, ! 335: addr2, addr2 + vm_size_used, FALSE); ! 336: assert(kr == KERN_SUCCESS); ! 337: ! 338: kr = vm_map_copyin(ipc_kernel_map, addr1, size_used, ! 339: TRUE, &memory1); ! 340: assert(kr == KERN_SUCCESS); ! 341: ! 342: kr = vm_map_copyin(ipc_kernel_map, addr2, size_used, ! 343: TRUE, &memory2); ! 344: assert(kr == KERN_SUCCESS); ! 345: ! 346: if (vm_size_used != size) { ! 347: kmem_free(ipc_kernel_map, ! 348: addr1 + vm_size_used, size - vm_size_used); ! 349: kmem_free(ipc_kernel_map, ! 350: addr2 + vm_size_used, size - vm_size_used); ! 351: } ! 352: } ! 353: ! 354: *namesp = (mach_port_name_t *) memory1; ! 355: *namesCnt = actual; ! 356: *typesp = (mach_port_type_t *) memory2; ! 357: *typesCnt = actual; ! 358: return KERN_SUCCESS; ! 359: } ! 360: ! 361: /* ! 362: * Routine: mach_port_type [kernel call] ! 363: * Purpose: ! 364: * Retrieves the type of a right in the space. ! 365: * The type is a bitwise combination of one or more ! 366: * of the following type bits: ! 367: * MACH_PORT_TYPE_SEND ! 368: * MACH_PORT_TYPE_RECEIVE ! 369: * MACH_PORT_TYPE_SEND_ONCE ! 370: * MACH_PORT_TYPE_PORT_SET ! 371: * MACH_PORT_TYPE_DEAD_NAME ! 372: * In addition, the following pseudo-type bits may be present: ! 373: * MACH_PORT_TYPE_DNREQUEST ! 374: * A dead-name notification is requested. ! 375: * Conditions: ! 376: * Nothing locked. ! 377: * Returns: ! 378: * KERN_SUCCESS Type is returned. ! 379: * KERN_INVALID_TASK The space is null. ! 380: * KERN_INVALID_TASK The space is dead. ! 381: * KERN_INVALID_NAME The name doesn't denote a right. ! 382: */ ! 383: ! 384: kern_return_t ! 385: mach_port_type( ! 386: ipc_space_t space, ! 387: mach_port_name_t name, ! 388: mach_port_type_t *typep) ! 389: { ! 390: mach_port_urefs_t urefs; ! 391: ipc_entry_t entry; ! 392: kern_return_t kr; ! 393: ! 394: if (space == IS_NULL) ! 395: return KERN_INVALID_TASK; ! 396: ! 397: kr = ipc_right_lookup_write(space, name, &entry); ! 398: if (kr != KERN_SUCCESS) ! 399: return kr; ! 400: /* space is write-locked and active */ ! 401: ! 402: kr = ipc_right_info(space, name, entry, typep, &urefs); ! 403: if (kr == KERN_SUCCESS) ! 404: is_write_unlock(space); ! 405: /* space is unlocked */ ! 406: return kr; ! 407: } ! 408: ! 409: /* ! 410: * Routine: mach_port_rename [kernel call] ! 411: * Purpose: ! 412: * Changes the name denoting a right, ! 413: * from oname to nname. ! 414: * Conditions: ! 415: * Nothing locked. ! 416: * Returns: ! 417: * KERN_SUCCESS The right is renamed. ! 418: * KERN_INVALID_TASK The space is null. ! 419: * KERN_INVALID_TASK The space is dead. ! 420: * KERN_INVALID_NAME The oname doesn't denote a right. ! 421: * KERN_INVALID_VALUE The nname isn't a legal name. ! 422: * KERN_NAME_EXISTS The nname already denotes a right. ! 423: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. ! 424: */ ! 425: ! 426: kern_return_t ! 427: mach_port_rename( ! 428: ipc_space_t space, ! 429: mach_port_name_t oname, ! 430: mach_port_name_t nname) ! 431: { ! 432: if (space == IS_NULL) ! 433: return KERN_INVALID_TASK; ! 434: ! 435: if (!MACH_PORT_VALID(nname)) ! 436: return KERN_INVALID_VALUE; ! 437: ! 438: return ipc_object_rename(space, oname, nname); ! 439: } ! 440: ! 441: /* ! 442: * Routine: mach_port_allocate_name [kernel call] ! 443: * Purpose: ! 444: * Allocates a right in a space, using a specific name ! 445: * for the new right. Possible rights: ! 446: * MACH_PORT_RIGHT_RECEIVE ! 447: * MACH_PORT_RIGHT_PORT_SET ! 448: * MACH_PORT_RIGHT_DEAD_NAME ! 449: * ! 450: * A new port (allocated with MACH_PORT_RIGHT_RECEIVE) ! 451: * has no extant send or send-once rights and no queued ! 452: * messages. Its queue limit is MACH_PORT_QLIMIT_DEFAULT ! 453: * and its make-send count is 0. It is not a member of ! 454: * a port set. It has no registered no-senders or ! 455: * port-destroyed notification requests. ! 456: * ! 457: * A new port set has no members. ! 458: * ! 459: * A new dead name has one user reference. ! 460: * Conditions: ! 461: * Nothing locked. ! 462: * Returns: ! 463: * KERN_SUCCESS The right is allocated. ! 464: * KERN_INVALID_TASK The space is null. ! 465: * KERN_INVALID_TASK The space is dead. ! 466: * KERN_INVALID_VALUE The name isn't a legal name. ! 467: * KERN_INVALID_VALUE "right" isn't a legal kind of right. ! 468: * KERN_NAME_EXISTS The name already denotes a right. ! 469: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. ! 470: * ! 471: * Restrictions on name allocation: NT bits are reserved by kernel, ! 472: * must be set on any chosen name. Can't do this at all in kernel ! 473: * loaded server. ! 474: */ ! 475: ! 476: kern_return_t ! 477: mach_port_allocate_name( ! 478: ipc_space_t space, ! 479: mach_port_right_t right, ! 480: mach_port_name_t name) ! 481: { ! 482: kern_return_t kr; ! 483: mach_port_qos_t qos = qos_template; ! 484: ! 485: qos.name = TRUE; ! 486: ! 487: kr = mach_port_allocate_full (space, right, SUBSYSTEM_NULL, ! 488: &qos, &name); ! 489: return (kr); ! 490: } ! 491: ! 492: /* ! 493: * Routine: mach_port_allocate [kernel call] ! 494: * Purpose: ! 495: * Allocates a right in a space. Like mach_port_allocate_name, ! 496: * except that the implementation picks a name for the right. ! 497: * The name may be any legal name in the space that doesn't ! 498: * currently denote a right. ! 499: * Conditions: ! 500: * Nothing locked. ! 501: * Returns: ! 502: * KERN_SUCCESS The right is allocated. ! 503: * KERN_INVALID_TASK The space is null. ! 504: * KERN_INVALID_TASK The space is dead. ! 505: * KERN_INVALID_VALUE "right" isn't a legal kind of right. ! 506: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. ! 507: * KERN_NO_SPACE No room in space for another right. ! 508: */ ! 509: ! 510: kern_return_t ! 511: mach_port_allocate( ! 512: ipc_space_t space, ! 513: mach_port_right_t right, ! 514: mach_port_name_t *namep) ! 515: { ! 516: kern_return_t kr; ! 517: mach_port_qos_t qos = qos_template; ! 518: ! 519: kr = mach_port_allocate_full (space, right, SUBSYSTEM_NULL, ! 520: &qos, namep); ! 521: return (kr); ! 522: } ! 523: ! 524: /* ! 525: * Routine: mach_port_allocate_qos [kernel call] ! 526: * Purpose: ! 527: * Allocates a right, with qos options, in a space. Like ! 528: * mach_port_allocate_name, except that the implementation ! 529: * picks a name for the right. The name may be any legal name ! 530: * in the space that doesn't currently denote a right. ! 531: * Conditions: ! 532: * Nothing locked. ! 533: * Returns: ! 534: * KERN_SUCCESS The right is allocated. ! 535: * KERN_INVALID_TASK The space is null. ! 536: * KERN_INVALID_TASK The space is dead. ! 537: * KERN_INVALID_VALUE "right" isn't a legal kind of right. ! 538: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. ! 539: * KERN_NO_SPACE No room in space for another right. ! 540: */ ! 541: ! 542: kern_return_t ! 543: mach_port_allocate_qos( ! 544: ipc_space_t space, ! 545: mach_port_right_t right, ! 546: mach_port_qos_t *qosp, ! 547: mach_port_name_t *namep) ! 548: { ! 549: kern_return_t kr; ! 550: ! 551: kr = mach_port_allocate_full (space, right, SUBSYSTEM_NULL, ! 552: qosp, namep); ! 553: return (kr); ! 554: } ! 555: ! 556: /* ! 557: * Routine: mach_port_allocate_subsystem [kernel call] ! 558: * Purpose: ! 559: * Allocates a receive right in a space. Like ! 560: * mach_port_allocate, except that the caller specifies an ! 561: * RPC subsystem that is to be used to implement RPC's to the ! 562: * port. When possible, allocate rpc subsystem ports without ! 563: * nms, since within RPC ports are intended to be used for ! 564: * identity only (i.e. nms is painful in the distributed case ! 565: * and we don't need or want it for RPC anyway). ! 566: * Conditions: ! 567: * Nothing locked. ! 568: * Returns: ! 569: * KERN_SUCCESS The right is allocated. ! 570: * KERN_INVALID_TASK The space is null. ! 571: * KERN_INVALID_TASK The space is dead. ! 572: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. ! 573: * KERN_NO_SPACE No room in space for another right. ! 574: * KERN_INVALID_ARGUMENT bogus subsystem ! 575: */ ! 576: ! 577: kern_return_t ! 578: mach_port_allocate_subsystem( ! 579: ipc_space_t space, ! 580: subsystem_t subsystem, ! 581: mach_port_name_t *namep) ! 582: { ! 583: kern_return_t kr; ! 584: ipc_port_t port; ! 585: mach_port_qos_t qos = qos_template; ! 586: ! 587: kr = mach_port_allocate_full (space, ! 588: #if TEMPORARY_NO_NMS ! 589: MACH_PORT_RIGHT_RECEIVE_NO_NMS, ! 590: #else ! 591: MACH_PORT_RIGHT_RECEIVE, ! 592: #endif /* TEMPORARY_NO_NMS */ ! 593: subsystem, &qos, namep); ! 594: return (kr); ! 595: } ! 596: ! 597: /* ! 598: * Routine: mach_port_allocate_full [kernel call] ! 599: * Purpose: ! 600: * Allocates a right in a space. Supports all of the ! 601: * special cases, such as specifying a subsystem, ! 602: * a specific name, a real-time port, etc. ! 603: * The name may be any legal name in the space that doesn't ! 604: * currently denote a right. ! 605: * Conditions: ! 606: * Nothing locked. ! 607: * Returns: ! 608: * KERN_SUCCESS The right is allocated. ! 609: * KERN_INVALID_TASK The space is null. ! 610: * KERN_INVALID_TASK The space is dead. ! 611: * KERN_INVALID_VALUE "right" isn't a legal kind of right. ! 612: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. ! 613: * KERN_NO_SPACE No room in space for another right. ! 614: */ ! 615: #if TEMPORARY_NO_NMS ! 616: counter(unsigned int c_mpalloc_fast = 0;) ! 617: #endif /* TEMPORARY_NO_NMS */ ! 618: ! 619: kern_return_t ! 620: mach_port_allocate_full( ! 621: ipc_space_t space, ! 622: mach_port_right_t right, ! 623: subsystem_t subsystem, ! 624: mach_port_qos_t *qosp, ! 625: mach_port_name_t *namep) ! 626: { ! 627: kern_return_t kr; ! 628: ! 629: if (space == IS_NULL) ! 630: return (KERN_INVALID_TASK); ! 631: ! 632: if (qosp->name) { ! 633: if (!MACH_PORT_VALID (*namep)) ! 634: return (KERN_INVALID_VALUE); ! 635: if (is_fast_space (space)) ! 636: return (KERN_FAILURE); ! 637: } ! 638: ! 639: if (subsystem != SUBSYSTEM_NULL) { ! 640: if (right != MACH_PORT_RIGHT_RECEIVE ! 641: #if TEMPORARY_NO_NMS ! 642: && right != MACH_PORT_RIGHT_RECEIVE_NO_NMS ! 643: #endif /* TEMPORARY_NO_NMS */ ! 644: ) ! 645: return (KERN_INVALID_VALUE); ! 646: } ! 647: ! 648: if (qosp->rt) { ! 649: #if MACH_RT ! 650: if (right != MACH_PORT_RIGHT_RECEIVE) ! 651: return (KERN_INVALID_VALUE); ! 652: #else /* MACH_RT */ ! 653: return (KERN_INVALID_ARGUMENT); ! 654: #endif /* MACH_RT */ ! 655: } ! 656: ! 657: switch (right) { ! 658: #if TEMPORARY_NO_NMS ! 659: case MACH_PORT_RIGHT_RECEIVE_NO_NMS: ! 660: { ! 661: ipc_port_t port; ! 662: ! 663: if (qosp->name) ! 664: kr = ipc_port_alloc_name(space, *namep, &port); ! 665: else ! 666: kr = ipc_port_alloc(space, namep, &port); ! 667: if (kr == KERN_SUCCESS) { ! 668: counter(++c_mpalloc_fast); ! 669: IP_CLEAR_NMS(port); ! 670: ! 671: #if MACH_RT ! 672: if (qosp->rt) ! 673: port->ip_flags |= IPC_PORT_FLAGS_RT; ! 674: #endif /* MACH_RT */ ! 675: ! 676: if (subsystem != SUBSYSTEM_NULL) { ! 677: port->ip_subsystem = &subsystem->user; ! 678: subsystem_reference (subsystem); ! 679: } ! 680: ip_unlock(port); ! 681: } ! 682: break; ! 683: } ! 684: #endif /* TEMPORARY_NO_NMS */ ! 685: ! 686: case MACH_PORT_RIGHT_RECEIVE: ! 687: { ! 688: ipc_port_t port; ! 689: ! 690: if (qosp->name) ! 691: kr = ipc_port_alloc_name(space, *namep, &port); ! 692: else ! 693: kr = ipc_port_alloc(space, namep, &port); ! 694: if (kr == KERN_SUCCESS) { ! 695: #if MACH_RT ! 696: if (qosp->rt) ! 697: port->ip_flags |= IPC_PORT_FLAGS_RT; ! 698: #endif /* MACH_RT */ ! 699: ! 700: if (subsystem != SUBSYSTEM_NULL) { ! 701: port->ip_subsystem = &subsystem->user; ! 702: subsystem_reference (subsystem); ! 703: } ! 704: ip_unlock(port); ! 705: } ! 706: break; ! 707: } ! 708: ! 709: case MACH_PORT_RIGHT_PORT_SET: ! 710: { ! 711: ipc_pset_t pset; ! 712: ! 713: if (qosp->name) ! 714: kr = ipc_pset_alloc_name(space, *namep, &pset); ! 715: else ! 716: kr = ipc_pset_alloc(space, namep, &pset); ! 717: if (kr == KERN_SUCCESS) ! 718: ips_unlock(pset); ! 719: break; ! 720: } ! 721: ! 722: case MACH_PORT_RIGHT_DEAD_NAME: ! 723: kr = ipc_object_alloc_dead(space, namep); ! 724: break; ! 725: ! 726: default: ! 727: kr = KERN_INVALID_VALUE; ! 728: break; ! 729: } ! 730: ! 731: return (kr); ! 732: } ! 733: ! 734: /* ! 735: * Routine: mach_port_destroy [kernel call] ! 736: * Purpose: ! 737: * Cleans up and destroys all rights denoted by a name ! 738: * in a space. The destruction of a receive right ! 739: * destroys the port, unless a port-destroyed request ! 740: * has been made for it; the destruction of a port-set right ! 741: * destroys the port set. ! 742: * Conditions: ! 743: * Nothing locked. ! 744: * Returns: ! 745: * KERN_SUCCESS The name is destroyed. ! 746: * KERN_INVALID_TASK The space is null. ! 747: * KERN_INVALID_TASK The space is dead. ! 748: * KERN_INVALID_NAME The name doesn't denote a right. ! 749: */ ! 750: ! 751: kern_return_t ! 752: mach_port_destroy( ! 753: ipc_space_t space, ! 754: mach_port_name_t name) ! 755: { ! 756: ipc_entry_t entry; ! 757: kern_return_t kr; ! 758: ! 759: if (space == IS_NULL) ! 760: return KERN_INVALID_TASK; ! 761: ! 762: kr = ipc_right_lookup_write(space, name, &entry); ! 763: if (kr != KERN_SUCCESS) ! 764: return kr; ! 765: /* space is write-locked and active */ ! 766: ! 767: kr = ipc_right_destroy(space, name, entry); ! 768: is_write_unlock(space); ! 769: return kr; ! 770: } ! 771: ! 772: /* ! 773: * Routine: mach_port_deallocate [kernel call] ! 774: * Purpose: ! 775: * Deallocates a user reference from a send right, ! 776: * send-once right, or a dead-name right. May ! 777: * deallocate the right, if this is the last uref, ! 778: * and destroy the name, if it doesn't denote ! 779: * other rights. ! 780: * Conditions: ! 781: * Nothing locked. ! 782: * Returns: ! 783: * KERN_SUCCESS The uref is deallocated. ! 784: * KERN_INVALID_TASK The space is null. ! 785: * KERN_INVALID_TASK The space is dead. ! 786: * KERN_INVALID_NAME The name doesn't denote a right. ! 787: * KERN_INVALID_RIGHT The right isn't correct. ! 788: */ ! 789: ! 790: kern_return_t ! 791: mach_port_deallocate( ! 792: ipc_space_t space, ! 793: mach_port_name_t name) ! 794: { ! 795: ipc_entry_t entry; ! 796: kern_return_t kr; ! 797: ! 798: if (space == IS_NULL) ! 799: return KERN_INVALID_TASK; ! 800: ! 801: kr = ipc_right_lookup_write(space, name, &entry); ! 802: if (kr != KERN_SUCCESS) ! 803: return kr; ! 804: /* space is write-locked */ ! 805: ! 806: kr = ipc_right_dealloc(space, name, entry); /* unlocks space */ ! 807: return kr; ! 808: } ! 809: ! 810: /* ! 811: * Routine: mach_port_get_refs [kernel call] ! 812: * Purpose: ! 813: * Retrieves the number of user references held by a right. ! 814: * Receive rights, port-set rights, and send-once rights ! 815: * always have one user reference. Returns zero if the ! 816: * name denotes a right, but not the queried right. ! 817: * Conditions: ! 818: * Nothing locked. ! 819: * Returns: ! 820: * KERN_SUCCESS Number of urefs returned. ! 821: * KERN_INVALID_TASK The space is null. ! 822: * KERN_INVALID_TASK The space is dead. ! 823: * KERN_INVALID_VALUE "right" isn't a legal value. ! 824: * KERN_INVALID_NAME The name doesn't denote a right. ! 825: */ ! 826: ! 827: kern_return_t ! 828: mach_port_get_refs( ! 829: ipc_space_t space, ! 830: mach_port_name_t name, ! 831: mach_port_right_t right, ! 832: mach_port_urefs_t *urefsp) ! 833: { ! 834: mach_port_type_t type; ! 835: mach_port_urefs_t urefs; ! 836: ipc_entry_t entry; ! 837: kern_return_t kr; ! 838: ! 839: if (space == IS_NULL) ! 840: return KERN_INVALID_TASK; ! 841: ! 842: if (right >= MACH_PORT_RIGHT_NUMBER) ! 843: return KERN_INVALID_VALUE; ! 844: ! 845: kr = ipc_right_lookup_write(space, name, &entry); ! 846: if (kr != KERN_SUCCESS) ! 847: return kr; ! 848: /* space is write-locked and active */ ! 849: ! 850: kr = ipc_right_info(space, name, entry, &type, &urefs); /* unlocks */ ! 851: if (kr != KERN_SUCCESS) ! 852: return kr; /* space is unlocked */ ! 853: is_write_unlock(space); ! 854: ! 855: if (type & MACH_PORT_TYPE(right)) ! 856: switch (right) { ! 857: case MACH_PORT_RIGHT_SEND_ONCE: ! 858: assert(urefs == 1); ! 859: /* fall-through */ ! 860: ! 861: case MACH_PORT_RIGHT_PORT_SET: ! 862: case MACH_PORT_RIGHT_RECEIVE: ! 863: *urefsp = 1; ! 864: break; ! 865: ! 866: case MACH_PORT_RIGHT_DEAD_NAME: ! 867: case MACH_PORT_RIGHT_SEND: ! 868: assert(urefs > 0); ! 869: *urefsp = urefs; ! 870: break; ! 871: ! 872: default: ! 873: panic("mach_port_get_refs: strange rights"); ! 874: } ! 875: else ! 876: *urefsp = 0; ! 877: ! 878: return kr; ! 879: } ! 880: ! 881: /* ! 882: * Routine: mach_port_mod_refs ! 883: * Purpose: ! 884: * Modifies the number of user references held by a right. ! 885: * The resulting number of user references must be non-negative. ! 886: * If it is zero, the right is deallocated. If the name ! 887: * doesn't denote other rights, it is destroyed. ! 888: * Conditions: ! 889: * Nothing locked. ! 890: * Returns: ! 891: * KERN_SUCCESS Modified number of urefs. ! 892: * KERN_INVALID_TASK The space is null. ! 893: * KERN_INVALID_TASK The space is dead. ! 894: * KERN_INVALID_VALUE "right" isn't a legal value. ! 895: * KERN_INVALID_NAME The name doesn't denote a right. ! 896: * KERN_INVALID_RIGHT Name doesn't denote specified right. ! 897: * KERN_INVALID_VALUE Impossible modification to urefs. ! 898: * KERN_UREFS_OVERFLOW Urefs would overflow. ! 899: */ ! 900: ! 901: kern_return_t ! 902: mach_port_mod_refs( ! 903: ipc_space_t space, ! 904: mach_port_name_t name, ! 905: mach_port_right_t right, ! 906: mach_port_delta_t delta) ! 907: { ! 908: ipc_entry_t entry; ! 909: kern_return_t kr; ! 910: ! 911: if (space == IS_NULL) ! 912: return KERN_INVALID_TASK; ! 913: ! 914: if (right >= MACH_PORT_RIGHT_NUMBER) ! 915: return KERN_INVALID_VALUE; ! 916: ! 917: kr = ipc_right_lookup_write(space, name, &entry); ! 918: if (kr != KERN_SUCCESS) ! 919: return kr; ! 920: /* space is write-locked and active */ ! 921: ! 922: kr = ipc_right_delta(space, name, entry, right, delta); /* unlocks */ ! 923: return kr; ! 924: } ! 925: ! 926: ! 927: /* ! 928: * Routine: mach_port_set_mscount [kernel call] ! 929: * Purpose: ! 930: * Changes a receive right's make-send count. ! 931: * Conditions: ! 932: * Nothing locked. ! 933: * Returns: ! 934: * KERN_SUCCESS Set make-send count. ! 935: * KERN_INVALID_TASK The space is null. ! 936: * KERN_INVALID_TASK The space is dead. ! 937: * KERN_INVALID_NAME The name doesn't denote a right. ! 938: * KERN_INVALID_RIGHT Name doesn't denote receive rights. ! 939: */ ! 940: ! 941: kern_return_t ! 942: mach_port_set_mscount( ! 943: ipc_space_t space, ! 944: mach_port_name_t name, ! 945: mach_port_mscount_t mscount) ! 946: { ! 947: ipc_port_t port; ! 948: kern_return_t kr; ! 949: ! 950: if (space == IS_NULL) ! 951: return KERN_INVALID_TASK; ! 952: ! 953: kr = ipc_port_translate_receive(space, name, &port); ! 954: if (kr != KERN_SUCCESS) ! 955: return kr; ! 956: /* port is locked and active */ ! 957: ! 958: ipc_port_set_mscount(port, mscount); ! 959: ! 960: ip_unlock(port); ! 961: return KERN_SUCCESS; ! 962: } ! 963: ! 964: /* ! 965: * Routine: mach_port_set_seqno [kernel call] ! 966: * Purpose: ! 967: * Changes a receive right's sequence number. ! 968: * Conditions: ! 969: * Nothing locked. ! 970: * Returns: ! 971: * KERN_SUCCESS Set sequence number. ! 972: * KERN_INVALID_TASK The space is null. ! 973: * KERN_INVALID_TASK The space is dead. ! 974: * KERN_INVALID_NAME The name doesn't denote a right. ! 975: * KERN_INVALID_RIGHT Name doesn't denote receive rights. ! 976: */ ! 977: ! 978: kern_return_t ! 979: mach_port_set_seqno( ! 980: ipc_space_t space, ! 981: mach_port_name_t name, ! 982: mach_port_seqno_t seqno) ! 983: { ! 984: ipc_port_t port; ! 985: kern_return_t kr; ! 986: ! 987: if (space == IS_NULL) ! 988: return KERN_INVALID_TASK; ! 989: ! 990: kr = ipc_port_translate_receive(space, name, &port); ! 991: if (kr != KERN_SUCCESS) ! 992: return kr; ! 993: /* port is locked and active */ ! 994: ! 995: ipc_mqueue_set_seqno(&port->ip_messages, seqno); ! 996: ! 997: ip_unlock(port); ! 998: return KERN_SUCCESS; ! 999: } ! 1000: ! 1001: /* ! 1002: * Routine: mach_port_gst_helper ! 1003: * Purpose: ! 1004: * A helper function for mach_port_get_set_status. ! 1005: */ ! 1006: ! 1007: void ! 1008: mach_port_gst_helper( ! 1009: ipc_pset_t pset, ! 1010: ipc_port_t port, ! 1011: ipc_entry_num_t maxnames, ! 1012: mach_port_name_t *names, ! 1013: ipc_entry_num_t *actualp) ! 1014: { ! 1015: ipc_pset_t ip_pset; ! 1016: mach_port_name_t name; ! 1017: ! 1018: assert(port != IP_NULL); ! 1019: ! 1020: ip_lock(port); ! 1021: assert(ip_active(port)); ! 1022: ! 1023: name = port->ip_receiver_name; ! 1024: assert(name != MACH_PORT_NULL); ! 1025: ! 1026: ip_unlock(port); ! 1027: ! 1028: if (ipc_pset_member(pset, port)) { ! 1029: ipc_entry_num_t actual = *actualp; ! 1030: ! 1031: if (actual < maxnames) ! 1032: names[actual] = name; ! 1033: ! 1034: *actualp = actual+1; ! 1035: } ! 1036: } ! 1037: ! 1038: /* ! 1039: * Routine: mach_port_get_set_status [kernel call] ! 1040: * Purpose: ! 1041: * Retrieves a list of members in a port set. ! 1042: * Returns the space's name for each receive right member. ! 1043: * Conditions: ! 1044: * Nothing locked. ! 1045: * Returns: ! 1046: * KERN_SUCCESS Retrieved list of members. ! 1047: * KERN_INVALID_TASK The space is null. ! 1048: * KERN_INVALID_TASK The space is dead. ! 1049: * KERN_INVALID_NAME The name doesn't denote a right. ! 1050: * KERN_INVALID_RIGHT Name doesn't denote a port set. ! 1051: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. ! 1052: */ ! 1053: ! 1054: kern_return_t ! 1055: mach_port_get_set_status( ! 1056: ipc_space_t space, ! 1057: mach_port_name_t name, ! 1058: mach_port_name_t **members, ! 1059: mach_msg_type_number_t *membersCnt) ! 1060: { ! 1061: ipc_entry_num_t actual; /* this many members */ ! 1062: ipc_entry_num_t maxnames; /* space for this many members */ ! 1063: kern_return_t kr; ! 1064: ! 1065: vm_size_t size; /* size of allocated memory */ ! 1066: vm_offset_t addr; /* allocated memory */ ! 1067: vm_map_copy_t memory; /* copied-in memory */ ! 1068: ! 1069: if (space == IS_NULL) ! 1070: return KERN_INVALID_TASK; ! 1071: ! 1072: size = PAGE_SIZE; /* initial guess */ ! 1073: ! 1074: for (;;) { ! 1075: ipc_tree_entry_t tentry; ! 1076: ipc_entry_t entry, table; ! 1077: ipc_entry_num_t tsize; ! 1078: mach_port_index_t index; ! 1079: mach_port_name_t *names; ! 1080: ipc_pset_t pset; ! 1081: ! 1082: kr = vm_allocate(ipc_kernel_map, &addr, size, TRUE); ! 1083: if (kr != KERN_SUCCESS) ! 1084: return KERN_RESOURCE_SHORTAGE; ! 1085: ! 1086: /* can't fault while we hold locks */ ! 1087: ! 1088: kr = vm_map_wire(ipc_kernel_map, addr, addr + size, ! 1089: VM_PROT_READ|VM_PROT_WRITE, FALSE); ! 1090: assert(kr == KERN_SUCCESS); ! 1091: ! 1092: kr = ipc_right_lookup_read(space, name, &entry); ! 1093: if (kr != KERN_SUCCESS) { ! 1094: kmem_free(ipc_kernel_map, addr, size); ! 1095: return kr; ! 1096: } ! 1097: /* space is read-locked and active */ ! 1098: ! 1099: if (IE_BITS_TYPE(entry->ie_bits) != MACH_PORT_TYPE_PORT_SET) { ! 1100: is_read_unlock(space); ! 1101: kmem_free(ipc_kernel_map, addr, size); ! 1102: return KERN_INVALID_RIGHT; ! 1103: } ! 1104: ! 1105: pset = (ipc_pset_t) entry->ie_object; ! 1106: assert(pset != IPS_NULL); ! 1107: /* the port set must be active */ ! 1108: ! 1109: names = (mach_port_name_t *) addr; ! 1110: maxnames = size / sizeof(mach_port_name_t); ! 1111: actual = 0; ! 1112: ! 1113: table = space->is_table; ! 1114: tsize = space->is_table_size; ! 1115: ! 1116: for (index = 0; index < tsize; index++) { ! 1117: ipc_entry_t ientry = &table[index]; ! 1118: ! 1119: if (ientry->ie_bits & MACH_PORT_TYPE_RECEIVE) { ! 1120: ipc_port_t port = ! 1121: (ipc_port_t) ientry->ie_object; ! 1122: ! 1123: mach_port_gst_helper(pset, port, ! 1124: maxnames, names, &actual); ! 1125: } ! 1126: } ! 1127: ! 1128: for (tentry = ipc_splay_traverse_start(&space->is_tree); ! 1129: tentry != ITE_NULL; ! 1130: tentry = ipc_splay_traverse_next(&space->is_tree,FALSE)) { ! 1131: ipc_entry_bits_t bits = tentry->ite_bits; ! 1132: ! 1133: assert(IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE); ! 1134: ! 1135: if (bits & MACH_PORT_TYPE_RECEIVE) { ! 1136: ipc_port_t port = (ipc_port_t) tentry->ite_object; ! 1137: ! 1138: mach_port_gst_helper(pset, port, maxnames, ! 1139: names, &actual); ! 1140: } ! 1141: } ! 1142: ipc_splay_traverse_finish(&space->is_tree); ! 1143: is_read_unlock(space); ! 1144: ! 1145: if (actual <= maxnames) ! 1146: break; ! 1147: ! 1148: /* didn't have enough memory; allocate more */ ! 1149: ! 1150: kmem_free(ipc_kernel_map, addr, size); ! 1151: size = round_page(actual * sizeof(mach_port_name_t)) + PAGE_SIZE; ! 1152: } ! 1153: ! 1154: if (actual == 0) { ! 1155: memory = VM_MAP_COPY_NULL; ! 1156: ! 1157: kmem_free(ipc_kernel_map, addr, size); ! 1158: } else { ! 1159: vm_size_t size_used; ! 1160: vm_size_t vm_size_used; ! 1161: ! 1162: size_used = actual * sizeof(mach_port_name_t); ! 1163: vm_size_used = round_page(size_used); ! 1164: ! 1165: /* ! 1166: * Make used memory pageable and get it into ! 1167: * copied-in form. Free any unused memory. ! 1168: */ ! 1169: ! 1170: kr = vm_map_unwire(ipc_kernel_map, ! 1171: addr, addr + vm_size_used, FALSE); ! 1172: assert(kr == KERN_SUCCESS); ! 1173: ! 1174: kr = vm_map_copyin(ipc_kernel_map, addr, size_used, ! 1175: TRUE, &memory); ! 1176: assert(kr == KERN_SUCCESS); ! 1177: ! 1178: if (vm_size_used != size) ! 1179: kmem_free(ipc_kernel_map, ! 1180: addr + vm_size_used, size - vm_size_used); ! 1181: } ! 1182: ! 1183: *members = (mach_port_name_t *) memory; ! 1184: *membersCnt = actual; ! 1185: return KERN_SUCCESS; ! 1186: } ! 1187: ! 1188: /* ! 1189: * Routine: mach_port_move_member [kernel call] ! 1190: * Purpose: ! 1191: * If after is MACH_PORT_NULL, removes member ! 1192: * from the port set it is in. Otherwise, adds ! 1193: * member to after, removing it from any set ! 1194: * it might already be in. ! 1195: * Conditions: ! 1196: * Nothing locked. ! 1197: * Returns: ! 1198: * KERN_SUCCESS Moved the port. ! 1199: * KERN_INVALID_TASK The space is null. ! 1200: * KERN_INVALID_TASK The space is dead. ! 1201: * KERN_INVALID_NAME Member didn't denote a right. ! 1202: * KERN_INVALID_RIGHT Member didn't denote a receive right. ! 1203: * KERN_INVALID_NAME After didn't denote a right. ! 1204: * KERN_INVALID_RIGHT After didn't denote a port set right. ! 1205: * KERN_NOT_IN_SET ! 1206: * After is MACH_PORT_NULL and Member isn't in a port set. ! 1207: */ ! 1208: ! 1209: kern_return_t ! 1210: mach_port_move_member( ! 1211: ipc_space_t space, ! 1212: mach_port_name_t member, ! 1213: mach_port_name_t after) ! 1214: { ! 1215: ipc_entry_t entry; ! 1216: ipc_port_t port; ! 1217: ipc_pset_t nset; ! 1218: kern_return_t kr; ! 1219: ! 1220: if (space == IS_NULL) ! 1221: return KERN_INVALID_TASK; ! 1222: ! 1223: kr = ipc_right_lookup_read(space, member, &entry); ! 1224: if (kr != KERN_SUCCESS) ! 1225: return kr; ! 1226: /* space is read-locked and active */ ! 1227: ! 1228: if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0) { ! 1229: is_read_unlock(space); ! 1230: return KERN_INVALID_RIGHT; ! 1231: } ! 1232: ! 1233: port = (ipc_port_t) entry->ie_object; ! 1234: assert(port != IP_NULL); ! 1235: ! 1236: if (after == MACH_PORT_NULL) ! 1237: nset = IPS_NULL; ! 1238: else { ! 1239: entry = ipc_entry_lookup(space, after); ! 1240: if (entry == IE_NULL) { ! 1241: is_read_unlock(space); ! 1242: return KERN_INVALID_NAME; ! 1243: } ! 1244: ! 1245: if ((entry->ie_bits & MACH_PORT_TYPE_PORT_SET) == 0) { ! 1246: is_read_unlock(space); ! 1247: return KERN_INVALID_RIGHT; ! 1248: } ! 1249: ! 1250: nset = (ipc_pset_t) entry->ie_object; ! 1251: assert(nset != IPS_NULL); ! 1252: } ! 1253: ip_lock(port); ! 1254: ipc_pset_remove_all(port); ! 1255: ! 1256: if (nset != IPS_NULL) { ! 1257: ips_lock(nset); ! 1258: kr = ipc_pset_add(nset, port); ! 1259: ips_unlock(nset); ! 1260: } ! 1261: ip_unlock(port); ! 1262: is_read_unlock(space); ! 1263: return kr; ! 1264: } ! 1265: ! 1266: /* ! 1267: * Routine: mach_port_request_notification [kernel call] ! 1268: * Purpose: ! 1269: * Requests a notification. The caller supplies ! 1270: * a send-once right for the notification to use, ! 1271: * and the call returns the previously registered ! 1272: * send-once right, if any. Possible types: ! 1273: * ! 1274: * MACH_NOTIFY_PORT_DESTROYED ! 1275: * Requests a port-destroyed notification ! 1276: * for a receive right. Sync should be zero. ! 1277: * MACH_NOTIFY_NO_SENDERS ! 1278: * Requests a no-senders notification for a ! 1279: * receive right. If there are currently no ! 1280: * senders, sync is less than or equal to the ! 1281: * current make-send count, and a send-once right ! 1282: * is supplied, then an immediate no-senders ! 1283: * notification is generated. ! 1284: * MACH_NOTIFY_DEAD_NAME ! 1285: * Requests a dead-name notification for a send ! 1286: * or receive right. If the name is already a ! 1287: * dead name, sync is non-zero, and a send-once ! 1288: * right is supplied, then an immediate dead-name ! 1289: * notification is generated. ! 1290: * Conditions: ! 1291: * Nothing locked. ! 1292: * Returns: ! 1293: * KERN_SUCCESS Requested a notification. ! 1294: * KERN_INVALID_TASK The space is null. ! 1295: * KERN_INVALID_TASK The space is dead. ! 1296: * KERN_INVALID_VALUE Bad id value. ! 1297: * KERN_INVALID_NAME Name doesn't denote a right. ! 1298: * KERN_INVALID_RIGHT Name doesn't denote appropriate right. ! 1299: * KERN_INVALID_CAPABILITY The notify port is dead. ! 1300: * MACH_NOTIFY_PORT_DESTROYED: ! 1301: * KERN_INVALID_VALUE Sync isn't zero. ! 1302: * MACH_NOTIFY_DEAD_NAME: ! 1303: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. ! 1304: * KERN_INVALID_ARGUMENT Name denotes dead name, but ! 1305: * sync is zero or notify is IP_NULL. ! 1306: * KERN_UREFS_OVERFLOW Name denotes dead name, but ! 1307: * generating immediate notif. would overflow urefs. ! 1308: */ ! 1309: ! 1310: kern_return_t ! 1311: mach_port_request_notification( ! 1312: ipc_space_t space, ! 1313: mach_port_name_t name, ! 1314: mach_msg_id_t id, ! 1315: mach_port_mscount_t sync, ! 1316: ipc_port_t notify, ! 1317: ipc_port_t *previousp) ! 1318: { ! 1319: kern_return_t kr; ! 1320: ipc_entry_t entry; ! 1321: ipc_port_t port; ! 1322: ! 1323: ! 1324: if (space == IS_NULL) ! 1325: return KERN_INVALID_TASK; ! 1326: ! 1327: if (notify == IP_DEAD) ! 1328: return KERN_INVALID_CAPABILITY; ! 1329: ! 1330: #if NOTYET ! 1331: /* ! 1332: * Requesting notifications on RPC ports is an error. ! 1333: */ ! 1334: kr = ipc_right_lookup_write(space, name, &entry); ! 1335: if (kr != KERN_SUCCESS) ! 1336: return kr; ! 1337: ! 1338: port = (ipc_port_t) entry->ie_object; ! 1339: ! 1340: if (port->ip_subsystem != NULL) { ! 1341: is_write_unlock(space); ! 1342: panic("mach_port_request_notification: on RPC port!!"); ! 1343: return KERN_INVALID_CAPABILITY; ! 1344: } ! 1345: is_write_unlock(space); ! 1346: #endif /* NOTYET */ ! 1347: ! 1348: ! 1349: switch (id) { ! 1350: case MACH_NOTIFY_PORT_DESTROYED: { ! 1351: ipc_port_t port, previous; ! 1352: ! 1353: if (sync != 0) ! 1354: return KERN_INVALID_VALUE; ! 1355: ! 1356: kr = ipc_port_translate_receive(space, name, &port); ! 1357: if (kr != KERN_SUCCESS) ! 1358: return kr; ! 1359: /* port is locked and active */ ! 1360: ! 1361: ipc_port_pdrequest(port, notify, &previous); ! 1362: /* port is unlocked */ ! 1363: ! 1364: *previousp = previous; ! 1365: break; ! 1366: } ! 1367: ! 1368: case MACH_NOTIFY_NO_SENDERS: { ! 1369: ipc_port_t port; ! 1370: ! 1371: kr = ipc_port_translate_receive(space, name, &port); ! 1372: if (kr != KERN_SUCCESS) ! 1373: return kr; ! 1374: /* port is locked and active */ ! 1375: ! 1376: if (!IP_NMS(port)) { ! 1377: ip_unlock(port); ! 1378: return KERN_INVALID_RIGHT; ! 1379: } ! 1380: ! 1381: ipc_port_nsrequest(port, sync, notify, previousp); ! 1382: /* port is unlocked */ ! 1383: break; ! 1384: } ! 1385: ! 1386: case MACH_NOTIFY_DEAD_NAME: ! 1387: kr = ipc_right_dnrequest(space, name, sync != 0, ! 1388: notify, previousp); ! 1389: if (kr != KERN_SUCCESS) ! 1390: return kr; ! 1391: break; ! 1392: ! 1393: default: ! 1394: return KERN_INVALID_VALUE; ! 1395: } ! 1396: ! 1397: return KERN_SUCCESS; ! 1398: } ! 1399: ! 1400: /* ! 1401: * Routine: mach_port_insert_right [kernel call] ! 1402: * Purpose: ! 1403: * Inserts a right into a space, as if the space ! 1404: * voluntarily received the right in a message, ! 1405: * except that the right gets the specified name. ! 1406: * Conditions: ! 1407: * Nothing locked. ! 1408: * Returns: ! 1409: * KERN_SUCCESS Inserted the right. ! 1410: * KERN_INVALID_TASK The space is null. ! 1411: * KERN_INVALID_TASK The space is dead. ! 1412: * KERN_INVALID_VALUE The name isn't a legal name. ! 1413: * KERN_NAME_EXISTS The name already denotes a right. ! 1414: * KERN_INVALID_VALUE Message doesn't carry a port right. ! 1415: * KERN_INVALID_CAPABILITY Port is null or dead. ! 1416: * KERN_UREFS_OVERFLOW Urefs limit would be exceeded. ! 1417: * KERN_RIGHT_EXISTS Space has rights under another name. ! 1418: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. ! 1419: */ ! 1420: ! 1421: kern_return_t ! 1422: mach_port_insert_right( ! 1423: ipc_space_t space, ! 1424: mach_port_name_t name, ! 1425: ipc_port_t poly, ! 1426: mach_msg_type_name_t polyPoly) ! 1427: { ! 1428: if (space == IS_NULL) ! 1429: return KERN_INVALID_TASK; ! 1430: ! 1431: if (!MACH_PORT_VALID(name) || ! 1432: !MACH_MSG_TYPE_PORT_ANY_RIGHT(polyPoly)) ! 1433: return KERN_INVALID_VALUE; ! 1434: ! 1435: if (!IO_VALID((ipc_object_t) poly)) ! 1436: return KERN_INVALID_CAPABILITY; ! 1437: ! 1438: return ipc_object_copyout_name(space, (ipc_object_t) poly, ! 1439: polyPoly, FALSE, name); ! 1440: } ! 1441: ! 1442: /* ! 1443: * Routine: mach_port_extract_right [kernel call] ! 1444: * Purpose: ! 1445: * Extracts a right from a space, as if the space ! 1446: * voluntarily sent the right to the caller. ! 1447: * Conditions: ! 1448: * Nothing locked. ! 1449: * Returns: ! 1450: * KERN_SUCCESS Extracted the right. ! 1451: * KERN_INVALID_TASK The space is null. ! 1452: * KERN_INVALID_TASK The space is dead. ! 1453: * KERN_INVALID_VALUE Requested type isn't a port right. ! 1454: * KERN_INVALID_NAME Name doesn't denote a right. ! 1455: * KERN_INVALID_RIGHT Name doesn't denote appropriate right. ! 1456: */ ! 1457: ! 1458: kern_return_t ! 1459: mach_port_extract_right( ! 1460: ipc_space_t space, ! 1461: mach_port_name_t name, ! 1462: mach_msg_type_name_t msgt_name, ! 1463: ipc_port_t *poly, ! 1464: mach_msg_type_name_t *polyPoly) ! 1465: { ! 1466: kern_return_t kr; ! 1467: ! 1468: if (space == IS_NULL) ! 1469: return KERN_INVALID_TASK; ! 1470: ! 1471: if (!MACH_MSG_TYPE_PORT_ANY(msgt_name)) ! 1472: return KERN_INVALID_VALUE; ! 1473: ! 1474: kr = ipc_object_copyin(space, name, msgt_name, (ipc_object_t *) poly); ! 1475: ! 1476: if (kr == KERN_SUCCESS) ! 1477: *polyPoly = ipc_object_copyin_type(msgt_name); ! 1478: return kr; ! 1479: } ! 1480: ! 1481: ! 1482: kern_return_t ! 1483: mach_port_get_attributes( ! 1484: ipc_space_t space, ! 1485: mach_port_name_t name, ! 1486: int flavor, ! 1487: mach_port_info_t info, ! 1488: mach_msg_type_number_t *count) ! 1489: { ! 1490: ipc_port_t port; ! 1491: kern_return_t kr; ! 1492: ! 1493: if (space == IS_NULL) ! 1494: return KERN_INVALID_TASK; ! 1495: ! 1496: switch (flavor) { ! 1497: case MACH_PORT_LIMITS_INFO: { ! 1498: mach_port_limits_t *lp = (mach_port_limits_t *)info; ! 1499: ! 1500: if (*count < MACH_PORT_LIMITS_INFO_COUNT) ! 1501: return KERN_FAILURE; ! 1502: ! 1503: kr = ipc_port_translate_receive(space, name, &port); ! 1504: if (kr != KERN_SUCCESS) ! 1505: return kr; ! 1506: /* port is locked and active */ ! 1507: ! 1508: lp->mpl_qlimit = port->ip_messages.imq_qlimit; ! 1509: *count = MACH_PORT_LIMITS_INFO_COUNT; ! 1510: ip_unlock(port); ! 1511: break; ! 1512: } ! 1513: ! 1514: case MACH_PORT_RECEIVE_STATUS: { ! 1515: mach_port_status_t *statusp = (mach_port_status_t *)info; ! 1516: ! 1517: if (*count < MACH_PORT_RECEIVE_STATUS_COUNT) ! 1518: return KERN_FAILURE; ! 1519: ! 1520: kr = ipc_port_translate_receive(space, name, &port); ! 1521: if (kr != KERN_SUCCESS) ! 1522: return kr; ! 1523: /* port is locked and active */ ! 1524: ! 1525: statusp->mps_pset = port->ip_pset_count; ! 1526: imq_lock(&port->ip_messages); ! 1527: statusp->mps_seqno = port->ip_messages.imq_seqno; ! 1528: statusp->mps_qlimit = port->ip_messages.imq_qlimit; ! 1529: statusp->mps_msgcount = port->ip_messages.imq_msgcount; ! 1530: imq_unlock(&port->ip_messages); ! 1531: ! 1532: statusp->mps_mscount = port->ip_mscount; ! 1533: statusp->mps_sorights = port->ip_sorights; ! 1534: statusp->mps_srights = port->ip_srights > 0; ! 1535: statusp->mps_pdrequest = port->ip_pdrequest != IP_NULL; ! 1536: statusp->mps_nsrequest = port->ip_nsrequest != IP_NULL; ! 1537: statusp->mps_flags = port->ip_flags; ! 1538: ! 1539: *count = MACH_PORT_RECEIVE_STATUS_COUNT; ! 1540: ip_unlock(port); ! 1541: break; ! 1542: } ! 1543: ! 1544: case MACH_PORT_DNREQUESTS_SIZE: { ! 1545: ipc_port_request_t table; ! 1546: ! 1547: if (*count < MACH_PORT_DNREQUESTS_SIZE_COUNT) ! 1548: return KERN_FAILURE; ! 1549: ! 1550: kr = ipc_port_translate_receive(space, name, &port); ! 1551: if (kr != KERN_SUCCESS) ! 1552: return kr; ! 1553: /* port is locked and active */ ! 1554: ! 1555: table = port->ip_dnrequests; ! 1556: if (table == IPR_NULL) ! 1557: *(int *)info = 0; ! 1558: else ! 1559: *(int *)info = table->ipr_size->its_size; ! 1560: *count = MACH_PORT_DNREQUESTS_SIZE_COUNT; ! 1561: ip_unlock(port); ! 1562: break; ! 1563: } ! 1564: ! 1565: default: ! 1566: return KERN_INVALID_ARGUMENT; ! 1567: /*NOTREACHED*/ ! 1568: } ! 1569: ! 1570: return KERN_SUCCESS; ! 1571: } ! 1572: ! 1573: kern_return_t ! 1574: mach_port_set_attributes( ! 1575: ipc_space_t space, ! 1576: mach_port_name_t name, ! 1577: int flavor, ! 1578: mach_port_info_t info, ! 1579: mach_msg_type_number_t count) ! 1580: { ! 1581: ipc_port_t port; ! 1582: kern_return_t kr; ! 1583: ! 1584: if (space == IS_NULL) ! 1585: return KERN_INVALID_TASK; ! 1586: ! 1587: switch (flavor) { ! 1588: ! 1589: case MACH_PORT_LIMITS_INFO: { ! 1590: mach_port_limits_t *mplp = (mach_port_limits_t *)info; ! 1591: ! 1592: if (count < MACH_PORT_LIMITS_INFO_COUNT) ! 1593: return KERN_FAILURE; ! 1594: ! 1595: if (mplp->mpl_qlimit > MACH_PORT_QLIMIT_MAX) ! 1596: return KERN_INVALID_VALUE; ! 1597: ! 1598: kr = ipc_port_translate_receive(space, name, &port); ! 1599: if (kr != KERN_SUCCESS) ! 1600: return kr; ! 1601: /* port is locked and active */ ! 1602: ! 1603: ipc_mqueue_set_qlimit(&port->ip_messages, mplp->mpl_qlimit); ! 1604: ip_unlock(port); ! 1605: break; ! 1606: } ! 1607: case MACH_PORT_DNREQUESTS_SIZE: { ! 1608: if (count < MACH_PORT_DNREQUESTS_SIZE_COUNT) ! 1609: return KERN_FAILURE; ! 1610: ! 1611: kr = ipc_port_translate_receive(space, name, &port); ! 1612: if (kr != KERN_SUCCESS) ! 1613: return kr; ! 1614: /* port is locked and active */ ! 1615: ! 1616: kr = ipc_port_dngrow(port, *(int *)info); ! 1617: if (kr != KERN_SUCCESS) ! 1618: return kr; ! 1619: break; ! 1620: } ! 1621: default: ! 1622: return KERN_INVALID_ARGUMENT; ! 1623: /*NOTREACHED*/ ! 1624: } ! 1625: return KERN_SUCCESS; ! 1626: } ! 1627: ! 1628: ! 1629: /* ! 1630: * Create an empty thread_activation (sans thread_shuttle) attached to ! 1631: * a port or port set in a given task to receive incoming threads. ! 1632: */ ! 1633: /* ! 1634: * NOTE: the following calls targeted at a thread_act port may be ! 1635: * called on an empty thread_act: ! 1636: * ! 1637: * thread_get_exception_ports thread_set_exception_ports ! 1638: * thread_get_special_port thread_set_special_port ! 1639: * thread_get_state thread_suspend ! 1640: * thread_resume thread_swap_exception_ports ! 1641: * thread_sample thread_terminate ! 1642: * ! 1643: * The following calls targeted at a thread_act port may _not_ be ! 1644: * called on an empty thread_act (and will return KERN_INVALID_ARGUMENT ! 1645: * if they are called with one): ! 1646: * ! 1647: * thread_abort thread_info ! 1648: * thread_abort_safely thread_wire ! 1649: * thread_depress_abort ! 1650: * ! 1651: * Also, if thread_switch() is called with an empty thread_act as ! 1652: * its first argument, the argument will be ignored (i.e., the ! 1653: * function will behave as if a zero-valued argument had been ! 1654: * given). ! 1655: */ ! 1656: kern_return_t ! 1657: thread_activation_create( ! 1658: task_t task, ! 1659: mach_port_name_t name, ! 1660: act_params_t act_params, ! 1661: thread_act_t *new_act) ! 1662: { ! 1663: ipc_space_t space; ! 1664: ipc_object_t object; ! 1665: kern_return_t kr; ! 1666: thread_act_t thr_act; ! 1667: int is_port = 1; ! 1668: thread_act_params_t params = (thread_act_params_t)act_params; ! 1669: ! 1670: if (task == TASK_NULL) ! 1671: return KERN_INVALID_TASK; ! 1672: ! 1673: /* First create the new activation. */ ! 1674: /* ! 1675: * We'll need this stack later -- make sure it's present. ! 1676: */ ! 1677: assert(params != 0); ! 1678: assert(params->stack != 0); ! 1679: kr = act_create(task, params, &thr_act); ! 1680: if (kr != KERN_SUCCESS) ! 1681: return kr; ! 1682: ! 1683: space = task->itk_space; ! 1684: ! 1685: kr = ipc_object_translate(space, name, ! 1686: MACH_PORT_RIGHT_PORT_SET, &object); ! 1687: if (kr != KERN_SUCCESS) { ! 1688: kr = ipc_object_translate(space, name, ! 1689: MACH_PORT_RIGHT_RECEIVE, &object); ! 1690: if (kr != KERN_SUCCESS) { ! 1691: thread_terminate(thr_act); ! 1692: act_deallocate(thr_act); ! 1693: return kr; ! 1694: } ! 1695: is_port = 0; ! 1696: } ! 1697: /* port/pset is locked and active */ ! 1698: ! 1699: #if MACH_ASSERT ! 1700: if (watchacts & WA_PORT) ! 1701: printf("thr_act on %s=%x stack=%x thr_act=%x\n", ! 1702: (is_port ? "port" : "pset"), ! 1703: object, params->stack, thr_act); ! 1704: #endif /* MACH_ASSERT */ ! 1705: ! 1706: /* Assign the activation to the thread_pool. */ ! 1707: kr = act_set_thread_pool(thr_act, (ipc_port_t)object); ! 1708: if (kr != KERN_SUCCESS) { ! 1709: io_unlock(object); ! 1710: thread_terminate(thr_act); ! 1711: act_deallocate(thr_act); ! 1712: return kr; ! 1713: } ! 1714: io_unlock(object); ! 1715: ! 1716: #if MACH_ASSERT ! 1717: if (watchacts & WA_PORT) ! 1718: printf("\tpool_port=%x thr_act=%x\n", (ipc_port_t)object, thr_act); ! 1719: #endif /* MACH_ASSERT */ ! 1720: ! 1721: /* Pass our reference to the activation back to the user. */ ! 1722: *new_act = thr_act; ! 1723: ! 1724: return KERN_SUCCESS; ! 1725: } ! 1726: ! 1727: /* ! 1728: * Routine: mach_port_insert_member [kernel call] ! 1729: * Purpose: ! 1730: * Add the receive right, specified by name, to ! 1731: * a portset. ! 1732: * The port cannot already be a member of the set. ! 1733: * Conditions: ! 1734: * Nothing locked. ! 1735: * Returns: ! 1736: * KERN_SUCCESS Moved the port. ! 1737: * KERN_INVALID_TASK The space is null. ! 1738: * KERN_INVALID_TASK The space is dead. ! 1739: * KERN_INVALID_NAME name didn't denote a right. ! 1740: * KERN_INVALID_RIGHT name didn't denote a receive right. ! 1741: * KERN_INVALID_NAME pset_name didn't denote a right. ! 1742: * KERN_INVALID_RIGHT pset_name didn't denote a portset right. ! 1743: * KERN_ALREADY_IN_SET name was already a member of pset. ! 1744: */ ! 1745: ! 1746: kern_return_t ! 1747: mach_port_insert_member( ! 1748: ipc_space_t space, ! 1749: mach_port_name_t name, ! 1750: mach_port_name_t pset_name) ! 1751: { ! 1752: ipc_object_t obj; ! 1753: ipc_object_t pset_obj; ! 1754: kern_return_t kr; ! 1755: ! 1756: if (space == IS_NULL) ! 1757: return KERN_INVALID_TASK; ! 1758: ! 1759: kr = ipc_object_translate(space, pset_name, MACH_PORT_RIGHT_PORT_SET, ! 1760: &pset_obj); /* pset locked */ ! 1761: if (kr != KERN_SUCCESS) ! 1762: return kr; ! 1763: assert(pset_obj != IO_NULL); ! 1764: ! 1765: kr = ipc_object_translate(space, name, MACH_PORT_RIGHT_RECEIVE, &obj); ! 1766: ! 1767: if (kr != KERN_SUCCESS) { ! 1768: io_unlock(pset_obj); ! 1769: return kr; ! 1770: } ! 1771: ! 1772: assert(obj != IO_NULL); ! 1773: ! 1774: kr = ipc_pset_add((ipc_pset_t)pset_obj, (ipc_port_t)obj); ! 1775: io_unlock(pset_obj); ! 1776: io_unlock(obj); ! 1777: return kr; ! 1778: } ! 1779: ! 1780: /* ! 1781: * Routine: mach_port_extract_member [kernel call] ! 1782: * Purpose: ! 1783: * If after is MACH_PORT_NULL, removes member ! 1784: * from the port set it is in. ! 1785: * Conditions: ! 1786: * Nothing locked. ! 1787: * Returns: ! 1788: * KERN_SUCCESS Moved the port. ! 1789: * KERN_INVALID_TASK The space is null. ! 1790: * KERN_INVALID_TASK The space is dead. ! 1791: * KERN_INVALID_NAME Member didn't denote a right. ! 1792: * KERN_INVALID_RIGHT Member didn't denote a receive right. ! 1793: * KERN_INVALID_NAME After didn't denote a right. ! 1794: * KERN_INVALID_RIGHT After didn't denote a port set right. ! 1795: * KERN_NOT_IN_SET ! 1796: * After is MACH_PORT_NULL and Member isn't in a port set. ! 1797: */ ! 1798: ! 1799: kern_return_t ! 1800: mach_port_extract_member( ! 1801: ipc_space_t space, ! 1802: mach_port_name_t name, ! 1803: mach_port_name_t pset_name) ! 1804: { ! 1805: mach_port_name_t oldname; ! 1806: ipc_object_t pset_obj; ! 1807: ipc_object_t obj; ! 1808: kern_return_t kr; ! 1809: ! 1810: if (space == IS_NULL) ! 1811: return KERN_INVALID_TASK; ! 1812: ! 1813: kr = ipc_object_translate(space, pset_name, MACH_PORT_RIGHT_PORT_SET, ! 1814: &pset_obj); /* pset locked and active */ ! 1815: if (kr != KERN_SUCCESS) ! 1816: return kr; ! 1817: assert(pset_obj != IO_NULL); ! 1818: ! 1819: kr = ipc_object_translate(space, name, MACH_PORT_RIGHT_RECEIVE, ! 1820: &obj); /* obj locked and active */ ! 1821: if (kr != KERN_SUCCESS) { ! 1822: io_unlock(pset_obj); ! 1823: return kr; ! 1824: } ! 1825: ! 1826: kr = ipc_pset_remove((ipc_pset_t)pset_obj, (ipc_port_t)obj); ! 1827: io_unlock(pset_obj); ! 1828: io_unlock(obj); ! 1829: ! 1830: if (kr != KERN_SUCCESS) ! 1831: return kr; ! 1832: ! 1833: return kr; ! 1834: } ! 1835:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.