123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029 |
- /*
- * Mach Operating System
- * Copyright (c) 1991,1990,1989 Carnegie Mellon University
- * All Rights Reserved.
- *
- * Permission to use, copy, modify and distribute this software and its
- * documentation is hereby granted, provided that both the copyright
- * notice and this permission notice appear in all copies of the
- * software, derivative works or modified versions, and any portions
- * thereof, and that both notices appear in supporting documentation.
- *
- * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
- * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
- * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
- * Carnegie Mellon requests users of this software to return to
- *
- * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
- * School of Computer Science
- * Carnegie Mellon University
- * Pittsburgh PA 15213-3890
- *
- * any improvements or extensions that they make and grant Carnegie Mellon
- * the rights to redistribute these changes.
- */
- /*
- * File: ipc/ipc_object.c
- * Author: Rich Draves
- * Date: 1989
- *
- * Functions to manipulate IPC objects.
- */
-
- #pragma GCC diagnostic error "-Wundef"
- #include <glue/gnulinux.h>
- #include <string.h>
- #include <mach/boolean.h>
- #include <mach/kern_return.h>
- #include <mach/port.h>
- #include <mach/message.h>
- #include <ipc/port.h>
- #include <ipc/ipc_space.h>
- #include <ipc/ipc_entry.h>
- #include <ipc/ipc_object.h>
- #include <ipc/ipc_right.h>
- #include <ipc/ipc_notify.h>
- #include <ipc/ipc_pset.h>
- #include <kern/debug.h>
- #include <kern/printf.h>
- #include <kern/slab.h>
- #if MACH_KDB
- #include <ddb/db_output.h>
- #endif /* MACH_KDB */
- struct gnu_kmem_cache ipc_object_caches[IOT_NUMBER];
- /*
- * Routine: ipc_object_reference
- * Purpose:
- * Take a reference to an object.
- */
- void
- ipc_object_reference(
- ipc_object_t object)
- {
- io_lock(object);
- assert(object->io_references > 0);
- io_reference(object);
- io_unlock(object);
- }
- /*
- * Routine: ipc_object_release
- * Purpose:
- * Release a reference to an object.
- */
- void
- ipc_object_release(
- ipc_object_t object)
- {
- io_lock(object);
- assert(object->io_references > 0);
- io_release(object);
- io_check_unlock(object);
- }
- /*
- * Routine: ipc_object_translate
- * Purpose:
- * Look up an object in a space.
- * Conditions:
- * Nothing locked before. If successful, the object
- * is returned locked. The caller doesn't get a ref.
- * Returns:
- * KERN_SUCCESS Objected returned locked.
- * KERN_INVALID_TASK The space is dead.
- * KERN_INVALID_NAME The name doesn't denote a right.
- * KERN_INVALID_RIGHT Name doesn't denote the correct right.
- */
- kern_return_t
- ipc_object_translate(
- ipc_space_t space,
- mach_port_t name,
- mach_port_right_t right,
- ipc_object_t *objectp)
- {
- ipc_entry_t entry;
- ipc_object_t object;
- kern_return_t kr;
- kr = ipc_right_lookup_read(space, name, &entry);
- if (kr != KERN_SUCCESS)
- return kr;
- /* space is read-locked and active */
- if ((entry->ie_bits & MACH_PORT_TYPE(right)) == (mach_port_right_t) 0) {
- is_read_unlock(space);
- return KERN_INVALID_RIGHT;
- }
- object = entry->ie_object;
- assert(object != IO_NULL);
- io_lock(object);
- is_read_unlock(space);
- *objectp = object;
- return KERN_SUCCESS;
- }
- /*
- * Routine: ipc_object_alloc_dead
- * Purpose:
- * Allocate a dead-name entry.
- * Conditions:
- * Nothing locked.
- * Returns:
- * KERN_SUCCESS The dead name is allocated.
- * KERN_INVALID_TASK The space is dead.
- * KERN_NO_SPACE No room for an entry in the space.
- * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
- */
- kern_return_t
- ipc_object_alloc_dead(
- ipc_space_t space,
- mach_port_t *namep)
- {
- ipc_entry_t entry;
- kern_return_t kr;
- is_write_lock(space);
- kr = ipc_entry_alloc(space, namep, &entry);
- if (kr != KERN_SUCCESS) {
- is_write_unlock(space);
- return kr;
- }
- /* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */
- assert(entry->ie_object == IO_NULL);
- entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1;
- is_write_unlock(space);
- return KERN_SUCCESS;
- }
- /*
- * Routine: ipc_object_alloc_dead_name
- * Purpose:
- * Allocate a dead-name entry, with a specific name.
- * Conditions:
- * Nothing locked.
- * Returns:
- * KERN_SUCCESS The dead name is allocated.
- * KERN_INVALID_TASK The space is dead.
- * KERN_NAME_EXISTS The name already denotes a right.
- * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
- */
- kern_return_t
- ipc_object_alloc_dead_name(
- ipc_space_t space,
- mach_port_t name)
- {
- ipc_entry_t entry;
- kern_return_t kr;
- is_write_lock(space);
- kr = ipc_entry_alloc_name(space, name, &entry);
- if (kr != KERN_SUCCESS) {
- is_write_unlock(space);
- return kr;
- }
- if (ipc_right_inuse(space, name, entry))
- return KERN_NAME_EXISTS;
- /* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */
- assert(entry->ie_object == IO_NULL);
- entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1;
- is_write_unlock(space);
- return KERN_SUCCESS;
- }
- /*
- * Routine: ipc_object_alloc
- * Purpose:
- * Allocate an object.
- * Conditions:
- * Nothing locked. If successful, the object is returned locked.
- * The caller doesn't get a reference for the object.
- * Returns:
- * KERN_SUCCESS The object is allocated.
- * KERN_INVALID_TASK The space is dead.
- * KERN_NO_SPACE No room for an entry in the space.
- * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
- */
- kern_return_t
- ipc_object_alloc(
- ipc_space_t space,
- ipc_object_type_t otype,
- mach_port_type_t type,
- mach_port_urefs_t urefs,
- mach_port_t *namep,
- ipc_object_t *objectp)
- {
- ipc_object_t object;
- ipc_entry_t entry;
- kern_return_t kr;
- assert(otype < IOT_NUMBER);
- assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type);
- assert(type != MACH_PORT_TYPE_NONE);
- assert(urefs <= MACH_PORT_UREFS_MAX);
- object = io_alloc(otype);
- if (object == IO_NULL)
- return KERN_RESOURCE_SHORTAGE;
- if (otype == IOT_PORT) {
- ipc_port_t port = (ipc_port_t)object;
- memset(port, 0, sizeof(*port));
- } else if (otype == IOT_PORT_SET) {
- ipc_pset_t pset = (ipc_pset_t)object;
- memset(pset, 0, sizeof(*pset));
- }
- is_write_lock(space);
- kr = ipc_entry_alloc(space, namep, &entry);
- if (kr != KERN_SUCCESS) {
- is_write_unlock(space);
- io_free(otype, object);
- return kr;
- }
- entry->ie_bits |= type | urefs;
- entry->ie_object = object;
- io_lock_init(object);
- io_lock(object);
- is_write_unlock(space);
- object->io_references = 1; /* for entry, not caller */
- object->io_bits = io_makebits(TRUE, otype, 0);
- *objectp = object;
- return KERN_SUCCESS;
- }
- /*
- * Routine: ipc_object_alloc_name
- * Purpose:
- * Allocate an object, with a specific name.
- * Conditions:
- * Nothing locked. If successful, the object is returned locked.
- * The caller doesn't get a reference for the object.
- * Returns:
- * KERN_SUCCESS The object is allocated.
- * KERN_INVALID_TASK The space is dead.
- * KERN_NAME_EXISTS The name already denotes a right.
- * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
- */
- kern_return_t
- ipc_object_alloc_name(
- ipc_space_t space,
- ipc_object_type_t otype,
- mach_port_type_t type,
- mach_port_urefs_t urefs,
- mach_port_t name,
- ipc_object_t *objectp)
- {
- ipc_object_t object;
- ipc_entry_t entry;
- kern_return_t kr;
- assert(otype < IOT_NUMBER);
- assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type);
- assert(type != MACH_PORT_TYPE_NONE);
- assert(urefs <= MACH_PORT_UREFS_MAX);
- object = io_alloc(otype);
- if (object == IO_NULL)
- return KERN_RESOURCE_SHORTAGE;
- if (otype == IOT_PORT) {
- ipc_port_t port = (ipc_port_t)object;
- memset(port, 0, sizeof(*port));
- } else if (otype == IOT_PORT_SET) {
- ipc_pset_t pset = (ipc_pset_t)object;
- memset(pset, 0, sizeof(*pset));
- }
- is_write_lock(space);
- kr = ipc_entry_alloc_name(space, name, &entry);
- if (kr != KERN_SUCCESS) {
- is_write_unlock(space);
- io_free(otype, object);
- return kr;
- }
- if (ipc_right_inuse(space, name, entry)) {
- io_free(otype, object);
- return KERN_NAME_EXISTS;
- }
- entry->ie_bits |= type | urefs;
- entry->ie_object = object;
- io_lock_init(object);
- io_lock(object);
- is_write_unlock(space);
- object->io_references = 1; /* for entry, not caller */
- object->io_bits = io_makebits(TRUE, otype, 0);
- *objectp = object;
- return KERN_SUCCESS;
- }
- /*
- * Routine: ipc_object_copyin_type
- * Purpose:
- * Convert a send type name to a received type name.
- */
- mach_msg_type_name_t
- ipc_object_copyin_type(
- mach_msg_type_name_t msgt_name)
- {
- switch (msgt_name) {
- case 0:
- return 0;
- case MACH_MSG_TYPE_MOVE_RECEIVE:
- return MACH_MSG_TYPE_PORT_RECEIVE;
- case MACH_MSG_TYPE_MOVE_SEND_ONCE:
- case MACH_MSG_TYPE_MAKE_SEND_ONCE:
- return MACH_MSG_TYPE_PORT_SEND_ONCE;
- case MACH_MSG_TYPE_MOVE_SEND:
- case MACH_MSG_TYPE_MAKE_SEND:
- case MACH_MSG_TYPE_COPY_SEND:
- return MACH_MSG_TYPE_PORT_SEND;
- default:
- #if MACH_ASSERT
- assert(!"ipc_object_copyin_type: strange rights");
- #else
- panic("ipc_object_copyin_type: strange rights");
- #endif
- return 0; /* in case assert/panic returns */
- }
- }
- /*
- * Routine: ipc_object_copyin
- * Purpose:
- * Copyin a capability from a space.
- * If successful, the caller gets a ref
- * for the resulting object, unless it is IO_DEAD.
- * Conditions:
- * Nothing locked.
- * Returns:
- * KERN_SUCCESS Acquired an object, possibly IO_DEAD.
- * KERN_INVALID_TASK The space is dead.
- * KERN_INVALID_NAME Name doesn't exist in space.
- * KERN_INVALID_RIGHT Name doesn't denote correct right.
- */
- kern_return_t
- ipc_object_copyin(
- ipc_space_t space,
- mach_port_t name,
- mach_msg_type_name_t msgt_name,
- ipc_object_t *objectp)
- {
- ipc_entry_t entry;
- ipc_port_t soright;
- kern_return_t kr;
- /*
- * Could first try a read lock when doing
- * MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND,
- * and MACH_MSG_TYPE_MAKE_SEND_ONCE.
- */
- kr = ipc_right_lookup_write(space, name, &entry);
- if (kr != KERN_SUCCESS)
- return kr;
- /* space is write-locked and active */
- kr = ipc_right_copyin(space, name, entry,
- msgt_name, TRUE,
- objectp, &soright);
- if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
- ipc_entry_dealloc(space, name, entry);
- is_write_unlock(space);
- if ((kr == KERN_SUCCESS) && (soright != IP_NULL))
- ipc_notify_port_deleted(soright, name);
- return kr;
- }
- /*
- * Routine: ipc_object_copyin_from_kernel
- * Purpose:
- * Copyin a naked capability from the kernel.
- *
- * MACH_MSG_TYPE_MOVE_RECEIVE
- * The receiver must be ipc_space_kernel.
- * Consumes the naked receive right.
- * MACH_MSG_TYPE_COPY_SEND
- * A naked send right must be supplied.
- * The port gains a reference, and a send right
- * if the port is still active.
- * MACH_MSG_TYPE_MAKE_SEND
- * The receiver must be ipc_space_kernel.
- * The port gains a reference and a send right.
- * MACH_MSG_TYPE_MOVE_SEND
- * Consumes a naked send right.
- * MACH_MSG_TYPE_MAKE_SEND_ONCE
- * The receiver must be ipc_space_kernel.
- * The port gains a reference and a send-once right.
- * MACH_MSG_TYPE_MOVE_SEND_ONCE
- * Consumes a naked send-once right.
- * Conditions:
- * Nothing locked.
- */
- void
- ipc_object_copyin_from_kernel(
- ipc_object_t object,
- mach_msg_type_name_t msgt_name)
- {
- assert(IO_VALID(object));
- switch (msgt_name) {
- case MACH_MSG_TYPE_MOVE_RECEIVE: {
- ipc_port_t port = (ipc_port_t) object;
- ip_lock(port);
- assert(ip_active(port));
- assert(port->ip_receiver_name != MACH_PORT_NULL);
- assert(port->ip_receiver == ipc_space_kernel);
- /* relevant part of ipc_port_clear_receiver */
- ipc_port_set_mscount(port, 0);
- port->ip_receiver_name = MACH_PORT_NULL;
- port->ip_destination = IP_NULL;
- ipc_port_flag_protected_payload_clear(port);
- ip_unlock(port);
- break;
- }
- case MACH_MSG_TYPE_COPY_SEND: {
- ipc_port_t port = (ipc_port_t) object;
- ip_lock(port);
- if (ip_active(port)) {
- assert(port->ip_srights > 0);
- port->ip_srights++;
- }
- ip_reference(port);
- ip_unlock(port);
- break;
- }
- case MACH_MSG_TYPE_MAKE_SEND: {
- ipc_port_t port = (ipc_port_t) object;
- ip_lock(port);
- assert(ip_active(port));
- assert(port->ip_receiver_name != MACH_PORT_NULL);
- assert(port->ip_receiver == ipc_space_kernel);
- ip_reference(port);
- port->ip_mscount++;
- port->ip_srights++;
- ip_unlock(port);
- break;
- }
- case MACH_MSG_TYPE_MOVE_SEND:
- /* move naked send right into the message */
- break;
- case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
- ipc_port_t port = (ipc_port_t) object;
- ip_lock(port);
- assert(ip_active(port));
- assert(port->ip_receiver_name != MACH_PORT_NULL);
- assert(port->ip_receiver == ipc_space_kernel);
- ip_reference(port);
- port->ip_sorights++;
- ip_unlock(port);
- break;
- }
- case MACH_MSG_TYPE_MOVE_SEND_ONCE:
- /* move naked send-once right into the message */
- break;
- default:
- #if MACH_ASSERT
- assert(!"ipc_object_copyin_from_kernel: strange rights");
- #else
- panic("ipc_object_copyin_from_kernel: strange rights");
- #endif
- }
- }
- /*
- * Routine: ipc_object_destroy
- * Purpose:
- * Destroys a naked capability.
- * Consumes a ref for the object.
- *
- * A receive right should be in limbo or in transit.
- * Conditions:
- * Nothing locked.
- */
- void
- ipc_object_destroy(
- ipc_object_t object,
- mach_msg_type_name_t msgt_name)
- {
- assert(IO_VALID(object));
- assert(io_otype(object) == IOT_PORT);
- switch (msgt_name) {
- case MACH_MSG_TYPE_PORT_SEND:
- ipc_port_release_send((ipc_port_t) object);
- break;
- case MACH_MSG_TYPE_PORT_SEND_ONCE:
- ipc_notify_send_once((ipc_port_t) object);
- break;
- case MACH_MSG_TYPE_PORT_RECEIVE:
- ipc_port_release_receive((ipc_port_t) object);
- break;
- default:
- panic("ipc_object_destroy: strange rights");
- }
- }
- /*
- * Routine: ipc_object_copyout
- * Purpose:
- * Copyout a capability, placing it into a space.
- * If successful, consumes a ref for the object.
- * Conditions:
- * Nothing locked.
- * Returns:
- * KERN_SUCCESS Copied out object, consumed ref.
- * KERN_INVALID_TASK The space is dead.
- * KERN_INVALID_CAPABILITY The object is dead.
- * KERN_NO_SPACE No room in space for another right.
- * KERN_RESOURCE_SHORTAGE No memory available.
- * KERN_UREFS_OVERFLOW Urefs limit exceeded
- * and overflow wasn't specified.
- */
- kern_return_t
- ipc_object_copyout(
- ipc_space_t space,
- ipc_object_t object,
- mach_msg_type_name_t msgt_name,
- boolean_t overflow,
- mach_port_t *namep)
- {
- mach_port_t name;
- ipc_entry_t entry;
- kern_return_t kr;
- assert(IO_VALID(object));
- assert(io_otype(object) == IOT_PORT);
- is_write_lock(space);
- for (;;) {
- if (!space->is_active) {
- is_write_unlock(space);
- return KERN_INVALID_TASK;
- }
- if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
- ipc_right_reverse(space, object, &name, &entry)) {
- /* object is locked and active */
- assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
- break;
- }
- kr = ipc_entry_alloc(space, &name, &entry);
- if (kr != KERN_SUCCESS) {
- is_write_unlock(space);
- return kr;
- }
- assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
- assert(entry->ie_object == IO_NULL);
- io_lock(object);
- if (!io_active(object)) {
- io_unlock(object);
- ipc_entry_dealloc(space, name, entry);
- is_write_unlock(space);
- return KERN_INVALID_CAPABILITY;
- }
- entry->ie_object = object;
- break;
- }
- /* space is write-locked and active, object is locked and active */
- kr = ipc_right_copyout(space, name, entry,
- msgt_name, overflow, object);
- /* object is unlocked */
- is_write_unlock(space);
- if (kr == KERN_SUCCESS)
- *namep = name;
- return kr;
- }
- #if 0
- /* XXX same, but don't check for already-existing send rights */
- kern_return_t
- ipc_object_copyout_multiname(space, object, namep)
- ipc_space_t space;
- ipc_object_t object;
- mach_port_t *namep;
- {
- mach_port_t name;
- ipc_entry_t entry;
- kern_return_t kr;
- assert(IO_VALID(object));
- assert(io_otype(object) == IOT_PORT);
- is_write_lock(space);
- for (;;) {
- if (!space->is_active) {
- is_write_unlock(space);
- return KERN_INVALID_TASK;
- }
- kr = ipc_entry_alloc(space, &name, &entry);
- if (kr != KERN_SUCCESS) {
- is_write_unlock(space);
- return kr; /* space is unlocked */
- }
- assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
- assert(entry->ie_object == IO_NULL);
- io_lock(object);
- if (!io_active(object)) {
- io_unlock(object);
- ipc_entry_dealloc(space, name, entry);
- is_write_unlock(space);
- return KERN_INVALID_CAPABILITY;
- }
- entry->ie_object = object;
- break;
- }
- /* space is write-locked and active, object is locked and active */
- kr = ipc_right_copyout_multiname(space, name, entry, object);
- /* object is unlocked */
- is_write_unlock(space);
- if (kr == KERN_SUCCESS)
- *namep = name;
- return kr;
- }
- #endif /* 0 */
- /*
- * Routine: ipc_object_copyout_name
- * Purpose:
- * Copyout a capability, placing it into a space.
- * The specified name is used for the capability.
- * If successful, consumes a ref for the object.
- * Conditions:
- * Nothing locked.
- * Returns:
- * KERN_SUCCESS Copied out object, consumed ref.
- * KERN_INVALID_TASK The space is dead.
- * KERN_INVALID_CAPABILITY The object is dead.
- * KERN_RESOURCE_SHORTAGE No memory available.
- * KERN_UREFS_OVERFLOW Urefs limit exceeded
- * and overflow wasn't specified.
- * KERN_RIGHT_EXISTS Space has rights under another name.
- * KERN_NAME_EXISTS Name is already used.
- */
- kern_return_t
- ipc_object_copyout_name(
- ipc_space_t space,
- ipc_object_t object,
- mach_msg_type_name_t msgt_name,
- boolean_t overflow,
- mach_port_t name)
- {
- mach_port_t oname;
- ipc_entry_t oentry;
- ipc_entry_t entry;
- kern_return_t kr;
- assert(IO_VALID(object));
- assert(io_otype(object) == IOT_PORT);
- is_write_lock(space);
- kr = ipc_entry_alloc_name(space, name, &entry);
- if (kr != KERN_SUCCESS) {
- is_write_unlock(space);
- return kr;
- }
- if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
- ipc_right_reverse(space, object, &oname, &oentry)) {
- /* object is locked and active */
- if (name != oname) {
- io_unlock(object);
- if (IE_BITS_TYPE(entry->ie_bits)
- == MACH_PORT_TYPE_NONE)
- ipc_entry_dealloc(space, name, entry);
- is_write_unlock(space);
- return KERN_RIGHT_EXISTS;
- }
- assert(entry == oentry);
- assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
- } else {
- if (ipc_right_inuse(space, name, entry))
- return KERN_NAME_EXISTS;
- assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
- assert(entry->ie_object == IO_NULL);
- io_lock(object);
- if (!io_active(object)) {
- io_unlock(object);
- ipc_entry_dealloc(space, name, entry);
- is_write_unlock(space);
- return KERN_INVALID_CAPABILITY;
- }
- entry->ie_object = object;
- }
- /* space is write-locked and active, object is locked and active */
- kr = ipc_right_copyout(space, name, entry,
- msgt_name, overflow, object);
- /* object is unlocked */
- is_write_unlock(space);
- return kr;
- }
- /*
- * Routine: ipc_object_copyout_dest
- * Purpose:
- * Translates/consumes the destination right of a message.
- * This is unlike normal copyout because the right is consumed
- * in a funny way instead of being given to the receiving space.
- * The receiver gets his name for the port, if he has receive
- * rights, otherwise MACH_PORT_NULL.
- * Conditions:
- * The object is locked and active. Nothing else locked.
- * The object is unlocked and loses a reference.
- */
- void
- ipc_object_copyout_dest(
- ipc_space_t space,
- ipc_object_t object,
- mach_msg_type_name_t msgt_name,
- mach_port_t *namep)
- {
- mach_port_t name;
- assert(IO_VALID(object));
- assert(io_active(object));
- io_release(object);
- /*
- * If the space is the receiver/owner of the object,
- * then we quietly consume the right and return
- * the space's name for the object. Otherwise
- * we destroy the right and return MACH_PORT_NULL.
- */
- switch (msgt_name) {
- case MACH_MSG_TYPE_PORT_SEND: {
- ipc_port_t port = (ipc_port_t) object;
- ipc_port_t nsrequest = IP_NULL;
- mach_port_mscount_t mscount = 0; /* '=0' to shut up lint */
- assert(port->ip_srights > 0);
- if (--port->ip_srights == 0) {
- nsrequest = port->ip_nsrequest;
- if (nsrequest != IP_NULL) {
- port->ip_nsrequest = IP_NULL;
- mscount = port->ip_mscount;
- }
- }
- if (port->ip_receiver == space)
- name = port->ip_receiver_name;
- else
- name = MACH_PORT_NULL;
- ip_unlock(port);
- if (nsrequest != IP_NULL)
- ipc_notify_no_senders(nsrequest, mscount);
- break;
- }
- case MACH_MSG_TYPE_PORT_SEND_ONCE: {
- ipc_port_t port = (ipc_port_t) object;
- assert(port->ip_sorights > 0);
- if (port->ip_receiver == space) {
- /* quietly consume the send-once right */
- port->ip_sorights--;
- name = port->ip_receiver_name;
- ip_unlock(port);
- } else {
- /*
- * A very bizarre case. The message
- * was received, but before this copyout
- * happened the space lost receive rights.
- * We can't quietly consume the soright
- * out from underneath some other task,
- * so generate a send-once notification.
- */
- ip_reference(port); /* restore ref */
- ip_unlock(port);
- ipc_notify_send_once(port);
- name = MACH_PORT_NULL;
- }
- break;
- }
- default:
- #if MACH_ASSERT
- assert(!"ipc_object_copyout_dest: strange rights");
- #else
- panic("ipc_object_copyout_dest: strange rights");
- #endif
- }
- *namep = name;
- }
- /*
- * Routine: ipc_object_rename
- * Purpose:
- * Rename an entry in a space.
- * Conditions:
- * Nothing locked.
- * Returns:
- * KERN_SUCCESS Renamed the entry.
- * KERN_INVALID_TASK The space was dead.
- * KERN_INVALID_NAME oname didn't denote an entry.
- * KERN_NAME_EXISTS nname already denoted an entry.
- * KERN_RESOURCE_SHORTAGE Couldn't allocate new entry.
- */
- kern_return_t
- ipc_object_rename(
- ipc_space_t space,
- mach_port_t oname,
- mach_port_t nname)
- {
- ipc_entry_t oentry, nentry;
- kern_return_t kr;
- is_write_lock(space);
- kr = ipc_entry_alloc_name(space, nname, &nentry);
- if (kr != KERN_SUCCESS) {
- is_write_unlock(space);
- return kr;
- }
- if (ipc_right_inuse(space, nname, nentry)) {
- /* space is unlocked */
- return KERN_NAME_EXISTS;
- }
- /* don't let ipc_entry_lookup see the uninitialized new entry */
- if ((oname == nname) ||
- ((oentry = ipc_entry_lookup(space, oname)) == IE_NULL)) {
- ipc_entry_dealloc(space, nname, nentry);
- is_write_unlock(space);
- return KERN_INVALID_NAME;
- }
- kr = ipc_right_rename(space, oname, oentry, nname, nentry);
- /* space is unlocked */
- return kr;
- }
- #if MACH_KDB
- #define printf kdbprintf
- /*
- * Routine: ipc_object_print
- * Purpose:
- * Pretty-print an object for kdb.
- */
- char *ikot_print_array[IKOT_MAX_TYPE] = {
- "(NONE) ",
- "(THREAD) ",
- "(TASK) ",
- "(HOST) ",
- "(HOST_PRIV) ",
- "(PROCESSOR) ",
- "(PSET) ",
- "(PSET_NAME) ",
- "(PAGER) ",
- "(PAGER_REQUEST) ",
- "(DEVICE) ", /* 10 */
- "(XMM_OBJECT) ",
- "(XMM_PAGER) ",
- "(XMM_KERNEL) ",
- "(XMM_REPLY) ",
- "(PAGER_TERMINATING)",
- "(PAGING_NAME) ",
- "(HOST_SECURITY) ",
- "(LEDGER) ",
- "(MASTER_DEVICE) ",
- "(ACTIVATION) ", /* 20 */
- "(SUBSYSTEM) ",
- "(IO_DONE_QUEUE) ",
- "(SEMAPHORE) ",
- "(LOCK_SET) ",
- "(CLOCK) ",
- "(CLOCK_CTRL) ",
- "(PAGER_PROXY) ", /* 27 */
- /* << new entries here */
- "(UNKNOWN) " /* magic catchall */
- }; /* Please keep in sync with kern/ipc_kobject.h */
- void
- ipc_object_print(
- const ipc_object_t object)
- {
- int kotype;
- iprintf("%s", io_active(object) ? "active" : "dead");
- printf(", refs=%d", object->io_references);
- printf(", otype=%d", io_otype(object));
- kotype = io_kotype(object);
- if (kotype >= 0 && kotype < IKOT_MAX_TYPE)
- printf(", kotype=%d %s\n", io_kotype(object),
- ikot_print_array[kotype]);
- else
- printf(", kotype=0x%x %s\n", io_kotype(object),
- ikot_print_array[IKOT_UNKNOWN]);
- }
- #endif /* MACH_KDB */
|