diff options
Diffstat (limited to 'ipc')
-rw-r--r-- | ipc/ipc_entry.c | 795 | ||||
-rw-r--r-- | ipc/ipc_entry.h | 72 | ||||
-rw-r--r-- | ipc/ipc_hash.c | 620 | ||||
-rw-r--r-- | ipc/ipc_hash.h | 96 | ||||
-rw-r--r-- | ipc/ipc_init.c | 10 | ||||
-rw-r--r-- | ipc/ipc_kmsg.c | 345 | ||||
-rw-r--r-- | ipc/ipc_kmsg.h | 29 | ||||
-rw-r--r-- | ipc/ipc_kmsg_queue.h | 2 | ||||
-rwxr-xr-x | ipc/ipc_machdep.h | 4 | ||||
-rw-r--r-- | ipc/ipc_marequest.c | 34 | ||||
-rw-r--r-- | ipc/ipc_mqueue.c | 14 | ||||
-rw-r--r-- | ipc/ipc_mqueue.h | 3 | ||||
-rw-r--r-- | ipc/ipc_notify.c | 42 | ||||
-rw-r--r-- | ipc/ipc_object.c | 58 | ||||
-rw-r--r-- | ipc/ipc_object.h | 6 | ||||
-rw-r--r-- | ipc/ipc_port.c | 88 | ||||
-rw-r--r-- | ipc/ipc_port.h | 30 | ||||
-rw-r--r-- | ipc/ipc_print.h | 39 | ||||
-rw-r--r-- | ipc/ipc_pset.c | 5 | ||||
-rw-r--r-- | ipc/ipc_pset.h | 3 | ||||
-rw-r--r-- | ipc/ipc_right.c | 91 | ||||
-rw-r--r-- | ipc/ipc_space.c | 104 | ||||
-rw-r--r-- | ipc/ipc_space.h | 228 | ||||
-rw-r--r-- | ipc/ipc_splay.c | 920 | ||||
-rw-r--r-- | ipc/ipc_splay.h | 114 | ||||
-rw-r--r-- | ipc/ipc_table.c | 70 | ||||
-rw-r--r-- | ipc/ipc_table.h | 59 | ||||
-rw-r--r-- | ipc/ipc_thread.h | 8 | ||||
-rw-r--r-- | ipc/mach_debug.c | 339 | ||||
-rw-r--r-- | ipc/mach_msg.c | 299 | ||||
-rw-r--r-- | ipc/mach_port.c | 263 | ||||
-rw-r--r-- | ipc/mach_port.h | 11 | ||||
-rw-r--r-- | ipc/mach_rpc.c | 9 | ||||
-rw-r--r-- | ipc/notify.defs | 22 | ||||
-rw-r--r-- | ipc/port.h | 7 |
35 files changed, 1065 insertions, 3774 deletions
diff --git a/ipc/ipc_entry.c b/ipc/ipc_entry.c index 3a062447..0414ba5f 100644 --- a/ipc/ipc_entry.c +++ b/ipc/ipc_entry.c @@ -46,158 +46,17 @@ #include <ipc/ipc_types.h> #include <ipc/ipc_entry.h> #include <ipc/ipc_space.h> -#include <ipc/ipc_splay.h> -#include <ipc/ipc_hash.h> #include <ipc/ipc_table.h> #include <ipc/ipc_object.h> -struct kmem_cache ipc_tree_entry_cache; - -/* - * Routine: ipc_entry_tree_collision - * Purpose: - * Checks if "name" collides with an allocated name - * in the space's tree. That is, returns TRUE - * if the splay tree contains a name with the same - * index as "name". - * Conditions: - * The space is locked (read or write) and active. - */ - -boolean_t -ipc_entry_tree_collision( - ipc_space_t space, - mach_port_t name) -{ - mach_port_index_t index; - mach_port_t lower, upper; - - assert(space->is_active); - - /* - * Check if we collide with the next smaller name - * or the next larger name. - */ - - ipc_splay_tree_bounds(&space->is_tree, name, &lower, &upper); - - index = MACH_PORT_INDEX(name); - return (((lower != ~0) && (MACH_PORT_INDEX(lower) == index)) || - ((upper != 0) && (MACH_PORT_INDEX(upper) == index))); -} - -/* - * Routine: ipc_entry_lookup - * Purpose: - * Searches for an entry, given its name. - * Conditions: - * The space must be read or write locked throughout. - * The space must be active. - */ - -ipc_entry_t -ipc_entry_lookup(space, name) - ipc_space_t space; - mach_port_t name; -{ - mach_port_index_t index; - ipc_entry_t entry; - - assert(space->is_active); - - index = MACH_PORT_INDEX(name); - if (index < space->is_table_size) { - entry = &space->is_table[index]; - if (IE_BITS_GEN(entry->ie_bits) != MACH_PORT_GEN(name)) - if (entry->ie_bits & IE_BITS_COLLISION) { - assert(space->is_tree_total > 0); - goto tree_lookup; - } else - entry = IE_NULL; - else if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) - entry = IE_NULL; - } else if (space->is_tree_total == 0) - entry = IE_NULL; - else - tree_lookup: - entry = (ipc_entry_t) - ipc_splay_tree_lookup(&space->is_tree, name); - - assert((entry == IE_NULL) || IE_BITS_TYPE(entry->ie_bits)); - return entry; -} - -/* - * Routine: ipc_entry_get - * Purpose: - * Tries to allocate an entry out of the space. - * Conditions: - * The space is write-locked and active throughout. - * An object may be locked. Will not allocate memory. - * Returns: - * KERN_SUCCESS A free entry was found. - * KERN_NO_SPACE No entry allocated. - */ - -kern_return_t -ipc_entry_get(space, namep, entryp) - ipc_space_t space; - mach_port_t *namep; - ipc_entry_t *entryp; -{ - ipc_entry_t table; - mach_port_index_t first_free; - mach_port_t new_name; - ipc_entry_t free_entry; - - assert(space->is_active); - - table = space->is_table; - first_free = table->ie_next; - - if (first_free == 0) - return KERN_NO_SPACE; - - free_entry = &table[first_free]; - table->ie_next = free_entry->ie_next; - - /* - * Initialize the new entry. We need only - * increment the generation number and clear ie_request. - */ - - { - mach_port_gen_t gen; - - assert((free_entry->ie_bits &~ IE_BITS_GEN_MASK) == 0); - gen = free_entry->ie_bits + IE_BITS_GEN_ONE; - free_entry->ie_bits = gen; - free_entry->ie_request = 0; - new_name = MACH_PORT_MAKE(first_free, gen); - } - - /* - * The new name can't be MACH_PORT_NULL because index - * is non-zero. It can't be MACH_PORT_DEAD because - * the table isn't allowed to grow big enough. - * (See comment in ipc/ipc_table.h.) - */ - - assert(MACH_PORT_VALID(new_name)); - assert(free_entry->ie_object == IO_NULL); - - *namep = new_name; - *entryp = free_entry; - return KERN_SUCCESS; -} +struct kmem_cache ipc_entry_cache; /* * Routine: ipc_entry_alloc * Purpose: * Allocate an entry out of the space. * Conditions: - * The space is not locked before, but it is write-locked after - * if the call is successful. May allocate memory. + * The space must be write-locked. May allocate memory. * Returns: * KERN_SUCCESS An entry was allocated. * KERN_INVALID_TASK The space is dead. @@ -212,23 +71,37 @@ ipc_entry_alloc( ipc_entry_t *entryp) { kern_return_t kr; + ipc_entry_t entry; + rdxtree_key_t key; - is_write_lock(space); + if (!space->is_active) { + return KERN_INVALID_TASK; + } - for (;;) { - if (!space->is_active) { - is_write_unlock(space); - return KERN_INVALID_TASK; - } + kr = ipc_entry_get(space, namep, entryp); + if (kr == KERN_SUCCESS) + return kr; - kr = ipc_entry_get(space, namep, entryp); - if (kr == KERN_SUCCESS) - return kr; + entry = ie_alloc(); + if (entry == IE_NULL) { + return KERN_RESOURCE_SHORTAGE; + } - kr = ipc_entry_grow_table(space); - if (kr != KERN_SUCCESS) - return kr; /* space is unlocked */ + kr = rdxtree_insert_alloc(&space->is_map, entry, &key); + if (kr) { + ie_free(entry); + return kr; } + space->is_size += 1; + + entry->ie_bits = 0; + entry->ie_object = IO_NULL; + entry->ie_request = 0; + entry->ie_name = (mach_port_t) key; + + *entryp = entry; + *namep = (mach_port_t) key; + return KERN_SUCCESS; } /* @@ -237,8 +110,7 @@ ipc_entry_alloc( * Allocates/finds an entry with a specific name. * If an existing entry is returned, its type will be nonzero. * Conditions: - * The space is not locked before, but it is write-locked after - * if the call is successful. May allocate memory. + * The space must be write-locked. May allocate memory. * Returns: * KERN_SUCCESS Found existing entry with same name. * KERN_SUCCESS Allocated a new entry. @@ -252,601 +124,80 @@ ipc_entry_alloc_name( mach_port_t name, ipc_entry_t *entryp) { - mach_port_index_t index = MACH_PORT_INDEX(name); - mach_port_gen_t gen = MACH_PORT_GEN(name); - ipc_tree_entry_t tree_entry = ITE_NULL; - + kern_return_t kr; + ipc_entry_t entry, e, *prevp; + void **slot; assert(MACH_PORT_VALID(name)); + if (!space->is_active) { + return KERN_INVALID_TASK; + } - is_write_lock(space); - - for (;;) { - ipc_entry_t entry; - ipc_tree_entry_t tentry; - ipc_table_size_t its; - - if (!space->is_active) { - is_write_unlock(space); - if (tree_entry) ite_free(tree_entry); - return KERN_INVALID_TASK; - } - - /* - * If we are under the table cutoff, - * there are three cases: - * 1) The entry is inuse, for the same name - * 2) The entry is inuse, for a different name - * 3) The entry is free - */ - - if ((0 < index) && (index < space->is_table_size)) { - ipc_entry_t table = space->is_table; - - entry = &table[index]; - - if (IE_BITS_TYPE(entry->ie_bits)) { - if (IE_BITS_GEN(entry->ie_bits) == gen) { - *entryp = entry; - if (tree_entry) ite_free(tree_entry); - return KERN_SUCCESS; - } - } else { - mach_port_index_t free_index, next_index; - - /* - * Rip the entry out of the free list. - */ - - for (free_index = 0; - (next_index = table[free_index].ie_next) - != index; - free_index = next_index) - continue; - - table[free_index].ie_next = - table[next_index].ie_next; - - entry->ie_bits = gen; - assert(entry->ie_object == IO_NULL); - entry->ie_request = 0; - - *entryp = entry; - if (tree_entry) ite_free(tree_entry); - return KERN_SUCCESS; - } - } - - /* - * Before trying to allocate any memory, - * check if the entry already exists in the tree. - * This avoids spurious resource errors. - * The splay tree makes a subsequent lookup/insert - * of the same name cheap, so this costs little. - */ - - if ((space->is_tree_total > 0) && - ((tentry = ipc_splay_tree_lookup(&space->is_tree, name)) - != ITE_NULL)) { - assert(tentry->ite_space == space); - assert(IE_BITS_TYPE(tentry->ite_bits)); + slot = rdxtree_lookup_slot(&space->is_map, (rdxtree_key_t) name); + if (slot != NULL) + entry = *(ipc_entry_t *) slot; - *entryp = &tentry->ite_entry; - if (tree_entry) ite_free(tree_entry); - return KERN_SUCCESS; + if (slot == NULL || entry == IE_NULL) { + entry = ie_alloc(); + if (entry == IE_NULL) { + return KERN_RESOURCE_SHORTAGE; } - its = space->is_table_next; - - /* - * Check if the table should be grown. - * - * Note that if space->is_table_size == its->its_size, - * then we won't ever try to grow the table. - * - * Note that we are optimistically assuming that name - * doesn't collide with any existing names. (So if - * it were entered into the tree, is_tree_small would - * be incremented.) This is OK, because even in that - * case, we don't lose memory by growing the table. - */ + entry->ie_bits = 0; + entry->ie_object = IO_NULL; + entry->ie_request = 0; + entry->ie_name = name; - if ((space->is_table_size <= index) && - (index < its->its_size) && - (((its->its_size - space->is_table_size) * - sizeof(struct ipc_entry)) < - ((space->is_tree_small + 1) * - sizeof(struct ipc_tree_entry)))) { - kern_return_t kr; - - /* - * Can save space by growing the table. - * Because the space will be unlocked, - * we must restart. - */ - - kr = ipc_entry_grow_table(space); - assert(kr != KERN_NO_SPACE); + if (slot != NULL) + rdxtree_replace_slot(slot, entry); + else { + kr = rdxtree_insert(&space->is_map, + (rdxtree_key_t) name, entry); if (kr != KERN_SUCCESS) { - /* space is unlocked */ - if (tree_entry) ite_free(tree_entry); + ie_free(entry); return kr; } - - continue; - } - - /* - * If a splay-tree entry was allocated previously, - * go ahead and insert it into the tree. - */ - - if (tree_entry != ITE_NULL) { - space->is_tree_total++; - - if (index < space->is_table_size) - space->is_table[index].ie_bits |= - IE_BITS_COLLISION; - else if ((index < its->its_size) && - !ipc_entry_tree_collision(space, name)) - space->is_tree_small++; - - ipc_splay_tree_insert(&space->is_tree, - name, tree_entry); - - tree_entry->ite_bits = 0; - tree_entry->ite_object = IO_NULL; - tree_entry->ite_request = 0; - tree_entry->ite_space = space; - *entryp = &tree_entry->ite_entry; - return KERN_SUCCESS; } + space->is_size += 1; - /* - * Allocate a tree entry and try again. - */ - - is_write_unlock(space); - tree_entry = ite_alloc(); - if (tree_entry == ITE_NULL) - return KERN_RESOURCE_SHORTAGE; - is_write_lock(space); + *entryp = entry; + return KERN_SUCCESS; } -} - -/* - * Routine: ipc_entry_dealloc - * Purpose: - * Deallocates an entry from a space. - * Conditions: - * The space must be write-locked throughout. - * The space must be active. - */ - -void -ipc_entry_dealloc( - ipc_space_t space, - mach_port_t name, - ipc_entry_t entry) -{ - ipc_entry_t table; - ipc_entry_num_t size; - mach_port_index_t index; - assert(space->is_active); - assert(entry->ie_object == IO_NULL); - assert(entry->ie_request == 0); - - index = MACH_PORT_INDEX(name); - table = space->is_table; - size = space->is_table_size; - - if ((index < size) && (entry == &table[index])) { - assert(IE_BITS_GEN(entry->ie_bits) == MACH_PORT_GEN(name)); - - if (entry->ie_bits & IE_BITS_COLLISION) { - struct ipc_splay_tree small, collisions; - ipc_tree_entry_t tentry; - mach_port_t tname; - boolean_t pick; - ipc_entry_bits_t bits; - ipc_object_t obj; - - /* must move an entry from tree to table */ - - ipc_splay_tree_split(&space->is_tree, - MACH_PORT_MAKE(index+1, 0), - &collisions); - ipc_splay_tree_split(&collisions, - MACH_PORT_MAKE(index, 0), - &small); - - pick = ipc_splay_tree_pick(&collisions, - &tname, &tentry); - assert(pick); - assert(MACH_PORT_INDEX(tname) == index); - - bits = tentry->ite_bits; - entry->ie_bits = bits | MACH_PORT_GEN(tname); - entry->ie_object = obj = tentry->ite_object; - entry->ie_request = tentry->ite_request; - assert(tentry->ite_space == space); - - if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND) { - ipc_hash_global_delete(space, obj, - tname, tentry); - ipc_hash_local_insert(space, obj, - index, entry); - } - - ipc_splay_tree_delete(&collisions, tname, tentry); - - assert(space->is_tree_total > 0); - space->is_tree_total--; - - /* check if collision bit should still be on */ - - pick = ipc_splay_tree_pick(&collisions, - &tname, &tentry); - if (pick) { - entry->ie_bits |= IE_BITS_COLLISION; - ipc_splay_tree_join(&space->is_tree, - &collisions); - } - - ipc_splay_tree_join(&space->is_tree, &small); - } else { - entry->ie_bits &= IE_BITS_GEN_MASK; - entry->ie_next = table->ie_next; - table->ie_next = index; - } - } else { - ipc_tree_entry_t tentry = (ipc_tree_entry_t) entry; - - assert(tentry->ite_space == space); - - ipc_splay_tree_delete(&space->is_tree, name, tentry); - - assert(space->is_tree_total > 0); - space->is_tree_total--; - - if (index < size) { - ipc_entry_t ientry = &table[index]; - - assert(ientry->ie_bits & IE_BITS_COLLISION); - - if (!ipc_entry_tree_collision(space, name)) - ientry->ie_bits &= ~IE_BITS_COLLISION; - } else if ((index < space->is_table_next->its_size) && - !ipc_entry_tree_collision(space, name)) { - assert(space->is_tree_small > 0); - space->is_tree_small--; - } + if (IE_BITS_TYPE(entry->ie_bits)) { + /* Used entry. */ + *entryp = entry; + return KERN_SUCCESS; } -} -/* - * Routine: ipc_entry_grow_table - * Purpose: - * Grows the table in a space. - * Conditions: - * The space must be write-locked and active before. - * If successful, it is also returned locked. - * Allocates memory. - * Returns: - * KERN_SUCCESS Grew the table. - * KERN_SUCCESS Somebody else grew the table. - * KERN_SUCCESS The space died. - * KERN_NO_SPACE Table has maximum size already. - * KERN_RESOURCE_SHORTAGE Couldn't allocate a new table. - */ - -kern_return_t -ipc_entry_grow_table(space) - ipc_space_t space; -{ - ipc_entry_num_t osize, size, nsize; - - do { - ipc_entry_t otable, table; - ipc_table_size_t oits, its, nits; - mach_port_index_t i, free_index; - - assert(space->is_active); - - if (space->is_growing) { - /* - * Somebody else is growing the table. - * We just wait for them to finish. - */ - - assert_wait((event_t) space, FALSE); - is_write_unlock(space); - thread_block((void (*)()) 0); - is_write_lock(space); - return KERN_SUCCESS; - } - - otable = space->is_table; - its = space->is_table_next; - size = its->its_size; - oits = its - 1; - osize = oits->its_size; - nits = its + 1; - nsize = nits->its_size; - - if (osize == size) { - is_write_unlock(space); - printf_once("no more room for ipc_entry_grow_table in space %p\n", space); - return KERN_NO_SPACE; - } - - assert((osize < size) && (size <= nsize)); - - /* - * OK, we'll attempt to grow the table. - * The realloc requires that the old table - * remain in existence. - */ + /* Free entry. Rip the entry out of the free list. */ + for (prevp = &space->is_free_list, e = space->is_free_list; + e != entry; + ({ prevp = &e->ie_next_free; e = e->ie_next_free; })) + continue; - space->is_growing = TRUE; - is_write_unlock(space); - if (it_entries_reallocable(oits)) - table = it_entries_realloc(oits, otable, its); - else - table = it_entries_alloc(its); - is_write_lock(space); - space->is_growing = FALSE; + *prevp = entry->ie_next_free; + space->is_free_list_size -= 1; - /* - * We need to do a wakeup on the space, - * to rouse waiting threads. We defer - * this until the space is unlocked, - * because we don't want them to spin. - */ - - if (table == IE_NULL) { - is_write_unlock(space); - thread_wakeup((event_t) space); - return KERN_RESOURCE_SHORTAGE; - } - - if (!space->is_active) { - /* - * The space died while it was unlocked. - */ - - is_write_unlock(space); - thread_wakeup((event_t) space); - it_entries_free(its, table); - is_write_lock(space); - return KERN_SUCCESS; - } - - assert(space->is_table == otable); - assert(space->is_table_next == its); - assert(space->is_table_size == osize); - - space->is_table = table; - space->is_table_size = size; - space->is_table_next = nits; - - /* - * If we did a realloc, it remapped the data. - * Otherwise we copy by hand first. Then we have - * to clear the index fields in the old part and - * zero the new part. - */ - - if (!it_entries_reallocable(oits)) - memcpy(table, otable, - osize * sizeof(struct ipc_entry)); - - for (i = 0; i < osize; i++) - table[i].ie_index = 0; - - (void) memset((void *) (table + osize), 0, - (size - osize) * sizeof(struct ipc_entry)); - - /* - * Put old entries into the reverse hash table. - */ - - for (i = 0; i < osize; i++) { - ipc_entry_t entry = &table[i]; - - if (IE_BITS_TYPE(entry->ie_bits) == - MACH_PORT_TYPE_SEND) - ipc_hash_local_insert(space, entry->ie_object, - i, entry); - } - - /* - * If there are entries in the splay tree, - * then we have work to do: - * 1) transfer entries to the table - * 2) update is_tree_small - */ - - if (space->is_tree_total > 0) { - mach_port_index_t index; - boolean_t delete; - struct ipc_splay_tree ignore; - struct ipc_splay_tree move; - struct ipc_splay_tree small; - ipc_entry_num_t nosmall; - ipc_tree_entry_t tentry; - - /* - * The splay tree divides into four regions, - * based on the index of the entries: - * 1) 0 <= index < osize - * 2) osize <= index < size - * 3) size <= index < nsize - * 4) nsize <= index - * - * Entries in the first part are ignored. - * Entries in the second part, that don't - * collide, are moved into the table. - * Entries in the third part, that don't - * collide, are counted for is_tree_small. - * Entries in the fourth part are ignored. - */ - - ipc_splay_tree_split(&space->is_tree, - MACH_PORT_MAKE(nsize, 0), - &small); - ipc_splay_tree_split(&small, - MACH_PORT_MAKE(size, 0), - &move); - ipc_splay_tree_split(&move, - MACH_PORT_MAKE(osize, 0), - &ignore); - - /* move entries into the table */ - - for (tentry = ipc_splay_traverse_start(&move); - tentry != ITE_NULL; - tentry = ipc_splay_traverse_next(&move, delete)) { - mach_port_t name; - mach_port_gen_t gen; - mach_port_type_t type; - ipc_entry_bits_t bits; - ipc_object_t obj; - ipc_entry_t entry; - - name = tentry->ite_name; - gen = MACH_PORT_GEN(name); - index = MACH_PORT_INDEX(name); - - assert(tentry->ite_space == space); - assert((osize <= index) && (index < size)); - - entry = &table[index]; - - /* collision with previously moved entry? */ - - bits = entry->ie_bits; - if (bits != 0) { - assert(IE_BITS_TYPE(bits)); - assert(IE_BITS_GEN(bits) != gen); - - entry->ie_bits = - bits | IE_BITS_COLLISION; - delete = FALSE; - continue; - } - - bits = tentry->ite_bits; - type = IE_BITS_TYPE(bits); - assert(type != MACH_PORT_TYPE_NONE); - - entry->ie_bits = bits | gen; - entry->ie_object = obj = tentry->ite_object; - entry->ie_request = tentry->ite_request; - - if (type == MACH_PORT_TYPE_SEND) { - ipc_hash_global_delete(space, obj, - name, tentry); - ipc_hash_local_insert(space, obj, - index, entry); - } - - space->is_tree_total--; - delete = TRUE; - } - ipc_splay_traverse_finish(&move); - - /* count entries for is_tree_small */ - - nosmall = 0; index = 0; - for (tentry = ipc_splay_traverse_start(&small); - tentry != ITE_NULL; - tentry = ipc_splay_traverse_next(&small, FALSE)) { - mach_port_index_t nindex; - - nindex = MACH_PORT_INDEX(tentry->ite_name); - - if (nindex != index) { - nosmall++; - index = nindex; - } - } - ipc_splay_traverse_finish(&small); - - assert(nosmall <= (nsize - size)); - assert(nosmall <= space->is_tree_total); - space->is_tree_small = nosmall; - - /* put the splay tree back together */ - - ipc_splay_tree_join(&space->is_tree, &small); - ipc_splay_tree_join(&space->is_tree, &move); - ipc_splay_tree_join(&space->is_tree, &ignore); - } - - /* - * Add entries in the new part which still aren't used - * to the free list. Add them in reverse order, - * and set the generation number to -1, so that - * early allocations produce "natural" names. - */ - - free_index = table[0].ie_next; - for (i = size-1; i >= osize; --i) { - ipc_entry_t entry = &table[i]; - - if (entry->ie_bits == 0) { - entry->ie_bits = IE_BITS_GEN_MASK; - entry->ie_next = free_index; - free_index = i; - } - } - table[0].ie_next = free_index; - - /* - * Now we need to free the old table. - * If the space dies or grows while unlocked, - * then we can quit here. - */ - - is_write_unlock(space); - thread_wakeup((event_t) space); - it_entries_free(oits, otable); - is_write_lock(space); - if (!space->is_active || (space->is_table_next != nits)) - return KERN_SUCCESS; - - /* - * We might have moved enough entries from - * the splay tree into the table that - * the table can be profitably grown again. - * - * Note that if size == nsize, then - * space->is_tree_small == 0. - */ - } while ((space->is_tree_small > 0) && - (((nsize - size) * sizeof(struct ipc_entry)) < - (space->is_tree_small * sizeof(struct ipc_tree_entry)))); + entry->ie_bits = 0; + assert(entry->ie_object == IO_NULL); + assert(entry->ie_name == name); + entry->ie_request = 0; + space->is_size += 1; + *entryp = entry; return KERN_SUCCESS; } - #if MACH_KDB #include <ddb/db_output.h> #include <kern/task.h> #define printf kdbprintf -ipc_entry_t db_ipc_object_by_name( - task_t task, - mach_port_t name); - - ipc_entry_t db_ipc_object_by_name( - task_t task, + const task_t task, mach_port_t name) { ipc_space_t space = task->itk_space; diff --git a/ipc/ipc_entry.h b/ipc/ipc_entry.h index 6afa4f68..b429984b 100644 --- a/ipc/ipc_entry.h +++ b/ipc/ipc_entry.h @@ -48,47 +48,27 @@ /* * Spaces hold capabilities for ipc_object_t's (ports and port sets). - * Each ipc_entry_t records a capability. Most capabilities have - * small names, and the entries are elements of a table. - * Capabilities can have large names, and a splay tree holds - * those entries. The cutoff point between the table and the tree - * is adjusted dynamically to minimize memory consumption. - * - * The ie_index field of entries in the table implements - * a ordered hash table with open addressing and linear probing. - * This hash table converts (space, object) -> name. - * It is used independently of the other fields. - * - * Free (unallocated) entries in the table have null ie_object - * fields. The ie_bits field is zero except for IE_BITS_GEN. - * The ie_next (ie_request) field links free entries into a free list. - * - * The first entry in the table (index 0) is always free. - * It is used as the head of the free list. + * Each ipc_entry_t records a capability. */ typedef unsigned int ipc_entry_bits_t; typedef ipc_table_elems_t ipc_entry_num_t; /* number of entries */ typedef struct ipc_entry { + mach_port_t ie_name; ipc_entry_bits_t ie_bits; struct ipc_object *ie_object; union { - mach_port_index_t next; + struct ipc_entry *next_free; /*XXX ipc_port_request_index_t request;*/ unsigned int request; } index; - union { - mach_port_index_t table; - struct ipc_tree_entry *tree; - } hash; } *ipc_entry_t; #define IE_NULL ((ipc_entry_t) 0) #define ie_request index.request -#define ie_next index.next -#define ie_index hash.table +#define ie_next_free index.next_free #define IE_BITS_UREFS_MASK 0x0000ffff /* 16 bits of user-reference */ #define IE_BITS_UREFS(bits) ((bits) & IE_BITS_UREFS_MASK) @@ -98,12 +78,10 @@ typedef struct ipc_entry { #define IE_BITS_MAREQUEST 0x00200000 /* 1 bit for msg-accepted */ -#define IE_BITS_COMPAT 0x00400000 /* 1 bit for compatibility */ - -#define IE_BITS_COLLISION 0x00800000 /* 1 bit for collisions */ -#define IE_BITS_RIGHT_MASK 0x007fffff /* relevant to the right */ +#define IE_BITS_RIGHT_MASK 0x003fffff /* relevant to the right */ #if PORT_GENERATIONS +#error "not supported" #define IE_BITS_GEN_MASK 0xff000000U /* 8 bits for generation */ #define IE_BITS_GEN(bits) ((bits) & IE_BITS_GEN_MASK) #define IE_BITS_GEN_ONE 0x01000000 /* low bit of generation */ @@ -114,32 +92,9 @@ typedef struct ipc_entry { #endif -typedef struct ipc_tree_entry { - struct ipc_entry ite_entry; - mach_port_t ite_name; - struct ipc_space *ite_space; - struct ipc_tree_entry *ite_lchild; - struct ipc_tree_entry *ite_rchild; -} *ipc_tree_entry_t; - -#define ITE_NULL ((ipc_tree_entry_t) 0) - -#define ite_bits ite_entry.ie_bits -#define ite_object ite_entry.ie_object -#define ite_request ite_entry.ie_request -#define ite_next ite_entry.hash.tree - -extern struct kmem_cache ipc_tree_entry_cache; - -#define ite_alloc() ((ipc_tree_entry_t) kmem_cache_alloc(&ipc_tree_entry_cache)) -#define ite_free(ite) kmem_cache_free(&ipc_tree_entry_cache, (vm_offset_t) (ite)) - - -extern ipc_entry_t -ipc_entry_lookup(ipc_space_t space, mach_port_t name); - -extern kern_return_t -ipc_entry_get(ipc_space_t space, mach_port_t *namep, ipc_entry_t *entryp); +extern struct kmem_cache ipc_entry_cache; +#define ie_alloc() ((ipc_entry_t) kmem_cache_alloc(&ipc_entry_cache)) +#define ie_free(e) kmem_cache_free(&ipc_entry_cache, (vm_offset_t) (e)) extern kern_return_t ipc_entry_alloc(ipc_space_t space, mach_port_t *namep, ipc_entry_t *entryp); @@ -147,10 +102,9 @@ ipc_entry_alloc(ipc_space_t space, mach_port_t *namep, ipc_entry_t *entryp); extern kern_return_t ipc_entry_alloc_name(ipc_space_t space, mach_port_t name, ipc_entry_t *entryp); -extern void -ipc_entry_dealloc(ipc_space_t space, mach_port_t name, ipc_entry_t entry); - -extern kern_return_t -ipc_entry_grow_table(ipc_space_t space); +ipc_entry_t +db_ipc_object_by_name( + task_t task, + mach_port_t name); #endif /* _IPC_IPC_ENTRY_H_ */ diff --git a/ipc/ipc_hash.c b/ipc/ipc_hash.c deleted file mode 100644 index 5eec58cb..00000000 --- a/ipc/ipc_hash.c +++ /dev/null @@ -1,620 +0,0 @@ -/* - * 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_hash.c - * Author: Rich Draves - * Date: 1989 - * - * Entry hash table operations. - */ - -#include <kern/printf.h> -#include <mach/boolean.h> -#include <mach/port.h> -#include <kern/lock.h> -#include <kern/kalloc.h> -#include <ipc/port.h> -#include <ipc/ipc_space.h> -#include <ipc/ipc_object.h> -#include <ipc/ipc_entry.h> -#include <ipc/ipc_hash.h> -#include <ipc/ipc_init.h> -#include <ipc/ipc_types.h> - -#if MACH_IPC_DEBUG -#include <mach/kern_return.h> -#include <mach_debug/hash_info.h> -#include <vm/vm_map.h> -#include <vm/vm_kern.h> -#include <vm/vm_user.h> -#endif - - - -/* - * Routine: ipc_hash_lookup - * Purpose: - * Converts (space, obj) -> (name, entry). - * Returns TRUE if an entry was found. - * Conditions: - * The space must be locked (read or write) throughout. - */ - -boolean_t -ipc_hash_lookup(space, obj, namep, entryp) - ipc_space_t space; - ipc_object_t obj; - mach_port_t *namep; - ipc_entry_t *entryp; -{ - return (ipc_hash_local_lookup(space, obj, namep, entryp) || - ((space->is_tree_hash > 0) && - ipc_hash_global_lookup(space, obj, namep, - (ipc_tree_entry_t *) entryp))); -} - -/* - * Routine: ipc_hash_insert - * Purpose: - * Inserts an entry into the appropriate reverse hash table, - * so that ipc_hash_lookup will find it. - * Conditions: - * The space must be write-locked. - */ - -void -ipc_hash_insert( - ipc_space_t space, - ipc_object_t obj, - mach_port_t name, - ipc_entry_t entry) -{ - mach_port_index_t index; - - index = MACH_PORT_INDEX(name); - if ((index < space->is_table_size) && - (entry == &space->is_table[index])) - ipc_hash_local_insert(space, obj, index, entry); - else - ipc_hash_global_insert(space, obj, name, - (ipc_tree_entry_t) entry); -} - -/* - * Routine: ipc_hash_delete - * Purpose: - * Deletes an entry from the appropriate reverse hash table. - * Conditions: - * The space must be write-locked. - */ - -void -ipc_hash_delete( - ipc_space_t space, - ipc_object_t obj, - mach_port_t name, - ipc_entry_t entry) -{ - mach_port_index_t index; - - index = MACH_PORT_INDEX(name); - if ((index < space->is_table_size) && - (entry == &space->is_table[index])) - ipc_hash_local_delete(space, obj, index, entry); - else - ipc_hash_global_delete(space, obj, name, - (ipc_tree_entry_t) entry); -} - -/* - * The global reverse hash table holds splay tree entries. - * It is a simple open-chaining hash table with singly-linked buckets. - * Each bucket is locked separately, with an exclusive lock. - * Within each bucket, move-to-front is used. - */ - -ipc_hash_index_t ipc_hash_global_size; -ipc_hash_index_t ipc_hash_global_mask; - -#define IH_GLOBAL_HASH(space, obj) \ - (((((ipc_hash_index_t) ((vm_offset_t)space)) >> 4) + \ - (((ipc_hash_index_t) ((vm_offset_t)obj)) >> 6)) & \ - ipc_hash_global_mask) - -typedef struct ipc_hash_global_bucket { - decl_simple_lock_data(, ihgb_lock_data) - ipc_tree_entry_t ihgb_head; -} *ipc_hash_global_bucket_t; - -#define IHGB_NULL ((ipc_hash_global_bucket_t) 0) - -#define ihgb_lock_init(ihgb) simple_lock_init(&(ihgb)->ihgb_lock_data) -#define ihgb_lock(ihgb) simple_lock(&(ihgb)->ihgb_lock_data) -#define ihgb_unlock(ihgb) simple_unlock(&(ihgb)->ihgb_lock_data) - -ipc_hash_global_bucket_t ipc_hash_global_table; - -/* - * Routine: ipc_hash_global_lookup - * Purpose: - * Converts (space, obj) -> (name, entry). - * Looks in the global table, for splay tree entries. - * Returns TRUE if an entry was found. - * Conditions: - * The space must be locked (read or write) throughout. - */ - -boolean_t -ipc_hash_global_lookup( - ipc_space_t space, - ipc_object_t obj, - mach_port_t *namep, - ipc_tree_entry_t *entryp) -{ - ipc_hash_global_bucket_t bucket; - ipc_tree_entry_t this, *last; - - assert(space != IS_NULL); - assert(obj != IO_NULL); - - bucket = &ipc_hash_global_table[IH_GLOBAL_HASH(space, obj)]; - ihgb_lock(bucket); - - if ((this = bucket->ihgb_head) != ITE_NULL) { - if ((this->ite_object == obj) && - (this->ite_space == space)) { - /* found it at front; no need to move */ - - *namep = this->ite_name; - *entryp = this; - } else for (last = &this->ite_next; - (this = *last) != ITE_NULL; - last = &this->ite_next) { - if ((this->ite_object == obj) && - (this->ite_space == space)) { - /* found it; move to front */ - - *last = this->ite_next; - this->ite_next = bucket->ihgb_head; - bucket->ihgb_head = this; - - *namep = this->ite_name; - *entryp = this; - break; - } - } - } - - ihgb_unlock(bucket); - return this != ITE_NULL; -} - -/* - * Routine: ipc_hash_global_insert - * Purpose: - * Inserts an entry into the global reverse hash table. - * Conditions: - * The space must be write-locked. - */ - -void -ipc_hash_global_insert( - ipc_space_t space, - ipc_object_t obj, - mach_port_t name, - ipc_tree_entry_t entry) -{ - ipc_hash_global_bucket_t bucket; - - - assert(entry->ite_name == name); - assert(space != IS_NULL); - assert(entry->ite_space == space); - assert(obj != IO_NULL); - assert(entry->ite_object == obj); - - space->is_tree_hash++; - assert(space->is_tree_hash <= space->is_tree_total); - - bucket = &ipc_hash_global_table[IH_GLOBAL_HASH(space, obj)]; - ihgb_lock(bucket); - - /* insert at front of bucket */ - - entry->ite_next = bucket->ihgb_head; - bucket->ihgb_head = entry; - - ihgb_unlock(bucket); -} - -/* - * Routine: ipc_hash_global_delete - * Purpose: - * Deletes an entry from the global reverse hash table. - * Conditions: - * The space must be write-locked. - */ - -void -ipc_hash_global_delete( - ipc_space_t space, - ipc_object_t obj, - mach_port_t name, - ipc_tree_entry_t entry) -{ - ipc_hash_global_bucket_t bucket; - ipc_tree_entry_t this, *last; - - assert(entry->ite_name == name); - assert(space != IS_NULL); - assert(entry->ite_space == space); - assert(obj != IO_NULL); - assert(entry->ite_object == obj); - - assert(space->is_tree_hash > 0); - space->is_tree_hash--; - - bucket = &ipc_hash_global_table[IH_GLOBAL_HASH(space, obj)]; - ihgb_lock(bucket); - - for (last = &bucket->ihgb_head; - (this = *last) != ITE_NULL; - last = &this->ite_next) { - if (this == entry) { - /* found it; remove from bucket */ - - *last = this->ite_next; - break; - } - } - assert(this != ITE_NULL); - - ihgb_unlock(bucket); -} - -/* - * Each space has a local reverse hash table, which holds - * entries from the space's table. In fact, the hash table - * just uses a field (ie_index) in the table itself. - * - * The local hash table is an open-addressing hash table, - * which means that when a collision occurs, instead of - * throwing the entry into a bucket, the entry is rehashed - * to another position in the table. In this case the rehash - * is very simple: linear probing (ie, just increment the position). - * This simple rehash makes deletions tractable (they're still a pain), - * but it means that collisions tend to build up into clumps. - * - * Because at least one entry in the table (index 0) is always unused, - * there will always be room in the reverse hash table. If a table - * with n slots gets completely full, the reverse hash table will - * have one giant clump of n-1 slots and one free slot somewhere. - * Because entries are only entered into the reverse table if they - * are pure send rights (not receive, send-once, port-set, - * or dead-name rights), and free entries of course aren't entered, - * I expect the reverse hash table won't get unreasonably full. - * - * Ordered hash tables (Amble & Knuth, Computer Journal, v. 17, no. 2, - * pp. 135-142.) may be desirable here. They can dramatically help - * unsuccessful lookups. But unsuccessful lookups are almost always - * followed by insertions, and those slow down somewhat. They - * also can help deletions somewhat. Successful lookups aren't affected. - * So possibly a small win; probably nothing significant. - */ - -#define IH_LOCAL_HASH(obj, size) \ - ((((mach_port_index_t) (vm_offset_t) (obj)) >> 6) % (size)) - -/* - * Routine: ipc_hash_local_lookup - * Purpose: - * Converts (space, obj) -> (name, entry). - * Looks in the space's local table, for table entries. - * Returns TRUE if an entry was found. - * Conditions: - * The space must be locked (read or write) throughout. - */ - -boolean_t -ipc_hash_local_lookup( - ipc_space_t space, - ipc_object_t obj, - mach_port_t *namep, - ipc_entry_t *entryp) -{ - ipc_entry_t table; - ipc_entry_num_t size; - mach_port_index_t hindex, index; - - assert(space != IS_NULL); - assert(obj != IO_NULL); - - table = space->is_table; - size = space->is_table_size; - hindex = IH_LOCAL_HASH(obj, size); - - /* - * Ideally, table[hindex].ie_index is the name we want. - * However, must check ie_object to verify this, - * because collisions can happen. In case of a collision, - * search farther along in the clump. - */ - - while ((index = table[hindex].ie_index) != 0) { - ipc_entry_t entry = &table[index]; - - if (entry->ie_object == obj) { - *namep = MACH_PORT_MAKEB(index, entry->ie_bits); - *entryp = entry; - return TRUE; - } - - if (++hindex == size) - hindex = 0; - } - - return FALSE; -} - -/* - * Routine: ipc_hash_local_insert - * Purpose: - * Inserts an entry into the space's reverse hash table. - * Conditions: - * The space must be write-locked. - */ - -void -ipc_hash_local_insert( - ipc_space_t space, - ipc_object_t obj, - mach_port_index_t index, - ipc_entry_t entry) -{ - ipc_entry_t table; - ipc_entry_num_t size; - mach_port_index_t hindex; - - assert(index != 0); - assert(space != IS_NULL); - assert(obj != IO_NULL); - - table = space->is_table; - size = space->is_table_size; - hindex = IH_LOCAL_HASH(obj, size); - - assert(entry == &table[index]); - assert(entry->ie_object == obj); - - /* - * We want to insert at hindex, but there may be collisions. - * If a collision occurs, search for the end of the clump - * and insert there. - */ - - while (table[hindex].ie_index != 0) { - if (++hindex == size) - hindex = 0; - } - - table[hindex].ie_index = index; -} - -/* - * Routine: ipc_hash_local_delete - * Purpose: - * Deletes an entry from the space's reverse hash table. - * Conditions: - * The space must be write-locked. - */ - -void -ipc_hash_local_delete( - ipc_space_t space, - ipc_object_t obj, - mach_port_index_t index, - ipc_entry_t entry) -{ - ipc_entry_t table; - ipc_entry_num_t size; - mach_port_index_t hindex, dindex; - - assert(index != MACH_PORT_NULL); - assert(space != IS_NULL); - assert(obj != IO_NULL); - - table = space->is_table; - size = space->is_table_size; - hindex = IH_LOCAL_HASH(obj, size); - - assert(entry == &table[index]); - assert(entry->ie_object == obj); - - /* - * First check we have the right hindex for this index. - * In case of collision, we have to search farther - * along in this clump. - */ - - while (table[hindex].ie_index != index) { - if (table[hindex].ie_index == 0) - { - static int gak = 0; - if (gak == 0) - { - printf("gak! entry wasn't in hash table!\n"); - gak = 1; - } - return; - } - if (++hindex == size) - hindex = 0; - } - - /* - * Now we want to set table[hindex].ie_index = 0. - * But if we aren't the last index in a clump, - * this might cause problems for lookups of objects - * farther along in the clump that are displaced - * due to collisions. Searches for them would fail - * at hindex instead of succeeding. - * - * So we must check the clump after hindex for objects - * that are so displaced, and move one up to the new hole. - * - * hindex - index of new hole in the clump - * dindex - index we are checking for a displaced object - * - * When we move a displaced object up into the hole, - * it creates a new hole, and we have to repeat the process - * until we get to the end of the clump. - */ - - for (dindex = hindex; index != 0; hindex = dindex) { - for (;;) { - mach_port_index_t tindex; - ipc_object_t tobj; - - if (++dindex == size) - dindex = 0; - assert(dindex != hindex); - - /* are we at the end of the clump? */ - - index = table[dindex].ie_index; - if (index == 0) - break; - - /* is this a displaced object? */ - - tobj = table[index].ie_object; - assert(tobj != IO_NULL); - tindex = IH_LOCAL_HASH(tobj, size); - - if ((dindex < hindex) ? - ((dindex < tindex) && (tindex <= hindex)) : - ((dindex < tindex) || (tindex <= hindex))) - break; - } - - table[hindex].ie_index = index; - } -} - -/* - * Routine: ipc_hash_init - * Purpose: - * Initialize the reverse hash table implementation. - */ - -void -ipc_hash_init(void) -{ - ipc_hash_index_t i; - - /* initialize ipc_hash_global_size */ - - ipc_hash_global_size = IPC_HASH_GLOBAL_SIZE; - - /* make sure it is a power of two */ - - ipc_hash_global_mask = ipc_hash_global_size - 1; - if ((ipc_hash_global_size & ipc_hash_global_mask) != 0) { - natural_t bit; - - /* round up to closest power of two */ - - for (bit = 1;; bit <<= 1) { - ipc_hash_global_mask |= bit; - ipc_hash_global_size = ipc_hash_global_mask + 1; - - if ((ipc_hash_global_size & ipc_hash_global_mask) == 0) - break; - } - } - - /* allocate ipc_hash_global_table */ - - ipc_hash_global_table = (ipc_hash_global_bucket_t) - kalloc((vm_size_t) (ipc_hash_global_size * - sizeof(struct ipc_hash_global_bucket))); - assert(ipc_hash_global_table != IHGB_NULL); - - /* and initialize it */ - - for (i = 0; i < ipc_hash_global_size; i++) { - ipc_hash_global_bucket_t bucket; - - bucket = &ipc_hash_global_table[i]; - ihgb_lock_init(bucket); - bucket->ihgb_head = ITE_NULL; - } -} - -#if MACH_IPC_DEBUG - -/* - * Routine: ipc_hash_info - * Purpose: - * Return information about the global reverse hash table. - * Fills the buffer with as much information as possible - * and returns the desired size of the buffer. - * Conditions: - * Nothing locked. The caller should provide - * possibly-pageable memory. - */ - - -ipc_hash_index_t -ipc_hash_info( - hash_info_bucket_t *info, - mach_msg_type_number_t count) -{ - ipc_hash_index_t i; - - if (ipc_hash_global_size < count) - count = ipc_hash_global_size; - - for (i = 0; i < count; i++) { - ipc_hash_global_bucket_t bucket = &ipc_hash_global_table[i]; - unsigned int bucket_count = 0; - ipc_tree_entry_t entry; - - ihgb_lock(bucket); - for (entry = bucket->ihgb_head; - entry != ITE_NULL; - entry = entry->ite_next) - bucket_count++; - ihgb_unlock(bucket); - - /* don't touch pageable memory while holding locks */ - info[i].hib_count = bucket_count; - } - - return ipc_hash_global_size; -} - -#endif /* MACH_IPC_DEBUG */ diff --git a/ipc/ipc_hash.h b/ipc/ipc_hash.h deleted file mode 100644 index 929ba77d..00000000 --- a/ipc/ipc_hash.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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_hash.h - * Author: Rich Draves - * Date: 1989 - * - * Declarations of entry hash table operations. - */ - -#ifndef _IPC_IPC_HASH_H_ -#define _IPC_IPC_HASH_H_ - -#include <mach/boolean.h> -#include <mach/kern_return.h> - -typedef natural_t ipc_hash_index_t; - -extern void -ipc_hash_init(void); - -#if MACH_IPC_DEBUG - -extern ipc_hash_index_t -ipc_hash_info(hash_info_bucket_t *, mach_msg_type_number_t); - -#endif /* MACH_IPC_DEBUG */ - -extern boolean_t -ipc_hash_lookup(ipc_space_t space, ipc_object_t obj, - mach_port_t *namep, ipc_entry_t *entryp); - -extern void -ipc_hash_insert(ipc_space_t space, ipc_object_t obj, - mach_port_t name, ipc_entry_t entry); - -extern void -ipc_hash_delete(ipc_space_t space, ipc_object_t obj, - mach_port_t name, ipc_entry_t entry); - -/* - * For use by functions that know what they're doing: - * the global primitives, for splay tree entries, - * and the local primitives, for table entries. - */ - -#define IPC_HASH_GLOBAL_SIZE 256 - -extern boolean_t -ipc_hash_global_lookup(ipc_space_t space, ipc_object_t obj, - mach_port_t *namep, ipc_tree_entry_t *entryp); - -extern void -ipc_hash_global_insert(ipc_space_t space, ipc_object_t obj, - mach_port_t name, ipc_tree_entry_t entry); - -extern void -ipc_hash_global_delete(ipc_space_t space, ipc_object_t obj, - mach_port_t name, ipc_tree_entry_t entry); - -extern boolean_t -ipc_hash_local_lookup(ipc_space_t space, ipc_object_t obj, - mach_port_t *namep, ipc_entry_t *entryp); - -extern void -ipc_hash_local_insert(ipc_space_t space, ipc_object_t obj, - mach_port_index_t index, ipc_entry_t entry); - -extern void -ipc_hash_local_delete(ipc_space_t space, ipc_object_t obj, - mach_port_index_t index, ipc_entry_t entry); - -#endif /* _IPC_IPC_HASH_H_ */ diff --git a/ipc/ipc_init.c b/ipc/ipc_init.c index ca7e7912..2c58a6e4 100644 --- a/ipc/ipc_init.c +++ b/ipc/ipc_init.c @@ -47,14 +47,13 @@ #include <ipc/ipc_marequest.h> #include <ipc/ipc_notify.h> #include <ipc/ipc_kmsg.h> -#include <ipc/ipc_hash.h> #include <ipc/ipc_init.h> static struct vm_map ipc_kernel_map_store; vm_map_t ipc_kernel_map = &ipc_kernel_map_store; -vm_size_t ipc_kernel_map_size = 8 * 1024 * 1024; +const vm_size_t ipc_kernel_map_size = 8 * 1024 * 1024; /* * Routine: ipc_bootstrap @@ -76,8 +75,8 @@ ipc_bootstrap(void) kmem_cache_init(&ipc_space_cache, "ipc_space", sizeof(struct ipc_space), 0, NULL, NULL, NULL, 0); - kmem_cache_init(&ipc_tree_entry_cache, "ipc_tree_entry", - sizeof(struct ipc_tree_entry), 0, NULL, NULL, NULL, 0); + kmem_cache_init(&ipc_entry_cache, "ipc_entry", + sizeof(struct ipc_entry), 0, NULL, NULL, NULL, 0); kmem_cache_init(&ipc_object_caches[IOT_PORT], "ipc_port", sizeof(struct ipc_port), 0, NULL, NULL, NULL, 0); @@ -97,7 +96,6 @@ ipc_bootstrap(void) ipc_table_init(); ipc_notify_init(); - ipc_hash_init(); ipc_marequest_init(); } @@ -108,7 +106,7 @@ ipc_bootstrap(void) */ void -ipc_init() +ipc_init(void) { vm_offset_t min, max; diff --git a/ipc/ipc_kmsg.c b/ipc/ipc_kmsg.c index c2689a48..5076809e 100644 --- a/ipc/ipc_kmsg.c +++ b/ipc/ipc_kmsg.c @@ -50,7 +50,6 @@ #include <vm/vm_user.h> #include <ipc/port.h> #include <ipc/ipc_entry.h> -#include <ipc/ipc_hash.h> #include <ipc/ipc_kmsg.h> #include <ipc/ipc_thread.h> #include <ipc/ipc_marequest.h> @@ -66,12 +65,9 @@ #if MACH_KDB #include <ddb/db_output.h> +#include <ipc/ipc_print.h> #endif -extern int copyinmap(); -extern int copyoutmap(); -void ipc_msg_print(); /* forward */ - #define is_misaligned(x) ( ((vm_offset_t)(x)) & (sizeof(vm_offset_t)-1) ) #define ptr_align(x) \ ( ( ((vm_offset_t)(x)) + (sizeof(vm_offset_t)-1) ) & ~(sizeof(vm_offset_t)-1) ) @@ -142,9 +138,7 @@ ipc_kmsg_rmqueue( next->ikm_prev = prev; prev->ikm_next = next; } - /* XXX Temporary debug logic */ - kmsg->ikm_next = IKM_BOGUS; - kmsg->ikm_prev = IKM_BOGUS; + ikm_mark_bogus (kmsg); } /* @@ -221,9 +215,9 @@ ipc_kmsg_destroy( */ void -ipc_kmsg_clean_body(saddr, eaddr) - vm_offset_t saddr; - vm_offset_t eaddr; +ipc_kmsg_clean_body( + vm_offset_t saddr, + vm_offset_t eaddr) { while (saddr < eaddr) { mach_msg_type_long_t *type; @@ -320,8 +314,7 @@ ipc_kmsg_clean_body(saddr, eaddr) */ void -ipc_kmsg_clean(kmsg) - ipc_kmsg_t kmsg; +ipc_kmsg_clean(ipc_kmsg_t kmsg) { ipc_marequest_t marequest; ipc_object_t object; @@ -364,11 +357,11 @@ ipc_kmsg_clean(kmsg) */ void -ipc_kmsg_clean_partial(kmsg, eaddr, dolast, number) - ipc_kmsg_t kmsg; - vm_offset_t eaddr; - boolean_t dolast; - mach_msg_type_number_t number; +ipc_kmsg_clean_partial( + ipc_kmsg_t kmsg, + vm_offset_t eaddr, + boolean_t dolast, + mach_msg_type_number_t number) { ipc_object_t object; mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits; @@ -469,8 +462,7 @@ xxx: type = (mach_msg_type_long_t *) eaddr; */ void -ipc_kmsg_free(kmsg) - ipc_kmsg_t kmsg; +ipc_kmsg_free(ipc_kmsg_t kmsg) { vm_size_t size = kmsg->ikm_size; @@ -503,10 +495,10 @@ ipc_kmsg_free(kmsg) */ mach_msg_return_t -ipc_kmsg_get(msg, size, kmsgp) - mach_msg_header_t *msg; - mach_msg_size_t size; - ipc_kmsg_t *kmsgp; +ipc_kmsg_get( + mach_msg_header_t *msg, + mach_msg_size_t size, + ipc_kmsg_t *kmsgp) { ipc_kmsg_t kmsg; @@ -555,10 +547,10 @@ ipc_kmsg_get(msg, size, kmsgp) */ extern mach_msg_return_t -ipc_kmsg_get_from_kernel(msg, size, kmsgp) - mach_msg_header_t *msg; - mach_msg_size_t size; - ipc_kmsg_t *kmsgp; +ipc_kmsg_get_from_kernel( + mach_msg_header_t *msg, + mach_msg_size_t size, + ipc_kmsg_t *kmsgp) { ipc_kmsg_t kmsg; @@ -592,10 +584,10 @@ ipc_kmsg_get_from_kernel(msg, size, kmsgp) */ mach_msg_return_t -ipc_kmsg_put(msg, kmsg, size) - mach_msg_header_t *msg; - ipc_kmsg_t kmsg; - mach_msg_size_t size; +ipc_kmsg_put( + mach_msg_header_t *msg, + ipc_kmsg_t kmsg, + mach_msg_size_t size) { mach_msg_return_t mr; @@ -677,10 +669,10 @@ ipc_kmsg_put_to_kernel( */ mach_msg_return_t -ipc_kmsg_copyin_header(msg, space, notify) - mach_msg_header_t *msg; - ipc_space_t space; - mach_port_t notify; +ipc_kmsg_copyin_header( + mach_msg_header_t *msg, + ipc_space_t space, + mach_port_t notify) { mach_msg_bits_t mbits = msg->msgh_bits &~ MACH_MSGH_BITS_CIRCULAR; mach_port_t dest_name = msg->msgh_remote_port; @@ -705,24 +697,14 @@ ipc_kmsg_copyin_header(msg, space, notify) if (!space->is_active) goto abort_async; - /* optimized ipc_entry_lookup */ - - { - mach_port_index_t index = MACH_PORT_INDEX(dest_name); - mach_port_gen_t gen = MACH_PORT_GEN(dest_name); - - if (index >= space->is_table_size) + entry = ipc_entry_lookup (space, dest_name); + if (entry == IE_NULL) goto abort_async; - - entry = &space->is_table[index]; bits = entry->ie_bits; - /* check generation number and type bit */ - - if ((bits & (IE_BITS_GEN_MASK|MACH_PORT_TYPE_SEND)) != - (gen | MACH_PORT_TYPE_SEND)) + /* check type bits */ + if (IE_BITS_TYPE (bits) != MACH_PORT_TYPE_SEND) goto abort_async; - } /* optimized ipc_right_copyin */ @@ -757,8 +739,6 @@ ipc_kmsg_copyin_header(msg, space, notify) case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE): { - ipc_entry_num_t size; - ipc_entry_t table; ipc_entry_t entry; ipc_entry_bits_t bits; ipc_port_t dest_port, reply_port; @@ -769,51 +749,28 @@ ipc_kmsg_copyin_header(msg, space, notify) if (!space->is_active) goto abort_request; - size = space->is_table_size; - table = space->is_table; - - /* optimized ipc_entry_lookup of dest_name */ - - { - mach_port_index_t index = MACH_PORT_INDEX(dest_name); - mach_port_gen_t gen = MACH_PORT_GEN(dest_name); - - if (index >= size) + entry = ipc_entry_lookup (space, dest_name); + if (entry == IE_NULL) goto abort_request; - - entry = &table[index]; bits = entry->ie_bits; - /* check generation number and type bit */ - - if ((bits & (IE_BITS_GEN_MASK|MACH_PORT_TYPE_SEND)) != - (gen | MACH_PORT_TYPE_SEND)) + /* check type bits */ + if (IE_BITS_TYPE (bits) != MACH_PORT_TYPE_SEND) goto abort_request; - } assert(IE_BITS_UREFS(bits) > 0); dest_port = (ipc_port_t) entry->ie_object; assert(dest_port != IP_NULL); - /* optimized ipc_entry_lookup of reply_name */ - - { - mach_port_index_t index = MACH_PORT_INDEX(reply_name); - mach_port_gen_t gen = MACH_PORT_GEN(reply_name); - - if (index >= size) + entry = ipc_entry_lookup (space, reply_name); + if (entry == IE_NULL) goto abort_request; - - entry = &table[index]; bits = entry->ie_bits; - /* check generation number and type bit */ - - if ((bits & (IE_BITS_GEN_MASK|MACH_PORT_TYPE_RECEIVE)) != - (gen | MACH_PORT_TYPE_RECEIVE)) + /* check type bits */ + if (IE_BITS_TYPE (bits) != MACH_PORT_TYPE_RECEIVE) goto abort_request; - } reply_port = (ipc_port_t) entry->ie_object; assert(reply_port != IP_NULL); @@ -860,9 +817,6 @@ ipc_kmsg_copyin_header(msg, space, notify) } case MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0): { - mach_port_index_t index; - mach_port_gen_t gen; - ipc_entry_t table; ipc_entry_t entry; ipc_entry_bits_t bits; ipc_port_t dest_port; @@ -876,24 +830,13 @@ ipc_kmsg_copyin_header(msg, space, notify) if (!space->is_active) goto abort_reply; - /* optimized ipc_entry_lookup */ - - table = space->is_table; - - index = MACH_PORT_INDEX(dest_name); - gen = MACH_PORT_GEN(dest_name); - - if (index >= space->is_table_size) + entry = ipc_entry_lookup (space, dest_name); + if (entry == IE_NULL) goto abort_reply; - - entry = &table[index]; bits = entry->ie_bits; - /* check generation number, collision bit, and type bit */ - - if ((bits & (IE_BITS_GEN_MASK|IE_BITS_COLLISION| - MACH_PORT_TYPE_SEND_ONCE)) != - (gen | MACH_PORT_TYPE_SEND_ONCE)) + /* check and type bits */ + if (IE_BITS_TYPE (bits) != MACH_PORT_TYPE_SEND_ONCE) goto abort_reply; /* optimized ipc_right_copyin */ @@ -917,12 +860,8 @@ ipc_kmsg_copyin_header(msg, space, notify) assert(dest_port->ip_sorights > 0); ip_unlock(dest_port); - /* optimized ipc_entry_dealloc */ - - entry->ie_next = table->ie_next; - table->ie_next = index; - entry->ie_bits = gen; entry->ie_object = IO_NULL; + ipc_entry_dealloc (space, dest_name, entry); is_write_unlock(space); msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | @@ -1342,10 +1281,10 @@ ipc_kmsg_copyin_header(msg, space, notify) } mach_msg_return_t -ipc_kmsg_copyin_body(kmsg, space, map) - ipc_kmsg_t kmsg; - ipc_space_t space; - vm_map_t map; +ipc_kmsg_copyin_body( + ipc_kmsg_t kmsg, + ipc_space_t space, + vm_map_t map) { ipc_object_t dest; vm_offset_t saddr, eaddr; @@ -1562,11 +1501,11 @@ ipc_kmsg_copyin_body(kmsg, space, map) */ mach_msg_return_t -ipc_kmsg_copyin(kmsg, space, map, notify) - ipc_kmsg_t kmsg; - ipc_space_t space; - vm_map_t map; - mach_port_t notify; +ipc_kmsg_copyin( + ipc_kmsg_t kmsg, + ipc_space_t space, + vm_map_t map, + mach_port_t notify) { mach_msg_return_t mr; @@ -1597,8 +1536,7 @@ ipc_kmsg_copyin(kmsg, space, map, notify) */ void -ipc_kmsg_copyin_from_kernel( - ipc_kmsg_t kmsg) +ipc_kmsg_copyin_from_kernel(ipc_kmsg_t kmsg) { mach_msg_bits_t bits = kmsg->ikm_header.msgh_bits; mach_msg_type_name_t rname = MACH_MSGH_BITS_REMOTE(bits); @@ -1757,10 +1695,10 @@ ipc_kmsg_copyin_from_kernel( */ mach_msg_return_t -ipc_kmsg_copyout_header(msg, space, notify) - mach_msg_header_t *msg; - ipc_space_t space; - mach_port_t notify; +ipc_kmsg_copyout_header( + mach_msg_header_t *msg, + ipc_space_t space, + mach_port_t notify) { mach_msg_bits_t mbits = msg->msgh_bits; ipc_port_t dest = (ipc_port_t) msg->msgh_remote_port; @@ -1774,6 +1712,7 @@ ipc_kmsg_copyout_header(msg, space, notify) case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0): { mach_port_t dest_name; ipc_port_t nsrequest; + unsigned long payload; /* receiving an asynchronous message */ @@ -1792,6 +1731,7 @@ ipc_kmsg_copyout_header(msg, space, notify) dest_name = dest->ip_receiver_name; else dest_name = MACH_PORT_NULL; + payload = dest->ip_protected_payload; if ((--dest->ip_srights == 0) && ((nsrequest = dest->ip_nsrequest) != IP_NULL)) { @@ -1805,21 +1745,27 @@ ipc_kmsg_copyout_header(msg, space, notify) } else ip_unlock(dest); - msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | - MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND)); - msg->msgh_local_port = dest_name; + if (! ipc_port_flag_protected_payload(dest)) { + msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | + MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND)); + msg->msgh_local_port = dest_name; + } else { + msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | + MACH_MSGH_BITS( + 0, MACH_MSG_TYPE_PROTECTED_PAYLOAD)); + msg->msgh_protected_payload = payload; + } msg->msgh_remote_port = MACH_PORT_NULL; return MACH_MSG_SUCCESS; } case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, MACH_MSG_TYPE_PORT_SEND_ONCE): { - ipc_entry_t table; - mach_port_index_t index; ipc_entry_t entry; ipc_port_t reply = (ipc_port_t) msg->msgh_local_port; mach_port_t dest_name, reply_name; ipc_port_t nsrequest; + unsigned long payload; /* receiving a request message */ @@ -1827,8 +1773,7 @@ ipc_kmsg_copyout_header(msg, space, notify) break; is_write_lock(space); - if (!space->is_active || - ((index = (table = space->is_table)->ie_next) == 0)) { + if (!space->is_active || space->is_free_list == NULL) { is_write_unlock(space); break; } @@ -1858,11 +1803,14 @@ ipc_kmsg_copyout_header(msg, space, notify) assert(reply->ip_sorights > 0); ip_unlock(reply); - /* optimized ipc_entry_get */ - - entry = &table[index]; - table->ie_next = entry->ie_next; - entry->ie_request = 0; + kern_return_t kr; + kr = ipc_entry_get (space, &reply_name, &entry); + if (kr) { + ip_unlock(reply); + ip_unlock(dest); + is_write_unlock(space); + break; + } { mach_port_gen_t gen; @@ -1870,8 +1818,6 @@ ipc_kmsg_copyout_header(msg, space, notify) assert((entry->ie_bits &~ IE_BITS_GEN_MASK) == 0); gen = entry->ie_bits + IE_BITS_GEN_ONE; - reply_name = MACH_PORT_MAKE(index, gen); - /* optimized ipc_right_copyout */ entry->ie_bits = gen | (MACH_PORT_TYPE_SEND_ONCE | 1); @@ -1890,6 +1836,7 @@ ipc_kmsg_copyout_header(msg, space, notify) dest_name = dest->ip_receiver_name; else dest_name = MACH_PORT_NULL; + payload = dest->ip_protected_payload; if ((--dest->ip_srights == 0) && ((nsrequest = dest->ip_nsrequest) != IP_NULL)) { @@ -1903,16 +1850,24 @@ ipc_kmsg_copyout_header(msg, space, notify) } else ip_unlock(dest); - msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | - MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, - MACH_MSG_TYPE_PORT_SEND)); - msg->msgh_local_port = dest_name; + if (! ipc_port_flag_protected_payload(dest)) { + msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | + MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, + MACH_MSG_TYPE_PORT_SEND)); + msg->msgh_local_port = dest_name; + } else { + msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | + MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, + MACH_MSG_TYPE_PROTECTED_PAYLOAD)); + msg->msgh_protected_payload = payload; + } msg->msgh_remote_port = reply_name; return MACH_MSG_SUCCESS; } case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0): { mach_port_t dest_name; + unsigned long payload; /* receiving a reply message */ @@ -1926,6 +1881,8 @@ ipc_kmsg_copyout_header(msg, space, notify) assert(dest->ip_sorights > 0); + payload = dest->ip_protected_payload; + if (dest->ip_receiver == space) { ip_release(dest); dest->ip_sorights--; @@ -1938,9 +1895,17 @@ ipc_kmsg_copyout_header(msg, space, notify) dest_name = MACH_PORT_NULL; } - msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | - MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND_ONCE)); - msg->msgh_local_port = dest_name; + if (! ipc_port_flag_protected_payload(dest)) { + msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | + MACH_MSGH_BITS(0, + MACH_MSG_TYPE_PORT_SEND_ONCE)); + msg->msgh_local_port = dest_name; + } else { + msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | + MACH_MSGH_BITS(0, + MACH_MSG_TYPE_PROTECTED_PAYLOAD)); + msg->msgh_protected_payload = payload; + } msg->msgh_remote_port = MACH_PORT_NULL; return MACH_MSG_SUCCESS; } @@ -1956,6 +1921,7 @@ ipc_kmsg_copyout_header(msg, space, notify) mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits); ipc_port_t reply = (ipc_port_t) msg->msgh_local_port; mach_port_t dest_name, reply_name; + unsigned long payload; if (IP_VALID(reply)) { ipc_port_t notify_port; @@ -2036,28 +2002,20 @@ ipc_kmsg_copyout_header(msg, space, notify) goto copyout_dest; } - kr = ipc_entry_get(space, &reply_name, &entry); + kr = ipc_entry_alloc(space, &reply_name, &entry); if (kr != KERN_SUCCESS) { ip_unlock(reply); if (notify_port != IP_NULL) ipc_port_release_sonce(notify_port); - /* space is locked */ - kr = ipc_entry_grow_table(space); - if (kr != KERN_SUCCESS) { - /* space is unlocked */ - - if (kr == KERN_RESOURCE_SHORTAGE) - return (MACH_RCV_HEADER_ERROR| - MACH_MSG_IPC_KERNEL); - else - return (MACH_RCV_HEADER_ERROR| - MACH_MSG_IPC_SPACE); - } - /* space is locked again; start over */ - - continue; + is_write_unlock(space); + if (kr == KERN_RESOURCE_SHORTAGE) + return (MACH_RCV_HEADER_ERROR| + MACH_MSG_IPC_KERNEL); + else + return (MACH_RCV_HEADER_ERROR| + MACH_MSG_IPC_SPACE); } assert(IE_BITS_TYPE(entry->ie_bits) @@ -2202,6 +2160,7 @@ ipc_kmsg_copyout_header(msg, space, notify) */ copyout_dest: + payload = dest->ip_protected_payload; if (ip_active(dest)) { ipc_object_copyout_dest(space, (ipc_object_t) dest, @@ -2230,9 +2189,17 @@ ipc_kmsg_copyout_header(msg, space, notify) if (IP_VALID(reply)) ipc_port_release(reply); - msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | - MACH_MSGH_BITS(reply_type, dest_type)); - msg->msgh_local_port = dest_name; + if (! ipc_port_flag_protected_payload(dest)) { + msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | + MACH_MSGH_BITS(reply_type, dest_type)); + msg->msgh_local_port = dest_name; + } else { + msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | + MACH_MSGH_BITS(reply_type, + MACH_MSG_TYPE_PROTECTED_PAYLOAD)); + msg->msgh_protected_payload = payload; + } + msg->msgh_remote_port = reply_name; } @@ -2257,11 +2224,11 @@ ipc_kmsg_copyout_header(msg, space, notify) */ mach_msg_return_t -ipc_kmsg_copyout_object(space, object, msgt_name, namep) - ipc_space_t space; - ipc_object_t object; - mach_msg_type_name_t msgt_name; - mach_port_t *namep; +ipc_kmsg_copyout_object( + ipc_space_t space, + ipc_object_t object, + mach_msg_type_name_t msgt_name, + mach_port_t *namep) { if (!IO_VALID(object)) { *namep = (mach_port_t) object; @@ -2279,7 +2246,7 @@ ipc_kmsg_copyout_object(space, object, msgt_name, namep) goto slow_copyout; { - register ipc_port_t port = (ipc_port_t) object; + ipc_port_t port = (ipc_port_t) object; ipc_entry_t entry; is_write_lock(space); @@ -2290,12 +2257,13 @@ ipc_kmsg_copyout_object(space, object, msgt_name, namep) ip_lock(port); if (!ip_active(port) || - !ipc_hash_local_lookup(space, (ipc_object_t) port, - namep, &entry)) { + (entry = ipc_reverse_lookup(space, + (ipc_object_t) port)) == NULL) { ip_unlock(port); is_write_unlock(space); goto slow_copyout; } + *namep = entry->ie_name; /* * Copyout the send right, incrementing urefs @@ -2312,7 +2280,7 @@ ipc_kmsg_copyout_object(space, object, msgt_name, namep) assert(IE_BITS_UREFS(entry->ie_bits) < MACH_PORT_UREFS_MAX); { - register ipc_entry_bits_t bits = entry->ie_bits + 1; + ipc_entry_bits_t bits = entry->ie_bits + 1; if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) entry->ie_bits = bits; @@ -2367,10 +2335,11 @@ ipc_kmsg_copyout_object(space, object, msgt_name, namep) */ mach_msg_return_t -ipc_kmsg_copyout_body(saddr, eaddr, space, map) - vm_offset_t saddr, eaddr; - ipc_space_t space; - vm_map_t map; +ipc_kmsg_copyout_body( + vm_offset_t saddr, + vm_offset_t eaddr, + ipc_space_t space, + vm_map_t map) { mach_msg_return_t mr = MACH_MSG_SUCCESS; kern_return_t kr; @@ -2519,11 +2488,11 @@ ipc_kmsg_copyout_body(saddr, eaddr, space, map) */ mach_msg_return_t -ipc_kmsg_copyout(kmsg, space, map, notify) - ipc_kmsg_t kmsg; - ipc_space_t space; - vm_map_t map; - mach_port_t notify; +ipc_kmsg_copyout( + ipc_kmsg_t kmsg, + ipc_space_t space, + vm_map_t map, + mach_port_t notify) { mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits; mach_msg_return_t mr; @@ -2613,9 +2582,9 @@ ipc_kmsg_copyout_pseudo( */ void -ipc_kmsg_copyout_dest(kmsg, space) - ipc_kmsg_t kmsg; - ipc_space_t space; +ipc_kmsg_copyout_dest( + ipc_kmsg_t kmsg, + ipc_space_t space) { mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits; ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port; @@ -2661,9 +2630,9 @@ ipc_kmsg_copyout_dest(kmsg, space) #if MACH_KDB char * -ipc_type_name(type_name, received) - int type_name; - boolean_t received; +ipc_type_name( + int type_name, + boolean_t received) { switch (type_name) { case MACH_MSG_TYPE_BOOLEAN: @@ -2744,8 +2713,7 @@ ipc_print_type_name( * ipc_kmsg_print [ debug ] */ void -ipc_kmsg_print(kmsg) - ipc_kmsg_t kmsg; +ipc_kmsg_print(ipc_kmsg_t kmsg) { db_printf("kmsg=0x%x\n", kmsg); db_printf("ikm_next=0x%x,prev=0x%x,size=%d,marequest=0x%x", @@ -2761,8 +2729,7 @@ ipc_kmsg_print(kmsg) * ipc_msg_print [ debug ] */ void -ipc_msg_print(msgh) - mach_msg_header_t *msgh; +ipc_msg_print(mach_msg_header_t *msgh) { vm_offset_t saddr, eaddr; diff --git a/ipc/ipc_kmsg.h b/ipc/ipc_kmsg.h index 8867310d..393c0392 100644 --- a/ipc/ipc_kmsg.h +++ b/ipc/ipc_kmsg.h @@ -38,7 +38,7 @@ #include <mach/message.h> #include <kern/assert.h> #include <kern/cpu_number.h> -#include <kern/macro_help.h> +#include <kern/macros.h> #include <kern/kalloc.h> #include <ipc/ipc_marequest.h> #include <ipc/ipc_object.h> @@ -72,11 +72,24 @@ typedef struct ipc_kmsg { #define ikm_plus_overhead(size) ((vm_size_t)((size) + IKM_OVERHEAD)) #define ikm_less_overhead(size) ((mach_msg_size_t)((size) - IKM_OVERHEAD)) +#if MACH_IPC_TEST /* - * XXX For debugging. + * For debugging. */ #define IKM_BOGUS ((ipc_kmsg_t) 0xffffff10) +#define ikm_mark_bogus(kmsg) \ +MACRO_BEGIN \ + (kmsg)->ikm_next = IKM_BOGUS; \ + (kmsg)->ikm_prev = IKM_BOGUS; \ +MACRO_END + +#else /* MACH_IPC_TEST */ + +#define ikm_mark_bogus(kmsg) ; + +#endif /* MACH_IPC_TEST */ + /* * We keep a per-processor cache of kernel message buffers. * The cache saves the overhead/locking of using kalloc/kfree. @@ -92,9 +105,12 @@ extern ipc_kmsg_t ipc_kmsg_cache[NCPUS]; /* * The size of the kernel message buffers that will be cached. * IKM_SAVED_KMSG_SIZE includes overhead; IKM_SAVED_MSG_SIZE doesn't. + * + * We use the page size for IKM_SAVED_KMSG_SIZE to make sure the + * page is pinned to a single processor. */ -#define IKM_SAVED_KMSG_SIZE ((vm_size_t) 256) +#define IKM_SAVED_KMSG_SIZE PAGE_SIZE #define IKM_SAVED_MSG_SIZE ikm_less_overhead(IKM_SAVED_KMSG_SIZE) #define ikm_alloc(size) \ @@ -140,8 +156,7 @@ MACRO_BEGIN \ MACRO_END /* - * struct ipc_kmsg_queue is defined in kern/thread.h instead of here, - * so that kern/thread.h doesn't have to include ipc/ipc_kmsg.h. + * struct ipc_kmsg_queue is defined in ipc/ipc_kmsg_queue.h */ #include <ipc/ipc_kmsg_queue.h> @@ -196,9 +211,7 @@ MACRO_BEGIN \ _next->ikm_prev = _prev; \ _prev->ikm_next = _next; \ } \ - /* XXX Debug paranoia */ \ - kmsg->ikm_next = IKM_BOGUS; \ - kmsg->ikm_prev = IKM_BOGUS; \ + ikm_mark_bogus (kmsg); \ MACRO_END #define ipc_kmsg_enqueue_macro(queue, kmsg) \ diff --git a/ipc/ipc_kmsg_queue.h b/ipc/ipc_kmsg_queue.h index 51ccbe24..b4b3df1d 100644 --- a/ipc/ipc_kmsg_queue.h +++ b/ipc/ipc_kmsg_queue.h @@ -27,5 +27,5 @@ #define _IPC_KMSG_QUEUE_H_ struct ipc_kmsg_queue { struct ipc_kmsg *ikmq_base; }; -#endif +#endif /* _IPC_KMSG_QUEUE_H_ */ diff --git a/ipc/ipc_machdep.h b/ipc/ipc_machdep.h index e864c4b0..c205ba45 100755 --- a/ipc/ipc_machdep.h +++ b/ipc/ipc_machdep.h @@ -24,6 +24,9 @@ * the rights to redistribute these changes. */ +#ifndef _IPC_IPC_MACHDEP_H_ +#define _IPC_IPC_MACHDEP_H_ + /* * At times, we need to know the size of a port in bits */ @@ -38,3 +41,4 @@ #define PORT_T_SIZE_IN_BITS 32 #endif +#endif /* _IPC_IPC_MACHDEP_H_ */ diff --git a/ipc/ipc_marequest.c b/ipc/ipc_marequest.c index 06c53eb4..ded1711d 100644 --- a/ipc/ipc_marequest.c +++ b/ipc/ipc_marequest.c @@ -160,11 +160,11 @@ ipc_marequest_init(void) */ mach_msg_return_t -ipc_marequest_create(space, port, notify, marequestp) - ipc_space_t space; - ipc_port_t port; - mach_port_t notify; - ipc_marequest_t *marequestp; +ipc_marequest_create( + ipc_space_t space, + ipc_port_t port, + mach_port_t notify, + ipc_marequest_t *marequestp) { mach_port_t name; ipc_entry_t entry; @@ -256,9 +256,9 @@ ipc_marequest_create(space, port, notify, marequestp) */ void -ipc_marequest_cancel(space, name) - ipc_space_t space; - mach_port_t name; +ipc_marequest_cancel( + ipc_space_t space, + mach_port_t name) { ipc_marequest_bucket_t bucket; ipc_marequest_t marequest, *last; @@ -292,9 +292,10 @@ ipc_marequest_cancel(space, name) */ void -ipc_marequest_rename(space, old, new) - ipc_space_t space; - mach_port_t old, new; +ipc_marequest_rename( + ipc_space_t space, + mach_port_t old, + mach_port_t new) { ipc_marequest_bucket_t bucket; ipc_marequest_t marequest, *last; @@ -336,8 +337,7 @@ ipc_marequest_rename(space, old, new) */ void -ipc_marequest_destroy(marequest) - ipc_marequest_t marequest; +ipc_marequest_destroy(ipc_marequest_t marequest) { ipc_space_t space = marequest->imar_space; mach_port_t name; @@ -404,10 +404,10 @@ ipc_marequest_destroy(marequest) */ unsigned int -ipc_marequest_info(maxp, info, count) - unsigned int *maxp; - hash_info_bucket_t *info; - unsigned int count; +ipc_marequest_info( + unsigned int *maxp, + hash_info_bucket_t *info, + unsigned int count) { ipc_marequest_index_t i; diff --git a/ipc/ipc_mqueue.c b/ipc/ipc_mqueue.c index 80a34d3a..9138aec4 100644 --- a/ipc/ipc_mqueue.c +++ b/ipc/ipc_mqueue.c @@ -79,9 +79,9 @@ ipc_mqueue_init( void ipc_mqueue_move( - ipc_mqueue_t dest, - ipc_mqueue_t source, - ipc_port_t port) + ipc_mqueue_t dest, + ipc_mqueue_t source, + const ipc_port_t port) { ipc_kmsg_queue_t oldq, newq; ipc_thread_queue_t blockedq; @@ -171,10 +171,10 @@ ipc_mqueue_changed( */ mach_msg_return_t -ipc_mqueue_send(kmsg, option, time_out) - ipc_kmsg_t kmsg; - mach_msg_option_t option; - mach_msg_timeout_t time_out; +ipc_mqueue_send( + ipc_kmsg_t kmsg, + mach_msg_option_t option, + mach_msg_timeout_t time_out) { ipc_port_t port; diff --git a/ipc/ipc_mqueue.h b/ipc/ipc_mqueue.h index ef0f9425..2af5e02e 100644 --- a/ipc/ipc_mqueue.h +++ b/ipc/ipc_mqueue.h @@ -37,7 +37,8 @@ #include <mach/message.h> #include <kern/assert.h> #include <kern/lock.h> -#include <kern/macro_help.h> +#include <kern/macros.h> +#include <ipc/ipc_kmsg_queue.h> #include <ipc/ipc_kmsg.h> #include <ipc/ipc_thread.h> diff --git a/ipc/ipc_notify.c b/ipc/ipc_notify.c index 25fa421b..df5f68bc 100644 --- a/ipc/ipc_notify.c +++ b/ipc/ipc_notify.c @@ -59,8 +59,7 @@ mach_dead_name_notification_t ipc_notify_dead_name_template; */ void -ipc_notify_init_port_deleted(n) - mach_port_deleted_notification_t *n; +ipc_notify_init_port_deleted(mach_port_deleted_notification_t *n) { mach_msg_header_t *m = &n->not_header; mach_msg_type_t *t = &n->not_type; @@ -90,8 +89,7 @@ ipc_notify_init_port_deleted(n) */ void -ipc_notify_init_msg_accepted(n) - mach_msg_accepted_notification_t *n; +ipc_notify_init_msg_accepted(mach_msg_accepted_notification_t *n) { mach_msg_header_t *m = &n->not_header; mach_msg_type_t *t = &n->not_type; @@ -121,8 +119,7 @@ ipc_notify_init_msg_accepted(n) */ void -ipc_notify_init_port_destroyed( - mach_port_destroyed_notification_t *n) +ipc_notify_init_port_destroyed(mach_port_destroyed_notification_t *n) { mach_msg_header_t *m = &n->not_header; mach_msg_type_t *t = &n->not_type; @@ -255,9 +252,9 @@ ipc_notify_init(void) */ void -ipc_notify_port_deleted(port, name) - ipc_port_t port; - mach_port_t name; +ipc_notify_port_deleted( + ipc_port_t port, + mach_port_t name) { ipc_kmsg_t kmsg; mach_port_deleted_notification_t *n; @@ -289,9 +286,9 @@ ipc_notify_port_deleted(port, name) */ void -ipc_notify_msg_accepted(port, name) - ipc_port_t port; - mach_port_t name; +ipc_notify_msg_accepted( + ipc_port_t port, + mach_port_t name) { ipc_kmsg_t kmsg; mach_msg_accepted_notification_t *n; @@ -326,9 +323,9 @@ ipc_notify_msg_accepted(port, name) */ void -ipc_notify_port_destroyed(port, right) - ipc_port_t port; - ipc_port_t right; +ipc_notify_port_destroyed( + ipc_port_t port, + ipc_port_t right) { ipc_kmsg_t kmsg; mach_port_destroyed_notification_t *n; @@ -362,9 +359,9 @@ ipc_notify_port_destroyed(port, right) */ void -ipc_notify_no_senders(port, mscount) - ipc_port_t port; - mach_port_mscount_t mscount; +ipc_notify_no_senders( + ipc_port_t port, + mach_port_mscount_t mscount) { ipc_kmsg_t kmsg; mach_no_senders_notification_t *n; @@ -396,8 +393,7 @@ ipc_notify_no_senders(port, mscount) */ void -ipc_notify_send_once(port) - ipc_port_t port; +ipc_notify_send_once(ipc_port_t port) { ipc_kmsg_t kmsg; mach_send_once_notification_t *n; @@ -428,9 +424,9 @@ ipc_notify_send_once(port) */ void -ipc_notify_dead_name(port, name) - ipc_port_t port; - mach_port_t name; +ipc_notify_dead_name( + ipc_port_t port, + mach_port_t name) { ipc_kmsg_t kmsg; mach_dead_name_notification_t *n; diff --git a/ipc/ipc_object.c b/ipc/ipc_object.c index b8cae8f5..320fbcb2 100644 --- a/ipc/ipc_object.c +++ b/ipc/ipc_object.c @@ -41,7 +41,6 @@ #include <ipc/ipc_space.h> #include <ipc/ipc_entry.h> #include <ipc/ipc_object.h> -#include <ipc/ipc_hash.h> #include <ipc/ipc_right.h> #include <ipc/ipc_notify.h> #include <ipc/ipc_pset.h> @@ -156,11 +155,12 @@ ipc_object_alloc_dead( ipc_entry_t entry; kern_return_t kr; - + is_write_lock(space); kr = ipc_entry_alloc(space, namep, &entry); - if (kr != KERN_SUCCESS) + if (kr != KERN_SUCCESS) { + is_write_unlock(space); return kr; - /* space is write-locked */ + } /* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */ @@ -192,11 +192,12 @@ ipc_object_alloc_dead_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) + if (kr != KERN_SUCCESS) { + is_write_unlock(space); return kr; - /* space is write-locked */ + } if (ipc_right_inuse(space, name, entry)) return KERN_NAME_EXISTS; @@ -255,12 +256,13 @@ ipc_object_alloc( 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; } - /* space is write-locked */ entry->ie_bits |= type | urefs; entry->ie_object = object; @@ -322,12 +324,13 @@ ipc_object_alloc_name( 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; } - /* space is write-locked */ if (ipc_right_inuse(space, name, entry)) { io_free(otype, object); @@ -481,6 +484,7 @@ ipc_object_copyin_from_kernel( port->ip_receiver_name = MACH_PORT_NULL; port->ip_destination = IP_NULL; + ipc_port_flag_protected_payload_clear(port); ip_unlock(port); break; } @@ -629,15 +633,10 @@ ipc_object_copyout( break; } - kr = ipc_entry_get(space, &name, &entry); + kr = ipc_entry_alloc(space, &name, &entry); if (kr != KERN_SUCCESS) { - /* unlocks/locks space, so must start again */ - - kr = ipc_entry_grow_table(space); - if (kr != KERN_SUCCESS) - return kr; /* space is unlocked */ - - continue; + is_write_unlock(space); + return kr; } assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE); @@ -690,15 +689,10 @@ ipc_object_copyout_multiname(space, object, namep) return KERN_INVALID_TASK; } - kr = ipc_entry_get(space, &name, &entry); + kr = ipc_entry_alloc(space, &name, &entry); if (kr != KERN_SUCCESS) { - /* unlocks/locks space, so must start again */ - - kr = ipc_entry_grow_table(space); - if (kr != KERN_SUCCESS) - return kr; /* space is unlocked */ - - continue; + is_write_unlock(space); + return kr; /* space is unlocked */ } assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE); @@ -763,10 +757,12 @@ ipc_object_copyout_name( 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) + if (kr != KERN_SUCCESS) { + is_write_unlock(space); return kr; - /* space is write-locked and active */ + } if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) && ipc_right_reverse(space, object, &oname, &oentry)) { @@ -940,10 +936,12 @@ ipc_object_rename( 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) + if (kr != KERN_SUCCESS) { + is_write_unlock(space); return kr; - /* space is write-locked and active */ + } if (ipc_right_inuse(space, nname, nentry)) { /* space is unlocked */ @@ -1007,7 +1005,7 @@ char *ikot_print_array[IKOT_MAX_TYPE] = { void ipc_object_print( - ipc_object_t object) + const ipc_object_t object) { int kotype; diff --git a/ipc/ipc_object.h b/ipc/ipc_object.h index adf5bca4..be5bea71 100644 --- a/ipc/ipc_object.h +++ b/ipc/ipc_object.h @@ -38,7 +38,7 @@ #include <mach/message.h> #include <ipc/ipc_types.h> #include <kern/lock.h> -#include <kern/macro_help.h> +#include <kern/macros.h> #include <kern/slab.h> typedef unsigned int ipc_object_refs_t; @@ -57,7 +57,9 @@ typedef struct ipc_object { #define IO_VALID(io) (((io) != IO_NULL) && ((io) != IO_DEAD)) #define IO_BITS_KOTYPE 0x0000ffff /* used by the object */ -#define IO_BITS_OTYPE 0x7fff0000 /* determines a cache */ +#define IO_BITS_OTYPE 0x3fff0000 /* determines a cache */ +/* The following masks are used to store attributes of ipc ports. */ +#define IO_BITS_PROTECTED_PAYLOAD 0x40000000 /* pp set? */ #define IO_BITS_ACTIVE 0x80000000U /* is object alive? */ #define io_active(io) ((int)(io)->io_bits < 0) /* hack */ diff --git a/ipc/ipc_port.c b/ipc/ipc_port.c index 8e41c3ca..86a4ee2a 100644 --- a/ipc/ipc_port.c +++ b/ipc/ipc_port.c @@ -53,6 +53,7 @@ #if MACH_KDB #include <ddb/db_output.h> +#include <ipc/ipc_print.h> #endif /* MACH_KDB */ @@ -93,11 +94,11 @@ ipc_port_timestamp(void) */ kern_return_t -ipc_port_dnrequest(port, name, soright, indexp) - ipc_port_t port; - mach_port_t name; - ipc_port_t soright; - ipc_port_request_index_t *indexp; +ipc_port_dnrequest( + ipc_port_t port, + mach_port_t name, + ipc_port_t soright, + ipc_port_request_index_t *indexp) { ipc_port_request_t ipr, table; ipc_port_request_index_t index; @@ -141,8 +142,7 @@ ipc_port_dnrequest(port, name, soright, indexp) */ kern_return_t -ipc_port_dngrow(port) - ipc_port_t port; +ipc_port_dngrow(ipc_port_t port) { ipc_table_size_t its; ipc_port_request_t otable, ntable; @@ -274,9 +274,9 @@ ipc_port_dncancel( void ipc_port_pdrequest( - ipc_port_t port, - ipc_port_t notify, - ipc_port_t *previousp) + ipc_port_t port, + const ipc_port_t notify, + ipc_port_t *previousp) { ipc_port_t previous; @@ -381,8 +381,7 @@ ipc_port_set_qlimit( */ ipc_mqueue_t -ipc_port_lock_mqueue(port) - ipc_port_t port; +ipc_port_lock_mqueue(ipc_port_t port) { if (port->ip_pset != IPS_NULL) { ipc_pset_t pset = port->ip_pset; @@ -412,9 +411,9 @@ ipc_port_lock_mqueue(port) */ void -ipc_port_set_seqno(port, seqno) - ipc_port_t port; - mach_port_seqno_t seqno; +ipc_port_set_seqno( + ipc_port_t port, + mach_port_seqno_t seqno) { ipc_mqueue_t mqueue; @@ -424,6 +423,44 @@ ipc_port_set_seqno(port, seqno) } /* + * Routine: ipc_port_set_protected_payload + * Purpose: + * Changes a port's protected payload. + * Conditions: + * The port is locked and active. + */ + +void +ipc_port_set_protected_payload(ipc_port_t port, unsigned long payload) +{ + ipc_mqueue_t mqueue; + + mqueue = ipc_port_lock_mqueue(port); + port->ip_protected_payload = payload; + ipc_port_flag_protected_payload_set(port); + imq_unlock(mqueue); +} + +/* + * Routine: ipc_port_clear_protected_payload + * Purpose: + * Clear a port's protected payload. + * Conditions: + * The port is locked and active. + */ + +void +ipc_port_clear_protected_payload(ipc_port_t port) +{ + ipc_mqueue_t mqueue; + + mqueue = ipc_port_lock_mqueue(port); + ipc_port_flag_protected_payload_clear(port); + imq_unlock(mqueue); +} + + +/* * Routine: ipc_port_clear_receiver * Purpose: * Prepares a receive right for transmission/destruction. @@ -492,6 +529,8 @@ ipc_port_init( port->ip_seqno = 0; port->ip_msgcount = 0; port->ip_qlimit = MACH_PORT_QLIMIT_DEFAULT; + ipc_port_flag_protected_payload_clear(port); + port->ip_protected_payload = 0; ipc_mqueue_init(&port->ip_messages); ipc_thread_queue_init(&port->ip_blocked); @@ -614,6 +653,7 @@ ipc_port_destroy( /* make port be in limbo */ port->ip_receiver_name = MACH_PORT_NULL; port->ip_destination = IP_NULL; + ipc_port_flag_protected_payload_clear(port); ip_unlock(port); if (!ipc_port_check_circularity(port, pdrequest)) { @@ -1134,16 +1174,15 @@ ipc_port_release_receive( */ ipc_port_t -ipc_port_alloc_special(space) - ipc_space_t space; +ipc_port_alloc_special(ipc_space_t space) { ipc_port_t port; - port = (ipc_port_t) io_alloc(IOT_PORT); + port = ip_alloc(); if (port == IP_NULL) return IP_NULL; - io_lock_init(&port->ip_object); + ip_lock_init(port); port->ip_references = 1; port->ip_object.io_bits = io_makebits(TRUE, IOT_PORT, 0); @@ -1211,12 +1250,17 @@ ipc_port_dealloc_special( void ipc_port_print(port) - ipc_port_t port; + const ipc_port_t port; { printf("port 0x%x\n", port); indent += 2; + iprintf("flags "); + printf("has_protected_payload=%d", + ipc_port_flag_protected_payload(port)); + printf("\n"); + ipc_object_print(&port->ip_object); iprintf("receiver=0x%x", port->ip_receiver); printf(", receiver_name=0x%x\n", port->ip_receiver_name); @@ -1239,7 +1283,9 @@ ipc_port_print(port) printf(", sndrs=0x%x", port->ip_blocked.ithq_base); printf(", kobj=0x%x\n", port->ip_kobject); - indent -=2; + iprintf("protected_payload=%p\n", (void *) port->ip_protected_payload); + + indent -= 2; } #endif /* MACH_KDB */ diff --git a/ipc/ipc_port.h b/ipc/ipc_port.h index 70ec4946..ade69679 100644 --- a/ipc/ipc_port.h +++ b/ipc/ipc_port.h @@ -43,11 +43,12 @@ #include <mach/kern_return.h> #include <mach/port.h> #include <kern/lock.h> -#include <kern/macro_help.h> +#include <kern/macros.h> #include <kern/ipc_kobject.h> #include <ipc/ipc_mqueue.h> #include <ipc/ipc_table.h> #include <ipc/ipc_thread.h> +#include <ipc/ipc_object.h> #include "ipc_target.h" #include <mach/rpc.h> @@ -96,6 +97,7 @@ struct ipc_port { mach_port_msgcount_t ip_msgcount; mach_port_msgcount_t ip_qlimit; struct ipc_thread_queue ip_blocked; + unsigned long ip_protected_payload; }; #define ip_object ip_target.ipt_object @@ -262,6 +264,12 @@ extern void ipc_port_set_seqno(ipc_port_t, mach_port_seqno_t); extern void +ipc_port_set_protected_payload(ipc_port_t, unsigned long); + +extern void +ipc_port_clear_protected_payload(ipc_port_t); + +extern void ipc_port_clear_receiver(ipc_port_t); extern void @@ -325,7 +333,23 @@ ipc_port_dealloc_special(ipc_port_t, ipc_space_t); #define ipc_port_release(port) \ ipc_object_release(&(port)->ip_object) -extern void -ipc_port_print(ipc_port_t); +static inline boolean_t +ipc_port_flag_protected_payload(const struct ipc_port *port) +{ + return !! (port->ip_target.ipt_object.io_bits + & IO_BITS_PROTECTED_PAYLOAD); +} + +static inline void +ipc_port_flag_protected_payload_set(struct ipc_port *port) +{ + port->ip_target.ipt_object.io_bits |= IO_BITS_PROTECTED_PAYLOAD; +} + +static inline void +ipc_port_flag_protected_payload_clear(struct ipc_port *port) +{ + port->ip_target.ipt_object.io_bits &= ~IO_BITS_PROTECTED_PAYLOAD; +} #endif /* _IPC_IPC_PORT_H_ */ diff --git a/ipc/ipc_print.h b/ipc/ipc_print.h new file mode 100644 index 00000000..5e8e4f34 --- /dev/null +++ b/ipc/ipc_print.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2013 Free Software Foundation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _IPC_PRINT_H_ +#define _IPC_PRINT_H_ + +#if MACH_KDB + +#include <mach/mach_types.h> +#include <mach/message.h> +#include <ipc/ipc_types.h> +#include <ipc/ipc_pset.h> + +extern void ipc_port_print(const ipc_port_t); + +extern void ipc_pset_print(const ipc_pset_t); + +extern void ipc_kmsg_print(const ipc_kmsg_t); + +extern void ipc_msg_print(mach_msg_header_t*); + +#endif /* MACH_KDB */ + +#endif /* IPC_PRINT_H */ diff --git a/ipc/ipc_pset.c b/ipc/ipc_pset.c index e2b3c862..884e8972 100644 --- a/ipc/ipc_pset.c +++ b/ipc/ipc_pset.c @@ -48,6 +48,7 @@ #if MACH_KDB #include <ddb/db_output.h> +#include <ipc/ipc_print.h> #endif /* MACH_KDB */ @@ -333,7 +334,7 @@ ipc_pset_destroy( void ipc_pset_print( - ipc_pset_t pset) + const ipc_pset_t pset) { printf("pset 0x%x\n", pset); @@ -344,7 +345,7 @@ ipc_pset_print( iprintf("kmsgs = 0x%x", pset->ips_messages.imq_messages.ikmq_base); printf(",rcvrs = 0x%x\n", pset->ips_messages.imq_threads.ithq_base); - indent -=2; + indent -= 2; } #endif /* MACH_KDB */ diff --git a/ipc/ipc_pset.h b/ipc/ipc_pset.h index ac984f99..e9936fef 100644 --- a/ipc/ipc_pset.h +++ b/ipc/ipc_pset.h @@ -89,7 +89,4 @@ ipc_pset_destroy(ipc_pset_t); #define ipc_pset_release(pset) \ ipc_object_release(&(pset)->ips_object) -extern void -ipc_pset_print(ipc_pset_t); - #endif /* _IPC_IPC_PSET_H_ */ diff --git a/ipc/ipc_right.c b/ipc/ipc_right.c index 41fe3de1..773b3b10 100644 --- a/ipc/ipc_right.c +++ b/ipc/ipc_right.c @@ -43,7 +43,6 @@ #include <ipc/ipc_entry.h> #include <ipc/ipc_space.h> #include <ipc/ipc_object.h> -#include <ipc/ipc_hash.h> #include <ipc/ipc_port.h> #include <ipc/ipc_pset.h> #include <ipc/ipc_marequest.h> @@ -142,7 +141,8 @@ ipc_right_reverse( return TRUE; } - if (ipc_hash_lookup(space, (ipc_object_t) port, namep, entryp)) { + if ((*entryp = ipc_reverse_lookup(space, (ipc_object_t) port))) { + *namep = (*entryp)->ie_name; assert((entry = *entryp) != IE_NULL); assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_SEND); assert(port == (ipc_port_t) entry->ie_object); @@ -331,10 +331,10 @@ ipc_right_dncancel( */ boolean_t -ipc_right_inuse(space, name, entry) - ipc_space_t space; - mach_port_t name; - ipc_entry_t entry; +ipc_right_inuse( + ipc_space_t space, + mach_port_t name, + ipc_entry_t entry) { ipc_entry_bits_t bits = entry->ie_bits; @@ -359,11 +359,11 @@ ipc_right_inuse(space, name, entry) */ boolean_t -ipc_right_check(space, port, name, entry) - ipc_space_t space; - ipc_port_t port; - mach_port_t name; - ipc_entry_t entry; +ipc_right_check( + ipc_space_t space, + ipc_port_t port, + mach_port_t name, + ipc_entry_t entry) { ipc_entry_bits_t bits; @@ -392,7 +392,7 @@ ipc_right_check(space, port, name, entry) ipc_marequest_cancel(space, name); } - ipc_hash_delete(space, (ipc_object_t) port, name, entry); + ipc_reverse_remove(space, (ipc_object_t) port); } else { assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE); assert(IE_BITS_UREFS(bits) == 1); @@ -423,7 +423,7 @@ ipc_right_check(space, port, name, entry) * Purpose: * Cleans up an entry in a dead space. * The entry isn't deallocated or removed - * from reverse hash tables. + * from the reverse mappings. * Conditions: * The space is dead and unlocked. */ @@ -609,8 +609,7 @@ ipc_right_destroy( } if (type == MACH_PORT_TYPE_SEND) - ipc_hash_delete(space, (ipc_object_t) port, - name, entry); + ipc_reverse_remove(space, (ipc_object_t) port); ip_lock(port); @@ -697,10 +696,10 @@ ipc_right_destroy( */ kern_return_t -ipc_right_dealloc(space, name, entry) - ipc_space_t space; - mach_port_t name; - ipc_entry_t entry; +ipc_right_dealloc( + ipc_space_t space, + mach_port_t name, + ipc_entry_t entry) { ipc_entry_bits_t bits = entry->ie_bits; mach_port_type_t type = IE_BITS_TYPE(bits); @@ -789,8 +788,7 @@ ipc_right_dealloc(space, name, entry) dnrequest = ipc_right_dncancel_macro(space, port, name, entry); - ipc_hash_delete(space, (ipc_object_t) port, - name, entry); + ipc_reverse_remove(space, (ipc_object_t) port); if (bits & IE_BITS_MAREQUEST) ipc_marequest_cancel(space, name); @@ -874,12 +872,12 @@ ipc_right_dealloc(space, name, entry) */ kern_return_t -ipc_right_delta(space, name, entry, right, delta) - ipc_space_t space; - mach_port_t name; - ipc_entry_t entry; - mach_port_right_t right; - mach_port_delta_t delta; +ipc_right_delta( + ipc_space_t space, + mach_port_t name, + ipc_entry_t entry, + mach_port_right_t right, + mach_port_delta_t delta) { ipc_entry_bits_t bits = entry->ie_bits; @@ -1134,8 +1132,7 @@ ipc_right_delta(space, name, entry, right, delta) dnrequest = ipc_right_dncancel_macro( space, port, name, entry); - ipc_hash_delete(space, (ipc_object_t) port, - name, entry); + ipc_reverse_remove(space, (ipc_object_t) port); if (bits & IE_BITS_MAREQUEST) ipc_marequest_cancel(space, name); @@ -1410,8 +1407,8 @@ ipc_right_copyin( assert(IE_BITS_UREFS(bits) > 0); assert(port->ip_srights > 0); - ipc_hash_insert(space, (ipc_object_t) port, - name, entry); + entry->ie_name = name; + ipc_reverse_insert(space, (ipc_object_t) port, entry); ip_reference(port); } else { @@ -1432,6 +1429,12 @@ ipc_right_copyin( port->ip_receiver_name = MACH_PORT_NULL; port->ip_destination = IP_NULL; + + /* + * Clear the protected payload field to retain + * the behavior of mach_msg. + */ + ipc_port_flag_protected_payload_clear(port); ip_unlock(port); *objectp = (ipc_object_t) port; @@ -1528,8 +1531,7 @@ ipc_right_copyin( dnrequest = ipc_right_dncancel_macro( space, port, name, entry); - ipc_hash_delete(space, (ipc_object_t) port, - name, entry); + ipc_reverse_remove(space, (ipc_object_t) port); if (bits & IE_BITS_MAREQUEST) ipc_marequest_cancel(space, name); @@ -1790,8 +1792,7 @@ ipc_right_copyin_two( dnrequest = ipc_right_dncancel_macro(space, port, name, entry); - ipc_hash_delete(space, (ipc_object_t) port, - name, entry); + ipc_reverse_remove(space, (ipc_object_t) port); if (bits & IE_BITS_MAREQUEST) ipc_marequest_cancel(space, name); @@ -1915,8 +1916,8 @@ ipc_right_copyout( /* entry is locked holding ref, so can use port */ - ipc_hash_insert(space, (ipc_object_t) port, - name, entry); + entry->ie_name = name; + ipc_reverse_insert(space, (ipc_object_t) port, entry); } entry->ie_bits = (bits | MACH_PORT_TYPE_SEND) + 1; @@ -1932,6 +1933,12 @@ ipc_right_copyout( port->ip_receiver_name = name; port->ip_receiver = space; + /* + * Clear the protected payload field to retain + * the behavior of mach_msg. + */ + ipc_port_flag_protected_payload_clear(port); + assert((bits & MACH_PORT_TYPE_RECEIVE) == 0); if (bits & MACH_PORT_TYPE_SEND) { @@ -1944,8 +1951,7 @@ ipc_right_copyout( /* entry is locked holding ref, so can use port */ - ipc_hash_delete(space, (ipc_object_t) port, - name, entry); + ipc_reverse_remove(space, (ipc_object_t) port); } else { assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE); assert(IE_BITS_UREFS(bits) == 0); @@ -2071,7 +2077,7 @@ ipc_right_rename( ipc_marequest_rename(space, oname, nname); } - /* initialize nentry before letting ipc_hash_insert see it */ + /* initialize nentry before letting ipc_reverse_insert see it */ assert((nentry->ie_bits & IE_BITS_RIGHT_MASK) == 0); nentry->ie_bits |= bits & IE_BITS_RIGHT_MASK; @@ -2085,8 +2091,9 @@ ipc_right_rename( port = (ipc_port_t) object; assert(port != IP_NULL); - ipc_hash_delete(space, (ipc_object_t) port, oname, oentry); - ipc_hash_insert(space, (ipc_object_t) port, nname, nentry); + ipc_reverse_remove(space, (ipc_object_t) port); + nentry->ie_name = nname; + ipc_reverse_insert(space, (ipc_object_t) port, nentry); break; } diff --git a/ipc/ipc_space.c b/ipc/ipc_space.c index ab55e838..894cf58e 100644 --- a/ipc/ipc_space.c +++ b/ipc/ipc_space.c @@ -46,8 +46,6 @@ #include <kern/slab.h> #include <ipc/port.h> #include <ipc/ipc_entry.h> -#include <ipc/ipc_splay.h> -#include <ipc/ipc_hash.h> #include <ipc/ipc_table.h> #include <ipc/ipc_port.h> #include <ipc/ipc_space.h> @@ -82,6 +80,9 @@ ipc_space_release( ipc_space_release_macro(space); } +/* A place-holder object for the zeroth entry. */ +struct ipc_entry zero_entry; + /* * Routine: ipc_space_create * Purpose: @@ -98,56 +99,27 @@ ipc_space_release( kern_return_t ipc_space_create( - ipc_table_size_t initial, ipc_space_t *spacep) { ipc_space_t space; - ipc_entry_t table; - ipc_entry_num_t new_size; - mach_port_index_t index; space = is_alloc(); if (space == IS_NULL) return KERN_RESOURCE_SHORTAGE; - table = it_entries_alloc(initial); - if (table == IE_NULL) { - is_free(space); - return KERN_RESOURCE_SHORTAGE; - } - - new_size = initial->its_size; - memset((void *) table, 0, new_size * sizeof(struct ipc_entry)); - - /* - * Initialize the free list in the table. - * Add the entries in reverse order, and - * set the generation number to -1, so that - * initial allocations produce "natural" names. - */ - - for (index = 0; index < new_size; index++) { - ipc_entry_t entry = &table[index]; - - entry->ie_bits = IE_BITS_GEN_MASK; - entry->ie_next = index+1; - } - table[new_size-1].ie_next = 0; - is_ref_lock_init(space); space->is_references = 2; is_lock_init(space); space->is_active = TRUE; - space->is_growing = FALSE; - space->is_table = table; - space->is_table_size = new_size; - space->is_table_next = initial+1; - ipc_splay_tree_init(&space->is_tree); - space->is_tree_total = 0; - space->is_tree_small = 0; - space->is_tree_hash = 0; + rdxtree_init(&space->is_map); + rdxtree_init(&space->is_reverse_map); + /* The zeroth entry is reserved. */ + rdxtree_insert(&space->is_map, 0, &zero_entry); + space->is_size = 1; + space->is_free_list = NULL; + space->is_free_list_size = 0; *spacep = space; return KERN_SUCCESS; @@ -201,10 +173,6 @@ void ipc_space_destroy( ipc_space_t space) { - ipc_tree_entry_t tentry; - ipc_entry_t table; - ipc_entry_num_t size; - mach_port_index_t index; boolean_t active; assert(space != IS_NULL); @@ -217,59 +185,25 @@ ipc_space_destroy( if (!active) return; - /* - * If somebody is trying to grow the table, - * we must wait until they finish and figure - * out the space died. - */ + ipc_entry_t entry; + struct rdxtree_iter iter; + rdxtree_for_each(&space->is_map, &iter, entry) { + if (entry->ie_name == MACH_PORT_NULL) + continue; - is_read_lock(space); - while (space->is_growing) { - assert_wait((event_t) space, FALSE); - is_read_unlock(space); - thread_block((void (*)(void)) 0); - is_read_lock(space); - } - is_read_unlock(space); - - /* - * Now we can futz with it without having it locked. - */ - - table = space->is_table; - size = space->is_table_size; - - for (index = 0; index < size; index++) { - ipc_entry_t entry = &table[index]; mach_port_type_t type = IE_BITS_TYPE(entry->ie_bits); if (type != MACH_PORT_TYPE_NONE) { mach_port_t name = - MACH_PORT_MAKEB(index, entry->ie_bits); + MACH_PORT_MAKEB(entry->ie_name, entry->ie_bits); ipc_right_clean(space, name, entry); } - } - - it_entries_free(space->is_table_next-1, table); - - for (tentry = ipc_splay_traverse_start(&space->is_tree); - tentry != ITE_NULL; - tentry = ipc_splay_traverse_next(&space->is_tree, TRUE)) { - mach_port_type_t type = IE_BITS_TYPE(tentry->ite_bits); - mach_port_t name = tentry->ite_name; - - assert(type != MACH_PORT_TYPE_NONE); - - /* use object before ipc_right_clean releases ref */ - - if (type == MACH_PORT_TYPE_SEND) - ipc_hash_global_delete(space, tentry->ite_object, - name, tentry); - ipc_right_clean(space, name, &tentry->ite_entry); + ie_free(entry); } - ipc_splay_traverse_finish(&space->is_tree); + rdxtree_remove_all(&space->is_map); + rdxtree_remove_all(&space->is_reverse_map); /* * Because the space is now dead, diff --git a/ipc/ipc_space.h b/ipc/ipc_space.h index c4683d20..73c90ef8 100644 --- a/ipc/ipc_space.h +++ b/ipc/ipc_space.h @@ -42,25 +42,18 @@ #include <mach/boolean.h> #include <mach/kern_return.h> #include <mach/mach_types.h> -#include <kern/macro_help.h> +#include <machine/vm_param.h> +#include <kern/macros.h> #include <kern/lock.h> +#include <kern/rdxtree.h> #include <kern/slab.h> -#include <ipc/ipc_splay.h> +#include <ipc/ipc_entry.h> #include <ipc/ipc_types.h> /* * Every task has a space of IPC capabilities. * IPC operations like send and receive use this space. * IPC kernel calls manipulate the space of the target task. - * - * Every space has a non-NULL is_table with is_table_size entries. - * A space may have a NULL is_tree. is_tree_small records the - * number of entries in the tree that, if the table were to grow - * to the next larger size, would move from the tree to the table. - * - * is_growing marks when the table is in the process of growing. - * When the table is growing, it can't be freed or grown by another - * thread, because of krealloc/kmem_realloc's requirements. */ typedef unsigned int ipc_space_refs_t; @@ -69,18 +62,18 @@ struct ipc_space { decl_simple_lock_data(,is_ref_lock_data) ipc_space_refs_t is_references; - decl_simple_lock_data(,is_lock_data) + struct lock is_lock_data; boolean_t is_active; /* is the space alive? */ - boolean_t is_growing; /* is the space growing? */ - ipc_entry_t is_table; /* an array of entries */ - ipc_entry_num_t is_table_size; /* current size of table */ - struct ipc_table_size *is_table_next; /* info for larger table */ - struct ipc_splay_tree is_tree; /* a splay tree of entries */ - ipc_entry_num_t is_tree_total; /* number of entries in the tree */ - ipc_entry_num_t is_tree_small; /* # of small entries in the tree */ - ipc_entry_num_t is_tree_hash; /* # of hashed entries in the tree */ + struct rdxtree is_map; /* a map of entries */ + size_t is_size; /* number of entries */ + struct rdxtree is_reverse_map; /* maps objects to entries */ + ipc_entry_t is_free_list; /* a linked list of free entries */ + size_t is_free_list_size; /* number of free entries */ +#define IS_FREE_LIST_SIZE_LIMIT 64 /* maximum number of entries + in the free list */ }; + #define IS_NULL ((ipc_space_t) 0) extern struct kmem_cache ipc_space_cache; @@ -114,16 +107,16 @@ MACRO_BEGIN \ is_free(is); \ MACRO_END -#define is_lock_init(is) simple_lock_init(&(is)->is_lock_data) +#define is_lock_init(is) lock_init(&(is)->is_lock_data, TRUE) -#define is_read_lock(is) simple_lock(&(is)->is_lock_data) -#define is_read_unlock(is) simple_unlock(&(is)->is_lock_data) +#define is_read_lock(is) lock_read(&(is)->is_lock_data) +#define is_read_unlock(is) lock_done(&(is)->is_lock_data) -#define is_write_lock(is) simple_lock(&(is)->is_lock_data) -#define is_write_lock_try(is) simple_lock_try(&(is)->is_lock_data) -#define is_write_unlock(is) simple_unlock(&(is)->is_lock_data) +#define is_write_lock(is) lock_write(&(is)->is_lock_data) +#define is_write_lock_try(is) lock_try_write(&(is)->is_lock_data) +#define is_write_unlock(is) lock_done(&(is)->is_lock_data) -#define is_write_to_read_lock(is) +#define is_write_to_read_lock(is) lock_write_to_read(&(is)->is_lock_data) extern void ipc_space_reference(struct ipc_space *space); extern void ipc_space_release(struct ipc_space *space); @@ -131,8 +124,187 @@ extern void ipc_space_release(struct ipc_space *space); #define is_reference(is) ipc_space_reference(is) #define is_release(is) ipc_space_release(is) -kern_return_t ipc_space_create(ipc_table_size_t, ipc_space_t *); +kern_return_t ipc_space_create(ipc_space_t *); kern_return_t ipc_space_create_special(struct ipc_space **); void ipc_space_destroy(struct ipc_space *); +/* IPC entry lookups. */ + +/* + * Routine: ipc_entry_lookup + * Purpose: + * Searches for an entry, given its name. + * Conditions: + * The space must be read or write locked throughout. + * The space must be active. + */ + +static inline ipc_entry_t +ipc_entry_lookup( + ipc_space_t space, + mach_port_t name) +{ + ipc_entry_t entry; + + assert(space->is_active); + entry = rdxtree_lookup(&space->is_map, (rdxtree_key_t) name); + if (entry != IE_NULL + && IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) + entry = NULL; + assert((entry == IE_NULL) || IE_BITS_TYPE(entry->ie_bits)); + return entry; +} + +/* + * Routine: ipc_entry_get + * Purpose: + * Tries to allocate an entry out of the space. + * Conditions: + * The space is write-locked and active throughout. + * An object may be locked. Will not allocate memory. + * Returns: + * KERN_SUCCESS A free entry was found. + * KERN_NO_SPACE No entry allocated. + */ + +static inline kern_return_t +ipc_entry_get( + ipc_space_t space, + mach_port_t *namep, + ipc_entry_t *entryp) +{ + mach_port_t new_name; + ipc_entry_t free_entry; + + assert(space->is_active); + + /* Get entry from the free list. */ + free_entry = space->is_free_list; + if (free_entry == IE_NULL) + return KERN_NO_SPACE; + + space->is_free_list = free_entry->ie_next_free; + space->is_free_list_size -= 1; + + /* + * Initialize the new entry. We need only + * increment the generation number and clear ie_request. + */ + + { + mach_port_gen_t gen; + + assert((free_entry->ie_bits &~ IE_BITS_GEN_MASK) == 0); + gen = free_entry->ie_bits + IE_BITS_GEN_ONE; + free_entry->ie_bits = gen; + free_entry->ie_request = 0; + new_name = MACH_PORT_MAKE(free_entry->ie_name, gen); + } + + /* + * The new name can't be MACH_PORT_NULL because index + * is non-zero. It can't be MACH_PORT_DEAD because + * the table isn't allowed to grow big enough. + * (See comment in ipc/ipc_table.h.) + */ + + assert(MACH_PORT_VALID(new_name)); + assert(free_entry->ie_object == IO_NULL); + + space->is_size += 1; + *namep = new_name; + *entryp = free_entry; + return KERN_SUCCESS; +} + +/* + * Routine: ipc_entry_dealloc + * Purpose: + * Deallocates an entry from a space. + * Conditions: + * The space must be write-locked throughout. + * The space must be active. + */ + +static inline void +ipc_entry_dealloc( + ipc_space_t space, + mach_port_t name, + ipc_entry_t entry) +{ + assert(space->is_active); + assert(entry->ie_object == IO_NULL); + assert(entry->ie_request == 0); + + if (space->is_free_list_size < IS_FREE_LIST_SIZE_LIMIT) { + space->is_free_list_size += 1; + entry->ie_bits &= IE_BITS_GEN_MASK; + entry->ie_next_free = space->is_free_list; + space->is_free_list = entry; + } else { + rdxtree_remove(&space->is_map, (rdxtree_key_t) name); + ie_free(entry); + } + space->is_size -= 1; +} + +/* Reverse lookups. */ + +/* Cast a pointer to a suitable key. */ +#define KEY(X) \ + ({ \ + assert((((unsigned long) (X)) & 0x07) == 0); \ + ((unsigned long long) \ + (((unsigned long) (X) - VM_MIN_KERNEL_ADDRESS) >> 3)); \ + }) + +/* Insert (OBJ, ENTRY) pair into the reverse mapping. SPACE must + be write-locked. */ +static inline kern_return_t +ipc_reverse_insert(ipc_space_t space, + ipc_object_t obj, + ipc_entry_t entry) +{ + assert(space != IS_NULL); + assert(obj != IO_NULL); + return (kern_return_t) rdxtree_insert(&space->is_reverse_map, + KEY(obj), entry); +} + +/* Remove OBJ from the reverse mapping. SPACE must be + write-locked. */ +static inline ipc_entry_t +ipc_reverse_remove(ipc_space_t space, + ipc_object_t obj) +{ + assert(space != IS_NULL); + assert(obj != IO_NULL); + return rdxtree_remove(&space->is_reverse_map, KEY(obj)); +} + +/* Remove all entries from the reverse mapping. SPACE must be + write-locked. */ +static inline void +ipc_reverse_remove_all(ipc_space_t space) +{ + assert(space != IS_NULL); + rdxtree_remove_all(&space->is_reverse_map); + assert(space->is_reverse_map.height == 0); + assert(space->is_reverse_map.root == NULL); +} + +/* Return ENTRY related to OBJ, or NULL if no such entry is found in + the reverse mapping. SPACE must be read-locked or + write-locked. */ +static inline ipc_entry_t +ipc_reverse_lookup(ipc_space_t space, + ipc_object_t obj) +{ + assert(space != IS_NULL); + assert(obj != IO_NULL); + return rdxtree_lookup(&space->is_reverse_map, KEY(obj)); +} + +#undef KEY + #endif /* _IPC_IPC_SPACE_H_ */ diff --git a/ipc/ipc_splay.c b/ipc/ipc_splay.c deleted file mode 100644 index 6fb5bcbc..00000000 --- a/ipc/ipc_splay.c +++ /dev/null @@ -1,920 +0,0 @@ -/* - * 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_splay.c - * Author: Rich Draves - * Date: 1989 - * - * Primitive splay tree operations. - */ - -#include <mach/port.h> -#include <kern/assert.h> -#include <kern/macro_help.h> -#include <ipc/ipc_entry.h> -#include <ipc/ipc_splay.h> - -/* - * Splay trees are self-adjusting binary search trees. - * They have the following attractive properties: - * 1) Space efficient; only two pointers per entry. - * 2) Robust performance; amortized O(log n) per operation. - * 3) Recursion not needed. - * This makes them a good fall-back data structure for those - * entries that don't fit into the lookup table. - * - * The paper by Sleator and Tarjan, JACM v. 32, no. 3, pp. 652-686, - * describes the splaying operation. ipc_splay_prim_lookup - * and ipc_splay_prim_assemble implement the top-down splay - * described on p. 669. - * - * The tree is stored in an unassembled form. If ist_root is null, - * then the tree has no entries. Otherwise, ist_name records - * the value used for the last lookup. ist_root points to the - * middle tree obtained from the top-down splay. ist_ltree and - * ist_rtree point to left and right subtrees, whose entries - * are all smaller (larger) than those in the middle tree. - * ist_ltreep and ist_rtreep are pointers to fields in the - * left and right subtrees. ist_ltreep points to the rchild field - * of the largest entry in ltree, and ist_rtreep points to the - * lchild field of the smallest entry in rtree. The pointed-to - * fields aren't initialized. If the left (right) subtree is null, - * then ist_ltreep (ist_rtreep) points to the ist_ltree (ist_rtree) - * field in the splay structure itself. - * - * The primary advantage of the unassembled form is that repeated - * unsuccessful lookups are efficient. In particular, an unsuccessful - * lookup followed by an insert only requires one splaying operation. - * - * The traversal algorithm works via pointer inversion. - * When descending down the tree, child pointers are reversed - * to point back to the parent entry. When ascending, - * the pointers are restored to their original value. - * - * The biggest potential problem with the splay tree implementation - * is that the operations, even lookup, require an exclusive lock. - * If IPC spaces are protected with exclusive locks, then - * the splay tree doesn't require its own lock, and ist_lock/ist_unlock - * needn't do anything. If IPC spaces are protected with read/write - * locks then ist_lock/ist_unlock should provide exclusive access. - * - * If it becomes important to let lookups run in parallel, - * or if the restructuring makes lookups too expensive, then - * there is hope. Use a read/write lock on the splay tree. - * Keep track of the number of entries in the tree. When doing - * a lookup, first try a non-restructuring lookup with a read lock held, - * with a bound (based on log of size of the tree) on the number of - * entries to traverse. If the lookup runs up against the bound, - * then take a write lock and do a reorganizing lookup. - * This way, if lookups only access roughly balanced parts - * of the tree, then lookups run in parallel and do no restructuring. - * - * The traversal algorithm currently requires an exclusive lock. - * If that is a problem, the tree could be changed from an lchild/rchild - * representation to a leftmost child/right sibling representation. - * In conjunction with non-restructing lookups, this would let - * lookups and traversals all run in parallel. But this representation - * is more complicated and would slow down the operations. - */ - -/* - * Boundary values to hand to ipc_splay_prim_lookup: - */ - -#define MACH_PORT_SMALLEST ((mach_port_t) 0) -#define MACH_PORT_LARGEST ((mach_port_t) ~0) - -/* - * Routine: ipc_splay_prim_lookup - * Purpose: - * Searches for the node labeled name in the splay tree. - * Returns three nodes (treep, ltreep, rtreep) and - * two pointers to nodes (ltreepp, rtreepp). - * - * ipc_splay_prim_lookup splits the supplied tree into - * three subtrees, left, middle, and right, returned - * in ltreep, treep, and rtreep. - * - * If name is present in the tree, then it is at - * the root of the middle tree. Otherwise, the root - * of the middle tree is the last node traversed. - * - * ipc_splay_prim_lookup returns a pointer into - * the left subtree, to the rchild field of its - * largest node, in ltreepp. It returns a pointer - * into the right subtree, to the lchild field of its - * smallest node, in rtreepp. - */ - -static void -ipc_splay_prim_lookup( - mach_port_t name, - ipc_tree_entry_t tree, - ipc_tree_entry_t *treep, - ipc_tree_entry_t *ltreep, - ipc_tree_entry_t **ltreepp, - ipc_tree_entry_t *rtreep, - ipc_tree_entry_t **rtreepp) -{ - mach_port_t tname; /* temp name */ - ipc_tree_entry_t lchild, rchild; /* temp child pointers */ - - assert(tree != ITE_NULL); - -#define link_left \ -MACRO_BEGIN \ - *ltreep = tree; \ - ltreep = &tree->ite_rchild; \ - tree = *ltreep; \ -MACRO_END - -#define link_right \ -MACRO_BEGIN \ - *rtreep = tree; \ - rtreep = &tree->ite_lchild; \ - tree = *rtreep; \ -MACRO_END - -#define rotate_left \ -MACRO_BEGIN \ - ipc_tree_entry_t temp = tree; \ - \ - tree = temp->ite_rchild; \ - temp->ite_rchild = tree->ite_lchild; \ - tree->ite_lchild = temp; \ -MACRO_END - -#define rotate_right \ -MACRO_BEGIN \ - ipc_tree_entry_t temp = tree; \ - \ - tree = temp->ite_lchild; \ - temp->ite_lchild = tree->ite_rchild; \ - tree->ite_rchild = temp; \ -MACRO_END - - while (name != (tname = tree->ite_name)) { - if (name < tname) { - /* descend to left */ - - lchild = tree->ite_lchild; - if (lchild == ITE_NULL) - break; - tname = lchild->ite_name; - - if ((name < tname) && - (lchild->ite_lchild != ITE_NULL)) - rotate_right; - link_right; - if ((name > tname) && - (lchild->ite_rchild != ITE_NULL)) - link_left; - } else { - /* descend to right */ - - rchild = tree->ite_rchild; - if (rchild == ITE_NULL) - break; - tname = rchild->ite_name; - - if ((name > tname) && - (rchild->ite_rchild != ITE_NULL)) - rotate_left; - link_left; - if ((name < tname) && - (rchild->ite_lchild != ITE_NULL)) - link_right; - } - - assert(tree != ITE_NULL); - } - - *treep = tree; - *ltreepp = ltreep; - *rtreepp = rtreep; - -#undef link_left -#undef link_right -#undef rotate_left -#undef rotate_right -} - -/* - * Routine: ipc_splay_prim_assemble - * Purpose: - * Assembles the results of ipc_splay_prim_lookup - * into a splay tree with the found node at the root. - * - * ltree and rtree are by-reference so storing - * through ltreep and rtreep can change them. - */ - -static void -ipc_splay_prim_assemble( - ipc_tree_entry_t tree, - ipc_tree_entry_t *ltree, - ipc_tree_entry_t *ltreep, - ipc_tree_entry_t *rtree, - ipc_tree_entry_t *rtreep) -{ - assert(tree != ITE_NULL); - - *ltreep = tree->ite_lchild; - *rtreep = tree->ite_rchild; - - tree->ite_lchild = *ltree; - tree->ite_rchild = *rtree; -} - -/* - * Routine: ipc_splay_tree_init - * Purpose: - * Initialize a raw splay tree for use. - */ - -void -ipc_splay_tree_init( - ipc_splay_tree_t splay) -{ - splay->ist_root = ITE_NULL; -} - -/* - * Routine: ipc_splay_tree_pick - * Purpose: - * Picks and returns a random entry in a splay tree. - * Returns FALSE if the splay tree is empty. - */ - -boolean_t -ipc_splay_tree_pick( - ipc_splay_tree_t splay, - mach_port_t *namep, - ipc_tree_entry_t *entryp) -{ - ipc_tree_entry_t root; - - ist_lock(splay); - - root = splay->ist_root; - if (root != ITE_NULL) { - *namep = root->ite_name; - *entryp = root; - } - - ist_unlock(splay); - - return root != ITE_NULL; -} - -/* - * Routine: ipc_splay_tree_lookup - * Purpose: - * Finds an entry in a splay tree. - * Returns ITE_NULL if not found. - */ - -ipc_tree_entry_t -ipc_splay_tree_lookup( - ipc_splay_tree_t splay, - mach_port_t name) -{ - ipc_tree_entry_t root; - - ist_lock(splay); - - root = splay->ist_root; - if (root != ITE_NULL) { - if (splay->ist_name != name) { - ipc_splay_prim_assemble(root, - &splay->ist_ltree, splay->ist_ltreep, - &splay->ist_rtree, splay->ist_rtreep); - ipc_splay_prim_lookup(name, root, &root, - &splay->ist_ltree, &splay->ist_ltreep, - &splay->ist_rtree, &splay->ist_rtreep); - splay->ist_name = name; - splay->ist_root = root; - } - - if (name != root->ite_name) - root = ITE_NULL; - } - - ist_unlock(splay); - - return root; -} - -/* - * Routine: ipc_splay_tree_insert - * Purpose: - * Inserts a new entry into a splay tree. - * The caller supplies a new entry. - * The name can't already be present in the tree. - */ - -void -ipc_splay_tree_insert( - ipc_splay_tree_t splay, - mach_port_t name, - ipc_tree_entry_t entry) -{ - ipc_tree_entry_t root; - - assert(entry != ITE_NULL); - - ist_lock(splay); - - root = splay->ist_root; - if (root == ITE_NULL) { - entry->ite_lchild = ITE_NULL; - entry->ite_rchild = ITE_NULL; - } else { - if (splay->ist_name != name) { - ipc_splay_prim_assemble(root, - &splay->ist_ltree, splay->ist_ltreep, - &splay->ist_rtree, splay->ist_rtreep); - ipc_splay_prim_lookup(name, root, &root, - &splay->ist_ltree, &splay->ist_ltreep, - &splay->ist_rtree, &splay->ist_rtreep); - } - - assert(root->ite_name != name); - - if (name < root->ite_name) { - assert(root->ite_lchild == ITE_NULL); - - *splay->ist_ltreep = ITE_NULL; - *splay->ist_rtreep = root; - } else { - assert(root->ite_rchild == ITE_NULL); - - *splay->ist_ltreep = root; - *splay->ist_rtreep = ITE_NULL; - } - - entry->ite_lchild = splay->ist_ltree; - entry->ite_rchild = splay->ist_rtree; - } - - entry->ite_name = name; - splay->ist_root = entry; - splay->ist_name = name; - splay->ist_ltreep = &splay->ist_ltree; - splay->ist_rtreep = &splay->ist_rtree; - - ist_unlock(splay); -} - -/* - * Routine: ipc_splay_tree_delete - * Purpose: - * Deletes an entry from a splay tree. - * The name must be present in the tree. - * Frees the entry. - * - * The "entry" argument isn't currently used. - * Other implementations might want it, though. - */ - -void -ipc_splay_tree_delete( - ipc_splay_tree_t splay, - mach_port_t name, - ipc_tree_entry_t entry) -{ - ipc_tree_entry_t root, saved; - - ist_lock(splay); - - root = splay->ist_root; - assert(root != ITE_NULL); - - if (splay->ist_name != name) { - ipc_splay_prim_assemble(root, - &splay->ist_ltree, splay->ist_ltreep, - &splay->ist_rtree, splay->ist_rtreep); - ipc_splay_prim_lookup(name, root, &root, - &splay->ist_ltree, &splay->ist_ltreep, - &splay->ist_rtree, &splay->ist_rtreep); - } - - assert(root->ite_name == name); - assert(root == entry); - - *splay->ist_ltreep = root->ite_lchild; - *splay->ist_rtreep = root->ite_rchild; - ite_free(root); - - root = splay->ist_ltree; - saved = splay->ist_rtree; - - if (root == ITE_NULL) - root = saved; - else if (saved != ITE_NULL) { - /* - * Find the largest node in the left subtree, and splay it - * to the root. Then add the saved right subtree. - */ - - ipc_splay_prim_lookup(MACH_PORT_LARGEST, root, &root, - &splay->ist_ltree, &splay->ist_ltreep, - &splay->ist_rtree, &splay->ist_rtreep); - ipc_splay_prim_assemble(root, - &splay->ist_ltree, splay->ist_ltreep, - &splay->ist_rtree, splay->ist_rtreep); - - assert(root->ite_rchild == ITE_NULL); - root->ite_rchild = saved; - } - - splay->ist_root = root; - if (root != ITE_NULL) { - splay->ist_name = root->ite_name; - splay->ist_ltreep = &splay->ist_ltree; - splay->ist_rtreep = &splay->ist_rtree; - } - - ist_unlock(splay); -} - -/* - * Routine: ipc_splay_tree_split - * Purpose: - * Split a splay tree. Puts all entries smaller than "name" - * into a new tree, "small". - * - * Doesn't do locking on "small", because nobody else - * should be fiddling with the uninitialized tree. - */ - -void -ipc_splay_tree_split( - ipc_splay_tree_t splay, - mach_port_t name, - ipc_splay_tree_t small) -{ - ipc_tree_entry_t root; - - ipc_splay_tree_init(small); - - ist_lock(splay); - - root = splay->ist_root; - if (root != ITE_NULL) { - /* lookup name, to get it (or last traversed) to the top */ - - if (splay->ist_name != name) { - ipc_splay_prim_assemble(root, - &splay->ist_ltree, splay->ist_ltreep, - &splay->ist_rtree, splay->ist_rtreep); - ipc_splay_prim_lookup(name, root, &root, - &splay->ist_ltree, &splay->ist_ltreep, - &splay->ist_rtree, &splay->ist_rtreep); - } - - if (root->ite_name < name) { - /* root goes into small */ - - *splay->ist_ltreep = root->ite_lchild; - *splay->ist_rtreep = ITE_NULL; - root->ite_lchild = splay->ist_ltree; - assert(root->ite_rchild == ITE_NULL); - - small->ist_root = root; - small->ist_name = root->ite_name; - small->ist_ltreep = &small->ist_ltree; - small->ist_rtreep = &small->ist_rtree; - - /* rtree goes into splay */ - - root = splay->ist_rtree; - splay->ist_root = root; - if (root != ITE_NULL) { - splay->ist_name = root->ite_name; - splay->ist_ltreep = &splay->ist_ltree; - splay->ist_rtreep = &splay->ist_rtree; - } - } else { - /* root stays in splay */ - - *splay->ist_ltreep = root->ite_lchild; - root->ite_lchild = ITE_NULL; - - splay->ist_root = root; - splay->ist_name = name; - splay->ist_ltreep = &splay->ist_ltree; - - /* ltree goes into small */ - - root = splay->ist_ltree; - small->ist_root = root; - if (root != ITE_NULL) { - small->ist_name = root->ite_name; - small->ist_ltreep = &small->ist_ltree; - small->ist_rtreep = &small->ist_rtree; - } - } - } - - ist_unlock(splay); -} - -/* - * Routine: ipc_splay_tree_join - * Purpose: - * Joins two splay trees. Merges the entries in "small", - * which must all be smaller than the entries in "splay", - * into "splay". - */ - -void -ipc_splay_tree_join( - ipc_splay_tree_t splay, - ipc_splay_tree_t small) -{ - ipc_tree_entry_t sroot; - - /* pull entries out of small */ - - ist_lock(small); - - sroot = small->ist_root; - if (sroot != ITE_NULL) { - ipc_splay_prim_assemble(sroot, - &small->ist_ltree, small->ist_ltreep, - &small->ist_rtree, small->ist_rtreep); - small->ist_root = ITE_NULL; - } - - ist_unlock(small); - - /* put entries, if any, into splay */ - - if (sroot != ITE_NULL) { - ipc_tree_entry_t root; - - ist_lock(splay); - - root = splay->ist_root; - if (root == ITE_NULL) { - root = sroot; - } else { - /* get smallest entry in splay tree to top */ - - if (splay->ist_name != MACH_PORT_SMALLEST) { - ipc_splay_prim_assemble(root, - &splay->ist_ltree, splay->ist_ltreep, - &splay->ist_rtree, splay->ist_rtreep); - ipc_splay_prim_lookup(MACH_PORT_SMALLEST, - root, &root, - &splay->ist_ltree, &splay->ist_ltreep, - &splay->ist_rtree, &splay->ist_rtreep); - } - - ipc_splay_prim_assemble(root, - &splay->ist_ltree, splay->ist_ltreep, - &splay->ist_rtree, splay->ist_rtreep); - - assert(root->ite_lchild == ITE_NULL); - assert(sroot->ite_name < root->ite_name); - root->ite_lchild = sroot; - } - - splay->ist_root = root; - splay->ist_name = root->ite_name; - splay->ist_ltreep = &splay->ist_ltree; - splay->ist_rtreep = &splay->ist_rtree; - - ist_unlock(splay); - } -} - -/* - * Routine: ipc_splay_tree_bounds - * Purpose: - * Given a name, returns the largest value present - * in the tree that is smaller than or equal to the name, - * or ~0 if no such value exists. Similarly, returns - * the smallest value present that is greater than or - * equal to the name, or 0 if no such value exists. - * - * Hence, if - * lower = upper, then lower = name = upper - * and name is present in the tree - * lower = ~0 and upper = 0, - * then the tree is empty - * lower = ~0 and upper > 0, then name < upper - * and upper is smallest value in tree - * lower < ~0 and upper = 0, then lower < name - * and lower is largest value in tree - * lower < ~0 and upper > 0, then lower < name < upper - * and they are tight bounds on name - * - * (Note MACH_PORT_SMALLEST = 0 and MACH_PORT_LARGEST = ~0.) - */ - -void -ipc_splay_tree_bounds( - ipc_splay_tree_t splay, - mach_port_t name, - mach_port_t *lowerp, - mach_port_t *upperp) -{ - ipc_tree_entry_t root; - - ist_lock(splay); - - root = splay->ist_root; - if (root == ITE_NULL) { - *lowerp = MACH_PORT_LARGEST; - *upperp = MACH_PORT_SMALLEST; - } else { - mach_port_t rname; - - if (splay->ist_name != name) { - ipc_splay_prim_assemble(root, - &splay->ist_ltree, splay->ist_ltreep, - &splay->ist_rtree, splay->ist_rtreep); - ipc_splay_prim_lookup(name, root, &root, - &splay->ist_ltree, &splay->ist_ltreep, - &splay->ist_rtree, &splay->ist_rtreep); - splay->ist_name = name; - splay->ist_root = root; - } - - rname = root->ite_name; - - /* - * OK, it's a hack. We convert the ltreep and rtreep - * pointers back into real entry pointers, - * so we can pick the names out of the entries. - */ - - if (rname <= name) - *lowerp = rname; - else if (splay->ist_ltreep == &splay->ist_ltree) - *lowerp = MACH_PORT_LARGEST; - else { - ipc_tree_entry_t entry; - - entry = (ipc_tree_entry_t) - ((char *)splay->ist_ltreep - - ((char *)&root->ite_rchild - - (char *)root)); - *lowerp = entry->ite_name; - } - - if (rname >= name) - *upperp = rname; - else if (splay->ist_rtreep == &splay->ist_rtree) - *upperp = MACH_PORT_SMALLEST; - else { - ipc_tree_entry_t entry; - - entry = (ipc_tree_entry_t) - ((char *)splay->ist_rtreep - - ((char *)&root->ite_lchild - - (char *)root)); - *upperp = entry->ite_name; - } - } - - ist_unlock(splay); -} - -/* - * Routine: ipc_splay_traverse_start - * Routine: ipc_splay_traverse_next - * Routine: ipc_splay_traverse_finish - * Purpose: - * Perform a symmetric order traversal of a splay tree. - * Usage: - * for (entry = ipc_splay_traverse_start(splay); - * entry != ITE_NULL; - * entry = ipc_splay_traverse_next(splay, delete)) { - * do something with entry - * } - * ipc_splay_traverse_finish(splay); - * - * If "delete" is TRUE, then the current entry - * is removed from the tree and deallocated. - * - * During the traversal, the splay tree is locked. - */ - -ipc_tree_entry_t -ipc_splay_traverse_start( - ipc_splay_tree_t splay) -{ - ipc_tree_entry_t current, parent; - - ist_lock(splay); - - current = splay->ist_root; - if (current != ITE_NULL) { - ipc_splay_prim_assemble(current, - &splay->ist_ltree, splay->ist_ltreep, - &splay->ist_rtree, splay->ist_rtreep); - - parent = ITE_NULL; - - while (current->ite_lchild != ITE_NULL) { - ipc_tree_entry_t next; - - next = current->ite_lchild; - current->ite_lchild = parent; - parent = current; - current = next; - } - - splay->ist_ltree = current; - splay->ist_rtree = parent; - } - - return current; -} - -ipc_tree_entry_t -ipc_splay_traverse_next( - ipc_splay_tree_t splay, - boolean_t delete) -{ - ipc_tree_entry_t current, parent; - - /* pick up where traverse_entry left off */ - - current = splay->ist_ltree; - parent = splay->ist_rtree; - assert(current != ITE_NULL); - - if (!delete) - goto traverse_right; - - /* we must delete current and patch the tree */ - - if (current->ite_lchild == ITE_NULL) { - if (current->ite_rchild == ITE_NULL) { - /* like traverse_back, but with deletion */ - - if (parent == ITE_NULL) { - ite_free(current); - - splay->ist_root = ITE_NULL; - return ITE_NULL; - } - - if (current->ite_name < parent->ite_name) { - ite_free(current); - - current = parent; - parent = current->ite_lchild; - current->ite_lchild = ITE_NULL; - goto traverse_entry; - } else { - ite_free(current); - - current = parent; - parent = current->ite_rchild; - current->ite_rchild = ITE_NULL; - goto traverse_back; - } - } else { - ipc_tree_entry_t prev; - - prev = current; - current = current->ite_rchild; - ite_free(prev); - goto traverse_left; - } - } else { - if (current->ite_rchild == ITE_NULL) { - ipc_tree_entry_t prev; - - prev = current; - current = current->ite_lchild; - ite_free(prev); - goto traverse_back; - } else { - ipc_tree_entry_t prev; - ipc_tree_entry_t ltree, rtree; - ipc_tree_entry_t *ltreep, *rtreep; - - /* replace current with largest of left children */ - - prev = current; - ipc_splay_prim_lookup(MACH_PORT_LARGEST, - current->ite_lchild, ¤t, - <ree, <reep, &rtree, &rtreep); - ipc_splay_prim_assemble(current, - <ree, ltreep, &rtree, rtreep); - - assert(current->ite_rchild == ITE_NULL); - current->ite_rchild = prev->ite_rchild; - ite_free(prev); - goto traverse_right; - } - } - /*NOTREACHED*/ - - /* - * A state machine: for each entry, we - * 1) traverse left subtree - * 2) traverse the entry - * 3) traverse right subtree - * 4) traverse back to parent - */ - - traverse_left: - if (current->ite_lchild != ITE_NULL) { - ipc_tree_entry_t next; - - next = current->ite_lchild; - current->ite_lchild = parent; - parent = current; - current = next; - goto traverse_left; - } - - traverse_entry: - splay->ist_ltree = current; - splay->ist_rtree = parent; - return current; - - traverse_right: - if (current->ite_rchild != ITE_NULL) { - ipc_tree_entry_t next; - - next = current->ite_rchild; - current->ite_rchild = parent; - parent = current; - current = next; - goto traverse_left; - } - - traverse_back: - if (parent == ITE_NULL) { - splay->ist_root = current; - return ITE_NULL; - } - - if (current->ite_name < parent->ite_name) { - ipc_tree_entry_t prev; - - prev = current; - current = parent; - parent = current->ite_lchild; - current->ite_lchild = prev; - goto traverse_entry; - } else { - ipc_tree_entry_t prev; - - prev = current; - current = parent; - parent = current->ite_rchild; - current->ite_rchild = prev; - goto traverse_back; - } -} - -void -ipc_splay_traverse_finish( - ipc_splay_tree_t splay) -{ - ipc_tree_entry_t root; - - root = splay->ist_root; - if (root != ITE_NULL) { - splay->ist_name = root->ite_name; - splay->ist_ltreep = &splay->ist_ltree; - splay->ist_rtreep = &splay->ist_rtree; - } - - ist_unlock(splay); -} - diff --git a/ipc/ipc_splay.h b/ipc/ipc_splay.h deleted file mode 100644 index d3316ef8..00000000 --- a/ipc/ipc_splay.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 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_splay.h - * Author: Rich Draves - * Date: 1989 - * - * Declarations of primitive splay tree operations. - */ - -#ifndef _IPC_IPC_SPLAY_H_ -#define _IPC_IPC_SPLAY_H_ - -#include <mach/port.h> -#include <kern/assert.h> -#include <kern/macro_help.h> -#include <ipc/ipc_entry.h> - -typedef struct ipc_splay_tree { - mach_port_t ist_name; /* name used in last lookup */ - ipc_tree_entry_t ist_root; /* root of middle tree */ - ipc_tree_entry_t ist_ltree; /* root of left tree */ - ipc_tree_entry_t *ist_ltreep; /* pointer into left tree */ - ipc_tree_entry_t ist_rtree; /* root of right tree */ - ipc_tree_entry_t *ist_rtreep; /* pointer into right tree */ -} *ipc_splay_tree_t; - -#define ist_lock(splay) /* no locking */ -#define ist_unlock(splay) /* no locking */ - -/* Initialize a raw splay tree */ -extern void ipc_splay_tree_init( - ipc_splay_tree_t splay); - -/* Pick a random entry in a splay tree */ -extern boolean_t ipc_splay_tree_pick( - ipc_splay_tree_t splay, - mach_port_t *namep, - ipc_tree_entry_t *entryp); - -/* Find an entry in a splay tree */ -extern ipc_tree_entry_t ipc_splay_tree_lookup( - ipc_splay_tree_t splay, - mach_port_t name); - -/* Insert a new entry into a splay tree */ -extern void ipc_splay_tree_insert( - ipc_splay_tree_t splay, - mach_port_t name, - ipc_tree_entry_t entry); - -/* Delete an entry from a splay tree */ -extern void ipc_splay_tree_delete( - ipc_splay_tree_t splay, - mach_port_t name, - ipc_tree_entry_t entry); - -/* Split a splay tree */ -extern void ipc_splay_tree_split( - ipc_splay_tree_t splay, - mach_port_t name, - ipc_splay_tree_t entry); - -/* Join two splay trees */ -extern void ipc_splay_tree_join( - ipc_splay_tree_t splay, - ipc_splay_tree_t small); - -/* Do a bounded splay tree lookup */ -extern void ipc_splay_tree_bounds( - ipc_splay_tree_t splay, - mach_port_t name, - mach_port_t *lowerp, - mach_port_t *upperp); - -/* Initialize a symmetric order traversal of a splay tree */ -extern ipc_tree_entry_t ipc_splay_traverse_start( - ipc_splay_tree_t splay); - -/* Return the next entry in a symmetric order traversal of a splay tree */ -extern ipc_tree_entry_t ipc_splay_traverse_next( - ipc_splay_tree_t splay, - boolean_t delete); - -/* Terminate a symmetric order traversal of a splay tree */ -extern void ipc_splay_traverse_finish( - ipc_splay_tree_t splay); - -#endif /* _IPC_IPC_SPLAY_H_ */ diff --git a/ipc/ipc_table.c b/ipc/ipc_table.c index cbb6a894..0f8592a3 100644 --- a/ipc/ipc_table.c +++ b/ipc/ipc_table.c @@ -42,20 +42,8 @@ #include <kern/slab.h> #include <vm/vm_kern.h> -/* - * Forward declarations - */ -void ipc_table_fill( - ipc_table_size_t its, - unsigned int num, - unsigned int min, - vm_size_t elemsize); - -ipc_table_size_t ipc_table_entries; -unsigned int ipc_table_entries_size = 512; - ipc_table_size_t ipc_table_dnrequests; -unsigned int ipc_table_dnrequests_size = 64; +const unsigned int ipc_table_dnrequests_size = 64; void ipc_table_fill( @@ -101,20 +89,6 @@ ipc_table_fill( void ipc_table_init(void) { - ipc_table_entries = (ipc_table_size_t) - kalloc(sizeof(struct ipc_table_size) * - ipc_table_entries_size); - assert(ipc_table_entries != ITS_NULL); - - ipc_table_fill(ipc_table_entries, ipc_table_entries_size - 1, - 4, sizeof(struct ipc_entry)); - - /* the last two elements should have the same size */ - - ipc_table_entries[ipc_table_entries_size - 1].its_size = - ipc_table_entries[ipc_table_entries_size - 2].its_size; - - ipc_table_dnrequests = (ipc_table_size_t) kalloc(sizeof(struct ipc_table_size) * ipc_table_dnrequests_size); @@ -140,42 +114,7 @@ vm_offset_t ipc_table_alloc( vm_size_t size) { - vm_offset_t table; - - if (size < PAGE_SIZE) - table = kalloc(size); - else - if (kmem_alloc(kmem_map, &table, size) != KERN_SUCCESS) - table = 0; - - return table; -} - -/* - * Routine: ipc_table_realloc - * Purpose: - * Reallocate a big table. - * - * The new table remaps the old table, - * so copying is not necessary. - * Conditions: - * Only works for page-size or bigger tables. - * May block. - */ - -vm_offset_t -ipc_table_realloc( - vm_size_t old_size, - vm_offset_t old_table, - vm_size_t new_size) -{ - vm_offset_t new_table; - - if (kmem_realloc(kmem_map, old_table, old_size, - &new_table, new_size) != KERN_SUCCESS) - new_table = 0; - - return new_table; + return kalloc(size); } /* @@ -192,8 +131,5 @@ ipc_table_free( vm_size_t size, vm_offset_t table) { - if (size < PAGE_SIZE) - kfree(table, size); - else - kmem_free(kmem_map, table, size); + kfree(table, size); } diff --git a/ipc/ipc_table.h b/ipc/ipc_table.h index 695adae4..7968e6bb 100644 --- a/ipc/ipc_table.h +++ b/ipc/ipc_table.h @@ -30,8 +30,8 @@ * Author: Rich Draves * Date: 1989 * - * Definitions for tables, used for IPC capabilities (ipc_entry_t) - * and dead-name requests (ipc_port_request_t). + * Definitions for tables, used for dead-name requests + * (ipc_port_request_t). */ #ifndef _IPC_IPC_TABLE_H_ @@ -41,20 +41,7 @@ #include <mach/vm_param.h> /* - * The is_table_next field of an ipc_space_t points to - * an ipc_table_size structure. These structures must - * be elements of an array, ipc_table_entries. - * - * The array must end with two elements with the same its_size value. - * Except for the terminating element, the its_size values must - * be strictly increasing. The largest (last) its_size value - * must be less than or equal to MACH_PORT_INDEX(MACH_PORT_DEAD). - * This ensures that - * 1) MACH_PORT_INDEX(MACH_PORT_DEAD) isn't a valid index - * in the table, so ipc_entry_get won't allocate it. - * 2) MACH_PORT_MAKE(index+1, 0) and MAKE_PORT_MAKE(size, 0) - * won't ever overflow. - * + * Every its_size value must must be a power of two. * * The ipr_size field of the first element in a table of * dead-name requests (ipc_port_request_t) points to the @@ -63,8 +50,6 @@ * with an element with zero its_size, and except for this last * element, the its_size values must be strictly increasing. * - * The is_table_next field points to the ipc_table_size structure - * for the next larger size of table, not the one currently in use. * The ipr_size field points to the currently used ipc_table_size. */ @@ -77,53 +62,31 @@ typedef struct ipc_table_size { #define ITS_NULL ((ipc_table_size_t) 0) -extern ipc_table_size_t ipc_table_entries; extern ipc_table_size_t ipc_table_dnrequests; extern void ipc_table_init(void); /* - * Note that ipc_table_alloc, ipc_table_realloc, and ipc_table_free - * all potentially use the VM system. Hence simple locks can't - * be held across them. - * - * We can't use a copying realloc, because the realloc happens - * with the data unlocked. ipc_table_realloc remaps the data, - * so it is OK. + * Note that ipc_table_alloc, and ipc_table_free all potentially + * use the VM system. Hence simple locks can't be held across + * them. */ /* Allocate a table */ extern vm_offset_t ipc_table_alloc( vm_size_t size); -/* Reallocate a big table */ -extern vm_offset_t ipc_table_realloc( - vm_size_t old_size, - vm_offset_t old_table, - vm_size_t new_size); - /* Free a table */ extern void ipc_table_free( vm_size_t size, vm_offset_t table); -#define it_entries_alloc(its) \ - ((ipc_entry_t) \ - ipc_table_alloc((its)->its_size * sizeof(struct ipc_entry))) - -#define it_entries_reallocable(its) \ - (((its)->its_size * sizeof(struct ipc_entry)) >= PAGE_SIZE) - -#define it_entries_realloc(its, table, nits) \ - ((ipc_entry_t) \ - ipc_table_realloc((its)->its_size * sizeof(struct ipc_entry), \ - (vm_offset_t)(table), \ - (nits)->its_size * sizeof(struct ipc_entry))) - -#define it_entries_free(its, table) \ - ipc_table_free((its)->its_size * sizeof(struct ipc_entry), \ - (vm_offset_t)(table)) +void ipc_table_fill( + ipc_table_size_t its, + unsigned int num, + unsigned int min, + vm_size_t elemsize); #define it_dnrequests_alloc(its) \ ((ipc_port_request_t) \ diff --git a/ipc/ipc_thread.h b/ipc/ipc_thread.h index fbeea46a..008ab4a9 100644 --- a/ipc/ipc_thread.h +++ b/ipc/ipc_thread.h @@ -75,7 +75,7 @@ MACRO_END #define ipc_thread_rmqueue_first_macro(queue, thread) \ MACRO_BEGIN \ - register ipc_thread_t _next; \ + ipc_thread_t _next; \ \ assert((queue)->ithq_base == (thread)); \ \ @@ -84,7 +84,7 @@ MACRO_BEGIN \ assert((thread)->ith_prev == (thread)); \ (queue)->ithq_base = ITH_NULL; \ } else { \ - register ipc_thread_t _prev = (thread)->ith_prev; \ + ipc_thread_t _prev = (thread)->ith_prev; \ \ (queue)->ithq_base = _next; \ _next->ith_prev = _prev; \ @@ -95,14 +95,14 @@ MACRO_END #define ipc_thread_enqueue_macro(queue, thread) \ MACRO_BEGIN \ - register ipc_thread_t _first = (queue)->ithq_base; \ + ipc_thread_t _first = (queue)->ithq_base; \ \ if (_first == ITH_NULL) { \ (queue)->ithq_base = (thread); \ assert((thread)->ith_next == (thread)); \ assert((thread)->ith_prev == (thread)); \ } else { \ - register ipc_thread_t _last = _first->ith_prev; \ + ipc_thread_t _last = _first->ith_prev; \ \ (thread)->ith_next = _first; \ (thread)->ith_prev = _last; \ diff --git a/ipc/mach_debug.c b/ipc/mach_debug.c index 28dd6935..efb07a4f 100644 --- a/ipc/mach_debug.c +++ b/ipc/mach_debug.c @@ -46,7 +46,6 @@ #include <vm/vm_kern.h> #include <ipc/ipc_space.h> #include <ipc/ipc_port.h> -#include <ipc/ipc_hash.h> #include <ipc/ipc_marequest.h> #include <ipc/ipc_table.h> #include <ipc/ipc_right.h> @@ -94,85 +93,6 @@ mach_port_get_srights( } /* - * Routine: host_ipc_hash_info - * Purpose: - * Return information about the global reverse hash table. - * Conditions: - * Nothing locked. Obeys CountInOut protocol. - * Returns: - * KERN_SUCCESS Returned information. - * KERN_INVALID_HOST The host is null. - * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. - */ - -kern_return_t -host_ipc_hash_info( - host_t host, - hash_info_bucket_array_t *infop, - mach_msg_type_number_t *countp) -{ - vm_offset_t addr; - vm_size_t size = 0; /* Suppress gcc warning */ - hash_info_bucket_t *info; - unsigned int potential, actual; - kern_return_t kr; - - if (host == HOST_NULL) - return KERN_INVALID_HOST; - - /* start with in-line data */ - - info = *infop; - potential = *countp; - - for (;;) { - actual = ipc_hash_info(info, potential); - if (actual <= potential) - break; - - /* allocate more memory */ - - if (info != *infop) - kmem_free(ipc_kernel_map, addr, size); - - size = round_page(actual * sizeof *info); - kr = kmem_alloc_pageable(ipc_kernel_map, &addr, size); - if (kr != KERN_SUCCESS) - return KERN_RESOURCE_SHORTAGE; - - info = (hash_info_bucket_t *) addr; - potential = size/sizeof *info; - } - - if (info == *infop) { - /* data fit in-line; nothing to deallocate */ - - *countp = actual; - } else if (actual == 0) { - kmem_free(ipc_kernel_map, addr, size); - - *countp = 0; - } else { - vm_map_copy_t copy; - vm_size_t used; - - used = round_page(actual * sizeof *info); - - if (used != size) - kmem_free(ipc_kernel_map, addr + used, size - used); - - kr = vm_map_copyin(ipc_kernel_map, addr, used, - TRUE, ©); - assert(kr == KERN_SUCCESS); - - *infop = (hash_info_bucket_t *) copy; - *countp = actual; - } - - return KERN_SUCCESS; -} - -/* * Routine: host_ipc_marequest_info * Purpose: * Return information about the marequest hash table. @@ -185,11 +105,11 @@ host_ipc_hash_info( */ kern_return_t -host_ipc_marequest_info(host, maxp, infop, countp) - host_t host; - unsigned int *maxp; - hash_info_bucket_array_t *infop; - unsigned int *countp; +host_ipc_marequest_info( + host_t host, + unsigned int *maxp, + hash_info_bucket_array_t *infop, + unsigned int *countp) { vm_offset_t addr; vm_size_t size = 0; /* '=0' to shut up lint */ @@ -253,251 +173,6 @@ host_ipc_marequest_info(host, maxp, infop, countp) } /* - * Routine: mach_port_space_info - * Purpose: - * Returns information about an IPC space. - * Conditions: - * Nothing locked. Obeys CountInOut protocol. - * Returns: - * KERN_SUCCESS Returned information. - * KERN_INVALID_TASK The space is null. - * KERN_INVALID_TASK The space is dead. - * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. - */ - -kern_return_t -mach_port_space_info( - ipc_space_t space, - ipc_info_space_t *infop, - ipc_info_name_array_t *tablep, - mach_msg_type_number_t *tableCntp, - ipc_info_tree_name_array_t *treep, - mach_msg_type_number_t *treeCntp) -{ - ipc_info_name_t *table_info; - unsigned int table_potential, table_actual; - vm_offset_t table_addr; - vm_size_t table_size = 0; /* Suppress gcc warning */ - ipc_info_tree_name_t *tree_info; - unsigned int tree_potential, tree_actual; - vm_offset_t tree_addr; - vm_size_t tree_size = 0; /* Suppress gcc warning */ - ipc_tree_entry_t tentry; - ipc_entry_t table; - ipc_entry_num_t tsize; - mach_port_index_t index; - kern_return_t kr; - - if (space == IS_NULL) - return KERN_INVALID_TASK; - - /* start with in-line memory */ - - table_info = *tablep; - table_potential = *tableCntp; - tree_info = *treep; - tree_potential = *treeCntp; - - for (;;) { - is_read_lock(space); - if (!space->is_active) { - is_read_unlock(space); - if (table_info != *tablep) - kmem_free(ipc_kernel_map, - table_addr, table_size); - if (tree_info != *treep) - kmem_free(ipc_kernel_map, - tree_addr, tree_size); - return KERN_INVALID_TASK; - } - - table_actual = space->is_table_size; - tree_actual = space->is_tree_total; - - if ((table_actual <= table_potential) && - (tree_actual <= tree_potential)) - break; - - is_read_unlock(space); - - if (table_actual > table_potential) { - if (table_info != *tablep) - kmem_free(ipc_kernel_map, - table_addr, table_size); - - table_size = round_page(table_actual * - sizeof *table_info); - kr = kmem_alloc(ipc_kernel_map, - &table_addr, table_size); - if (kr != KERN_SUCCESS) { - if (tree_info != *treep) - kmem_free(ipc_kernel_map, - tree_addr, tree_size); - - return KERN_RESOURCE_SHORTAGE; - } - - table_info = (ipc_info_name_t *) table_addr; - table_potential = table_size/sizeof *table_info; - } - - if (tree_actual > tree_potential) { - if (tree_info != *treep) - kmem_free(ipc_kernel_map, - tree_addr, tree_size); - - tree_size = round_page(tree_actual * - sizeof *tree_info); - kr = kmem_alloc(ipc_kernel_map, - &tree_addr, tree_size); - if (kr != KERN_SUCCESS) { - if (table_info != *tablep) - kmem_free(ipc_kernel_map, - table_addr, table_size); - - return KERN_RESOURCE_SHORTAGE; - } - - tree_info = (ipc_info_tree_name_t *) tree_addr; - tree_potential = tree_size/sizeof *tree_info; - } - } - /* space is read-locked and active; we have enough wired memory */ - - infop->iis_genno_mask = MACH_PORT_NGEN(MACH_PORT_DEAD); - infop->iis_table_size = space->is_table_size; - infop->iis_table_next = space->is_table_next->its_size; - infop->iis_tree_size = space->is_tree_total; - infop->iis_tree_small = space->is_tree_small; - infop->iis_tree_hash = space->is_tree_hash; - - table = space->is_table; - tsize = space->is_table_size; - - for (index = 0; index < tsize; index++) { - ipc_info_name_t *iin = &table_info[index]; - ipc_entry_t entry = &table[index]; - ipc_entry_bits_t bits = entry->ie_bits; - - iin->iin_name = MACH_PORT_MAKEB(index, bits); - iin->iin_collision = (bits & IE_BITS_COLLISION) ? TRUE : FALSE; - iin->iin_compat = FALSE; - iin->iin_marequest = (bits & IE_BITS_MAREQUEST) ? TRUE : FALSE; - iin->iin_type = IE_BITS_TYPE(bits); - iin->iin_urefs = IE_BITS_UREFS(bits); - iin->iin_object = (vm_offset_t) entry->ie_object; - iin->iin_next = entry->ie_next; - iin->iin_hash = entry->ie_index; - } - - for (tentry = ipc_splay_traverse_start(&space->is_tree), index = 0; - tentry != ITE_NULL; - tentry = ipc_splay_traverse_next(&space->is_tree, FALSE)) { - ipc_info_tree_name_t *iitn = &tree_info[index++]; - ipc_info_name_t *iin = &iitn->iitn_name; - ipc_entry_t entry = &tentry->ite_entry; - ipc_entry_bits_t bits = entry->ie_bits; - - assert(IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE); - - iin->iin_name = tentry->ite_name; - iin->iin_collision = (bits & IE_BITS_COLLISION) ? TRUE : FALSE; - iin->iin_compat = FALSE; - iin->iin_marequest = (bits & IE_BITS_MAREQUEST) ? TRUE : FALSE; - iin->iin_type = IE_BITS_TYPE(bits); - iin->iin_urefs = IE_BITS_UREFS(bits); - iin->iin_object = (vm_offset_t) entry->ie_object; - iin->iin_next = entry->ie_next; - iin->iin_hash = entry->ie_index; - - if (tentry->ite_lchild == ITE_NULL) - iitn->iitn_lchild = MACH_PORT_NULL; - else - iitn->iitn_lchild = tentry->ite_lchild->ite_name; - - if (tentry->ite_rchild == ITE_NULL) - iitn->iitn_rchild = MACH_PORT_NULL; - else - iitn->iitn_rchild = tentry->ite_rchild->ite_name; - - } - ipc_splay_traverse_finish(&space->is_tree); - is_read_unlock(space); - - if (table_info == *tablep) { - /* data fit in-line; nothing to deallocate */ - - *tableCntp = table_actual; - } else if (table_actual == 0) { - kmem_free(ipc_kernel_map, table_addr, table_size); - - *tableCntp = 0; - } else { - vm_size_t size_used, rsize_used; - vm_map_copy_t copy; - - /* kmem_alloc doesn't zero memory */ - - size_used = table_actual * sizeof *table_info; - rsize_used = round_page(size_used); - - if (rsize_used != table_size) - kmem_free(ipc_kernel_map, - table_addr + rsize_used, - table_size - rsize_used); - - if (size_used != rsize_used) - memset((char *) (table_addr + size_used), 0, - rsize_used - size_used); - - kr = vm_map_copyin(ipc_kernel_map, table_addr, rsize_used, - TRUE, ©); - - assert(kr == KERN_SUCCESS); - - *tablep = (ipc_info_name_t *) copy; - *tableCntp = table_actual; - } - - if (tree_info == *treep) { - /* data fit in-line; nothing to deallocate */ - - *treeCntp = tree_actual; - } else if (tree_actual == 0) { - kmem_free(ipc_kernel_map, tree_addr, tree_size); - - *treeCntp = 0; - } else { - vm_size_t size_used, rsize_used; - vm_map_copy_t copy; - - /* kmem_alloc doesn't zero memory */ - - size_used = tree_actual * sizeof *tree_info; - rsize_used = round_page(size_used); - - if (rsize_used != tree_size) - kmem_free(ipc_kernel_map, - tree_addr + rsize_used, - tree_size - rsize_used); - - if (size_used != rsize_used) - memset((char *) (tree_addr + size_used), 0, - rsize_used - size_used); - - kr = vm_map_copyin(ipc_kernel_map, tree_addr, rsize_used, - TRUE, ©); - - assert(kr == KERN_SUCCESS); - - *treep = (ipc_info_tree_name_t *) copy; - *treeCntp = tree_actual; - } - - return KERN_SUCCESS; -} - -/* * Routine: mach_port_dnrequest_info * Purpose: * Returns information about the dead-name requests @@ -603,8 +278,8 @@ mach_port_kernel_object( return KERN_INVALID_RIGHT; } - *typep = (unsigned int) ip_kotype(port); - *addrp = (vm_offset_t) port->ip_kobject; + *typep = ip_kotype(port); + *addrp = port->ip_kobject; ip_unlock(port); return KERN_SUCCESS; } diff --git a/ipc/mach_msg.c b/ipc/mach_msg.c index 00ab085b..fe0c43e3 100644 --- a/ipc/mach_msg.c +++ b/ipc/mach_msg.c @@ -46,6 +46,7 @@ #include <kern/printf.h> #include <kern/sched_prim.h> #include <kern/ipc_sched.h> +#include <kern/exception.h> #include <vm/vm_map.h> #include <ipc/ipc_kmsg.h> #include <ipc/ipc_marequest.h> @@ -61,9 +62,6 @@ #include <machine/locore.h> #include <machine/pcb.h> -extern void exception_raise_continue(); -extern void exception_raise_continue_fast(); - /* * Routine: mach_msg_send * Purpose: @@ -90,12 +88,12 @@ extern void exception_raise_continue_fast(); */ mach_msg_return_t -mach_msg_send(msg, option, send_size, time_out, notify) - mach_msg_header_t *msg; - mach_msg_option_t option; - mach_msg_size_t send_size; - mach_msg_timeout_t time_out; - mach_port_t notify; +mach_msg_send( + mach_msg_header_t *msg, + mach_msg_option_t option, + mach_msg_size_t send_size, + mach_msg_timeout_t time_out, + mach_port_t notify) { ipc_space_t space = current_space(); vm_map_t map = current_map(); @@ -172,13 +170,13 @@ mach_msg_send(msg, option, send_size, time_out, notify) */ mach_msg_return_t -mach_msg_receive(msg, option, rcv_size, rcv_name, time_out, notify) - mach_msg_header_t *msg; - mach_msg_option_t option; - mach_msg_size_t rcv_size; - mach_port_t rcv_name; - mach_msg_timeout_t time_out; - mach_port_t notify; +mach_msg_receive( + mach_msg_header_t *msg, + mach_msg_option_t option, + mach_msg_size_t rcv_size, + mach_port_t rcv_name, + mach_msg_timeout_t time_out, + mach_port_t notify) { ipc_thread_t self = current_thread(); ipc_space_t space = current_space(); @@ -381,26 +379,26 @@ mach_msg_receive_continue(void) */ mach_msg_return_t -mach_msg_trap(msg, option, send_size, rcv_size, rcv_name, time_out, notify) - mach_msg_header_t *msg; - mach_msg_option_t option; - mach_msg_size_t send_size; - mach_msg_size_t rcv_size; - mach_port_t rcv_name; - mach_msg_timeout_t time_out; - mach_port_t notify; +mach_msg_trap( + mach_msg_header_t *msg, + mach_msg_option_t option, + mach_msg_size_t send_size, + mach_msg_size_t rcv_size, + mach_port_t rcv_name, + mach_msg_timeout_t time_out, + mach_port_t notify) { mach_msg_return_t mr; /* first check for common cases */ if (option == (MACH_SEND_MSG|MACH_RCV_MSG)) { - register ipc_thread_t self = current_thread(); + ipc_thread_t self = current_thread(); ipc_space_t space = self->task->itk_space; - register ipc_kmsg_t kmsg; - register ipc_port_t dest_port; + ipc_kmsg_t kmsg; + ipc_port_t dest_port; ipc_object_t rcv_object; - register ipc_mqueue_t rcv_mqueue; + ipc_mqueue_t rcv_mqueue; mach_msg_size_t reply_size; /* @@ -484,85 +482,38 @@ mach_msg_trap(msg, option, send_size, rcv_size, rcv_name, time_out, notify) switch (kmsg->ikm_header.msgh_bits) { case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE): { - register ipc_entry_t table; - register ipc_entry_num_t size; - register ipc_port_t reply_port; - - /* sending a request message */ - + ipc_port_t reply_port; { - register mach_port_index_t index; - register mach_port_gen_t gen; - - { - register mach_port_t reply_name = + mach_port_t reply_name = kmsg->ikm_header.msgh_local_port; if (reply_name != rcv_name) goto slow_copyin; - /* optimized ipc_entry_lookup of reply_name */ - - index = MACH_PORT_INDEX(reply_name); - gen = MACH_PORT_GEN(reply_name); - } - is_read_lock(space); assert(space->is_active); - size = space->is_table_size; - table = space->is_table; - - if (index >= size) - goto abort_request_copyin; - - { - register ipc_entry_t entry; - register ipc_entry_bits_t bits; - - entry = &table[index]; - bits = entry->ie_bits; - - /* check generation number and type bit */ - - if ((bits & (IE_BITS_GEN_MASK| - MACH_PORT_TYPE_RECEIVE)) != - (gen | MACH_PORT_TYPE_RECEIVE)) + ipc_entry_t entry; + entry = ipc_entry_lookup (space, reply_name); + if (entry == IE_NULL) goto abort_request_copyin; - reply_port = (ipc_port_t) entry->ie_object; assert(reply_port != IP_NULL); } - } - - /* optimized ipc_entry_lookup of dest_name */ - - { - register mach_port_index_t index; - register mach_port_gen_t gen; { - register mach_port_t dest_name = + mach_port_t dest_name = kmsg->ikm_header.msgh_remote_port; - index = MACH_PORT_INDEX(dest_name); - gen = MACH_PORT_GEN(dest_name); - } - - if (index >= size) + ipc_entry_t entry; + ipc_entry_bits_t bits; + entry = ipc_entry_lookup (space, dest_name); + if (entry == IE_NULL) goto abort_request_copyin; - - { - register ipc_entry_t entry; - register ipc_entry_bits_t bits; - - entry = &table[index]; bits = entry->ie_bits; - /* check generation number and type bit */ - - if ((bits & (IE_BITS_GEN_MASK|MACH_PORT_TYPE_SEND)) != - (gen | MACH_PORT_TYPE_SEND)) + /* check type bits */ + if (IE_BITS_TYPE (bits) != MACH_PORT_TYPE_SEND) goto abort_request_copyin; assert(IE_BITS_UREFS(bits) > 0); @@ -570,7 +521,6 @@ mach_msg_trap(msg, option, send_size, rcv_size, rcv_name, time_out, notify) dest_port = (ipc_port_t) entry->ie_object; assert(dest_port != IP_NULL); } - } /* * To do an atomic copyin, need simultaneous @@ -651,13 +601,10 @@ mach_msg_trap(msg, option, send_size, rcv_size, rcv_name, time_out, notify) } case MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0): { - register ipc_entry_num_t size; - register ipc_entry_t table; - /* sending a reply message */ { - register mach_port_t reply_name = + mach_port_t reply_name = kmsg->ikm_header.msgh_local_port; if (reply_name != MACH_PORT_NULL) @@ -667,35 +614,18 @@ mach_msg_trap(msg, option, send_size, rcv_size, rcv_name, time_out, notify) is_write_lock(space); assert(space->is_active); - /* optimized ipc_entry_lookup */ - - size = space->is_table_size; - table = space->is_table; - - { - register ipc_entry_t entry; - register mach_port_gen_t gen; - register mach_port_index_t index; - { - register mach_port_t dest_name = + ipc_entry_t entry; + mach_port_t dest_name = kmsg->ikm_header.msgh_remote_port; - index = MACH_PORT_INDEX(dest_name); - gen = MACH_PORT_GEN(dest_name); - } - - if (index >= size) + entry = ipc_entry_lookup (space, dest_name); + if (entry == IE_NULL) goto abort_reply_dest_copyin; - entry = &table[index]; - - /* check generation, collision bit, and type bit */ - - if ((entry->ie_bits & (IE_BITS_GEN_MASK| - IE_BITS_COLLISION| - MACH_PORT_TYPE_SEND_ONCE)) != - (gen | MACH_PORT_TYPE_SEND_ONCE)) + /* check type bits */ + if (IE_BITS_TYPE (entry->ie_bits) != + MACH_PORT_TYPE_SEND_ONCE) goto abort_reply_dest_copyin; /* optimized ipc_right_copyin */ @@ -718,13 +648,8 @@ mach_msg_trap(msg, option, send_size, rcv_size, rcv_name, time_out, notify) } assert(dest_port->ip_sorights > 0); - - /* optimized ipc_entry_dealloc */ - - entry->ie_next = table->ie_next; - table->ie_next = index; - entry->ie_bits = gen; entry->ie_object = IO_NULL; + ipc_entry_dealloc (space, dest_name, entry); } kmsg->ikm_header.msgh_bits = @@ -737,35 +662,20 @@ mach_msg_trap(msg, option, send_size, rcv_size, rcv_name, time_out, notify) assert(dest_port->ip_receiver != ipc_space_kernel); - /* optimized ipc_entry_lookup/ipc_mqueue_copyin */ - - { - register ipc_entry_t entry; - register ipc_entry_bits_t bits; + /* optimized ipc_mqueue_copyin */ { - register mach_port_index_t index; - register mach_port_gen_t gen; - - index = MACH_PORT_INDEX(rcv_name); - gen = MACH_PORT_GEN(rcv_name); - - if (index >= size) + ipc_entry_t entry; + ipc_entry_bits_t bits; + entry = ipc_entry_lookup (space, rcv_name); + if (entry == IE_NULL) goto abort_reply_rcv_copyin; - - entry = &table[index]; bits = entry->ie_bits; - /* check generation number */ - - if ((bits & IE_BITS_GEN_MASK) != gen) - goto abort_reply_rcv_copyin; - } - /* check type bits; looking for receive or set */ if (bits & MACH_PORT_TYPE_PORT_SET) { - register ipc_pset_t rcv_pset; + ipc_pset_t rcv_pset; rcv_pset = (ipc_pset_t) entry->ie_object; assert(rcv_pset != IPS_NULL); @@ -776,7 +686,7 @@ mach_msg_trap(msg, option, send_size, rcv_size, rcv_name, time_out, notify) rcv_object = (ipc_object_t) rcv_pset; rcv_mqueue = &rcv_pset->ips_messages; } else if (bits & MACH_PORT_TYPE_RECEIVE) { - register ipc_port_t rcv_port; + ipc_port_t rcv_port; rcv_port = (ipc_port_t) entry->ie_object; assert(rcv_port != IP_NULL); @@ -841,11 +751,11 @@ mach_msg_trap(msg, option, send_size, rcv_size, rcv_name, time_out, notify) MACH_MSGH_BITS_CIRCULAR) == 0); { - register ipc_mqueue_t dest_mqueue; - register ipc_thread_t receiver; + ipc_mqueue_t dest_mqueue; + ipc_thread_t receiver; { - register ipc_pset_t dest_pset; + ipc_pset_t dest_pset; dest_pset = dest_port->ip_pset; if (dest_pset == IPS_NULL) @@ -1043,6 +953,7 @@ mach_msg_trap(msg, option, send_size, rcv_size, rcv_name, time_out, notify) ipc_port_t reply_port = (ipc_port_t) kmsg->ikm_header.msgh_local_port; mach_port_t dest_name, reply_name; + unsigned long payload; /* receiving a request message */ @@ -1074,30 +985,19 @@ mach_msg_trap(msg, option, send_size, rcv_size, rcv_name, time_out, notify) ip_unlock(reply_port); { - register ipc_entry_t table; - register ipc_entry_t entry; - register mach_port_index_t index; - - /* optimized ipc_entry_get */ - - table = space->is_table; - index = table->ie_next; - - if (index == 0) + ipc_entry_t entry; + kern_return_t kr; + kr = ipc_entry_get (space, &reply_name, &entry); + if (kr) goto abort_request_copyout; - - entry = &table[index]; - table->ie_next = entry->ie_next; - entry->ie_request = 0; + assert (entry != NULL); { - register mach_port_gen_t gen; + mach_port_gen_t gen; assert((entry->ie_bits &~ IE_BITS_GEN_MASK) == 0); gen = entry->ie_bits + IE_BITS_GEN_ONE; - reply_name = MACH_PORT_MAKE(index, gen); - /* optimized ipc_right_copyout */ entry->ie_bits = gen | (MACH_PORT_TYPE_SEND_ONCE | 1); @@ -1117,6 +1017,7 @@ mach_msg_trap(msg, option, send_size, rcv_size, rcv_name, time_out, notify) dest_name = dest_port->ip_receiver_name; else dest_name = MACH_PORT_NULL; + payload = dest_port->ip_protected_payload; if ((--dest_port->ip_srights == 0) && (dest_port->ip_nsrequest != IP_NULL)) { @@ -1134,11 +1035,19 @@ mach_msg_trap(msg, option, send_size, rcv_size, rcv_name, time_out, notify) } else ip_unlock(dest_port); - kmsg->ikm_header.msgh_bits = - MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, - MACH_MSG_TYPE_PORT_SEND); + if (! ipc_port_flag_protected_payload(dest_port)) { + kmsg->ikm_header.msgh_bits = MACH_MSGH_BITS( + MACH_MSG_TYPE_PORT_SEND_ONCE, + MACH_MSG_TYPE_PORT_SEND); + kmsg->ikm_header.msgh_local_port = dest_name; + } else { + kmsg->ikm_header.msgh_bits = MACH_MSGH_BITS( + MACH_MSG_TYPE_PORT_SEND_ONCE, + MACH_MSG_TYPE_PROTECTED_PAYLOAD); + kmsg->ikm_header.msgh_protected_payload = + payload; + } kmsg->ikm_header.msgh_remote_port = reply_name; - kmsg->ikm_header.msgh_local_port = dest_name; goto fast_put; abort_request_copyout: @@ -1148,7 +1057,8 @@ mach_msg_trap(msg, option, send_size, rcv_size, rcv_name, time_out, notify) } case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0): { - register mach_port_t dest_name; + mach_port_t dest_name; + unsigned long payload; /* receiving a reply message */ @@ -1160,6 +1070,8 @@ mach_msg_trap(msg, option, send_size, rcv_size, rcv_name, time_out, notify) assert(dest_port->ip_sorights > 0); + payload = dest_port->ip_protected_payload; + if (dest_port->ip_receiver == space) { ip_release(dest_port); dest_port->ip_sorights--; @@ -1172,17 +1084,26 @@ mach_msg_trap(msg, option, send_size, rcv_size, rcv_name, time_out, notify) dest_name = MACH_PORT_NULL; } - kmsg->ikm_header.msgh_bits = - MACH_MSGH_BITS(0, - MACH_MSG_TYPE_PORT_SEND_ONCE); + if (! ipc_port_flag_protected_payload(dest_port)) { + kmsg->ikm_header.msgh_bits = MACH_MSGH_BITS( + 0, + MACH_MSG_TYPE_PORT_SEND_ONCE); + kmsg->ikm_header.msgh_local_port = dest_name; + } else { + kmsg->ikm_header.msgh_bits = MACH_MSGH_BITS( + 0, + MACH_MSG_TYPE_PROTECTED_PAYLOAD); + kmsg->ikm_header.msgh_protected_payload = + payload; + } kmsg->ikm_header.msgh_remote_port = MACH_PORT_NULL; - kmsg->ikm_header.msgh_local_port = dest_name; goto fast_put; } case MACH_MSGH_BITS_COMPLEX| MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0): { - register mach_port_t dest_name; + mach_port_t dest_name; + unsigned long payload; /* receiving a complex reply message */ @@ -1194,6 +1115,8 @@ mach_msg_trap(msg, option, send_size, rcv_size, rcv_name, time_out, notify) assert(dest_port->ip_sorights > 0); + payload = dest_port->ip_protected_payload; + if (dest_port->ip_receiver == space) { ip_release(dest_port); dest_port->ip_sorights--; @@ -1206,12 +1129,23 @@ mach_msg_trap(msg, option, send_size, rcv_size, rcv_name, time_out, notify) dest_name = MACH_PORT_NULL; } - kmsg->ikm_header.msgh_bits = - MACH_MSGH_BITS_COMPLEX | - MACH_MSGH_BITS(0, - MACH_MSG_TYPE_PORT_SEND_ONCE); + if (! ipc_port_flag_protected_payload(dest_port)) { + kmsg->ikm_header.msgh_bits = + MACH_MSGH_BITS_COMPLEX + | MACH_MSGH_BITS( + 0, + MACH_MSG_TYPE_PORT_SEND_ONCE); + kmsg->ikm_header.msgh_local_port = dest_name; + } else { + kmsg->ikm_header.msgh_bits = + MACH_MSGH_BITS_COMPLEX + | MACH_MSGH_BITS( + 0, + MACH_MSG_TYPE_PROTECTED_PAYLOAD); + kmsg->ikm_header.msgh_protected_payload = + payload; + } kmsg->ikm_header.msgh_remote_port = MACH_PORT_NULL; - kmsg->ikm_header.msgh_local_port = dest_name; mr = ipc_kmsg_copyout_body( (vm_offset_t) (&kmsg->ikm_header + 1), @@ -1322,7 +1256,7 @@ mach_msg_trap(msg, option, send_size, rcv_size, rcv_name, time_out, notify) * It will work if this is a request message. */ - register ipc_port_t reply_port; + ipc_port_t reply_port; reply_port = (ipc_port_t) kmsg->ikm_header.msgh_local_port; @@ -1357,7 +1291,7 @@ mach_msg_trap(msg, option, send_size, rcv_size, rcv_name, time_out, notify) */ { - register ipc_port_t reply_port; + ipc_port_t reply_port; /* * Perform the kernel function. @@ -1735,8 +1669,7 @@ mach_msg_continue(void) */ boolean_t -mach_msg_interrupt(thread) - thread_t thread; +mach_msg_interrupt(thread_t thread) { ipc_mqueue_t mqueue; diff --git a/ipc/mach_port.c b/ipc/mach_port.c index d0310b55..93a1248f 100644 --- a/ipc/mach_port.c +++ b/ipc/mach_port.c @@ -150,10 +150,6 @@ mach_port_names( mach_port_type_t **typesp, mach_msg_type_number_t *typesCnt) { - ipc_tree_entry_t tentry; - ipc_entry_t table; - ipc_entry_num_t tsize; - mach_port_index_t index; ipc_entry_num_t actual; /* this many names */ ipc_port_timestamp_t timestamp; /* logical time of this operation */ mach_port_t *names; @@ -190,7 +186,7 @@ mach_port_names( /* upper bound on number of names in the space */ - bound = space->is_table_size + space->is_tree_total; + bound = space->is_size; size_needed = round_page(bound * sizeof(mach_port_t)); if (size_needed <= size) @@ -235,33 +231,16 @@ mach_port_names( timestamp = ipc_port_timestamp(); - table = space->is_table; - tsize = space->is_table_size; - - for (index = 0; index < tsize; index++) { - ipc_entry_t entry = &table[index]; + ipc_entry_t entry; + struct rdxtree_iter iter; + rdxtree_for_each(&space->is_map, &iter, entry) { ipc_entry_bits_t bits = entry->ie_bits; if (IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE) { - mach_port_t name = MACH_PORT_MAKEB(index, bits); - - mach_port_names_helper(timestamp, entry, name, + mach_port_names_helper(timestamp, entry, entry->ie_name, names, types, &actual); } } - - for (tentry = ipc_splay_traverse_start(&space->is_tree); - tentry != ITE_NULL; - tentry = ipc_splay_traverse_next(&space->is_tree, FALSE)) { - ipc_entry_t entry = &tentry->ite_entry; - mach_port_t name = tentry->ite_name; - - assert(IE_BITS_TYPE(tentry->ite_bits) != MACH_PORT_TYPE_NONE); - - mach_port_names_helper(timestamp, entry, name, - names, types, &actual); - } - ipc_splay_traverse_finish(&space->is_tree); is_read_unlock(space); if (actual == 0) { @@ -434,10 +413,10 @@ mach_port_rename( */ kern_return_t -mach_port_allocate_name(space, right, name) - ipc_space_t space; - mach_port_right_t right; - mach_port_t name; +mach_port_allocate_name( + ipc_space_t space, + mach_port_right_t right, + mach_port_t name) { kern_return_t kr; @@ -497,10 +476,10 @@ mach_port_allocate_name(space, right, name) */ kern_return_t -mach_port_allocate(space, right, namep) - ipc_space_t space; - mach_port_right_t right; - mach_port_t *namep; +mach_port_allocate( + ipc_space_t space, + mach_port_right_t right, + mach_port_t *namep) { kern_return_t kr; @@ -555,7 +534,7 @@ mach_port_allocate(space, right, namep) * KERN_INVALID_NAME The name doesn't denote a right. */ -static volatile int mach_port_deallocate_debug = 0; +static volatile boolean_t mach_port_deallocate_debug = FALSE; kern_return_t mach_port_destroy( @@ -570,8 +549,8 @@ mach_port_destroy( kr = ipc_right_lookup_write(space, name, &entry); if (kr != KERN_SUCCESS) { - if (name != MACH_PORT_NULL && name != MACH_PORT_DEAD && space == current_space()) { - printf("task %p destroying an invalid port %lu, most probably a bug.\n", current_task(), name); + if (MACH_PORT_VALID (name) && space == current_space()) { + printf("task %.*s destroying a bogus port %lu, most probably a bug.\n", sizeof current_task()->name, current_task()->name, name); if (mach_port_deallocate_debug) SoftDebugger("mach_port_deallocate"); } @@ -614,8 +593,8 @@ mach_port_deallocate( kr = ipc_right_lookup_write(space, name, &entry); if (kr != KERN_SUCCESS) { - if (name != MACH_PORT_NULL && name != MACH_PORT_DEAD && space == current_space()) { - printf("task %p deallocating an invalid port %lu, most probably a bug.\n", current_task(), name); + if (MACH_PORT_VALID (name) && space == current_space()) { + printf("task %.*s deallocating a bogus port %lu, most probably a bug.\n", sizeof current_task()->name, current_task()->name, name); if (mach_port_deallocate_debug) SoftDebugger("mach_port_deallocate"); } @@ -735,8 +714,19 @@ mach_port_mod_refs( return KERN_INVALID_VALUE; kr = ipc_right_lookup_write(space, name, &entry); - if (kr != KERN_SUCCESS) + if (kr != KERN_SUCCESS) { + if (MACH_PORT_VALID (name) && space == current_space()) { + printf("task %.*s %screasing a bogus port " + "%lu by %d, most probably a bug.\n", + sizeof current_task()->name, + current_task()->name, + delta < 0 ? "de" : "in", name, + delta < 0 ? -delta : delta); + if (mach_port_deallocate_debug) + SoftDebugger("mach_port_mod_refs"); + } return kr; + } /* space is write-locked and active */ kr = ipc_right_delta(space, name, entry, right, delta); /* unlocks */ @@ -744,48 +734,6 @@ mach_port_mod_refs( } /* - * Routine: old_mach_port_get_receive_status [kernel call] - * Purpose: - * Compatibility for code written before sequence numbers. - * Retrieves mucho info about a receive right. - * Conditions: - * Nothing locked. - * Returns: - * KERN_SUCCESS Retrieved status. - * KERN_INVALID_TASK The space is null. - * KERN_INVALID_TASK The space is dead. - * KERN_INVALID_NAME The name doesn't denote a right. - * KERN_INVALID_RIGHT Name doesn't denote receive rights. - */ - -kern_return_t -mach_port_get_receive_status(ipc_space_t, mach_port_t, mach_port_status_t *); -kern_return_t -old_mach_port_get_receive_status(space, name, statusp) - ipc_space_t space; - mach_port_t name; - old_mach_port_status_t *statusp; -{ - mach_port_status_t status; - kern_return_t kr; - - kr = mach_port_get_receive_status(space, name, &status); - if (kr != KERN_SUCCESS) - return kr; - - statusp->mps_pset = status.mps_pset; - statusp->mps_mscount = status.mps_mscount; - statusp->mps_qlimit = status.mps_qlimit; - statusp->mps_msgcount = status.mps_msgcount; - statusp->mps_sorights = status.mps_sorights; - statusp->mps_srights = status.mps_srights; - statusp->mps_pdrequest = status.mps_pdrequest; - statusp->mps_nsrequest = status.mps_nsrequest; - - return KERN_SUCCESS; -} - -/* * Routine: mach_port_set_qlimit [kernel call] * Purpose: * Changes a receive right's queue limit. @@ -803,10 +751,10 @@ old_mach_port_get_receive_status(space, name, statusp) */ kern_return_t -mach_port_set_qlimit(space, name, qlimit) - ipc_space_t space; - mach_port_t name; - mach_port_msgcount_t qlimit; +mach_port_set_qlimit( + ipc_space_t space, + mach_port_t name, + mach_port_msgcount_t qlimit) { ipc_port_t port; kern_return_t kr; @@ -977,10 +925,7 @@ mach_port_get_set_status( size = PAGE_SIZE; /* initial guess */ for (;;) { - ipc_tree_entry_t tentry; - ipc_entry_t entry, table; - ipc_entry_num_t tsize; - mach_port_index_t index; + ipc_entry_t entry; mach_port_t *names; ipc_pset_t pset; @@ -1017,11 +962,9 @@ mach_port_get_set_status( maxnames = size / sizeof(mach_port_t); actual = 0; - table = space->is_table; - tsize = space->is_table_size; - - for (index = 0; index < tsize; index++) { - ipc_entry_t ientry = &table[index]; + ipc_entry_t ientry; + struct rdxtree_iter iter; + rdxtree_for_each(&space->is_map, &iter, ientry) { ipc_entry_bits_t bits = ientry->ie_bits; if (bits & MACH_PORT_TYPE_RECEIVE) { @@ -1033,22 +976,6 @@ mach_port_get_set_status( } } - for (tentry = ipc_splay_traverse_start(&space->is_tree); - tentry != ITE_NULL; - tentry = ipc_splay_traverse_next(&space->is_tree,FALSE)) { - ipc_entry_bits_t bits = tentry->ite_bits; - - assert(IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE); - - if (bits & MACH_PORT_TYPE_RECEIVE) { - ipc_port_t port = - (ipc_port_t) tentry->ite_object; - - mach_port_gst_helper(pset, port, maxnames, - names, &actual); - } - } - ipc_splay_traverse_finish(&space->is_tree); is_read_unlock(space); if (actual <= maxnames) @@ -1367,10 +1294,10 @@ mach_port_extract_right( */ kern_return_t -mach_port_get_receive_status(space, name, statusp) - ipc_space_t space; - mach_port_t name; - mach_port_status_t *statusp; +mach_port_get_receive_status( + ipc_space_t space, + mach_port_t name, + mach_port_status_t *statusp) { ipc_port_t port; kern_return_t kr; @@ -1421,11 +1348,11 @@ mach_port_get_receive_status(space, name, statusp) #ifdef MIGRATING_THREADS kern_return_t -mach_port_set_rpcinfo(space, name, rpc_info, rpc_info_count) - ipc_space_t space; - mach_port_t name; - void *rpc_info; - unsigned int rpc_info_count; +mach_port_set_rpcinfo( + ipc_space_t space, + mach_port_t name, + void *rpc_info, + unsigned int rpc_info_count) { ipc_target_t target; ipc_object_t object; @@ -1459,19 +1386,19 @@ mach_port_set_rpcinfo(space, name, rpc_info, rpc_info_count) int sacts, maxsacts; #endif -sact_count() +void sact_count(void) { printf("%d server activations in use, %d max\n", sacts, maxsacts); } kern_return_t -mach_port_create_act(task, name, user_stack, user_rbuf, user_rbuf_size, out_act) - task_t task; - mach_port_t name; - vm_offset_t user_stack; - vm_offset_t user_rbuf; - vm_size_t user_rbuf_size; - Act **out_act; +mach_port_create_act( + task_t task, + mach_port_t name, + vm_offset_t user_stack, + vm_offset_t user_rbuf, + vm_size_t user_rbuf_size, + Act **out_act) { ipc_target_t target; ipc_space_t space; @@ -1538,12 +1465,11 @@ mach_port_create_act(task, name, user_stack, user_rbuf, user_rbuf_size, out_act) #ifdef RPCKERNELSIG kern_return_t -mach_port_set_syscall_right(task, name) - task_t task; - mach_port_t name; +mach_port_set_syscall_right( + task_t task, + mach_port_t name) { ipc_entry_t entry; - ipc_port_t port; kern_return_t kr; if (task == IS_NULL) @@ -1567,3 +1493,76 @@ mach_port_set_syscall_right(task, name) } #endif #endif /* MIGRATING_THREADS */ + +/* + * Routine: mach_port_set_protected_payload [kernel call] + * Purpose: + * Changes a receive right's protected payload. + * Conditions: + * Nothing locked. + * Returns: + * KERN_SUCCESS Set protected payload. + * KERN_INVALID_TASK The space is null. + * KERN_INVALID_TASK The space is dead. + * KERN_INVALID_NAME The name doesn't denote a right. + * KERN_INVALID_RIGHT Name doesn't denote receive rights. + */ + +kern_return_t +mach_port_set_protected_payload( + ipc_space_t space, + mach_port_t name, + unsigned long payload) +{ + ipc_port_t port; + kern_return_t kr; + + if (space == IS_NULL) + return KERN_INVALID_TASK; + + kr = ipc_port_translate_receive(space, name, &port); + if (kr != KERN_SUCCESS) + return kr; + /* port is locked and active */ + + ipc_port_set_protected_payload(port, payload); + + ip_unlock(port); + return KERN_SUCCESS; +} + +/* + * Routine: mach_port_clear_protected_payload [kernel call] + * Purpose: + * Clears a receive right's protected payload. + * Conditions: + * Nothing locked. + * Returns: + * KERN_SUCCESS Clear protected payload. + * KERN_INVALID_TASK The space is null. + * KERN_INVALID_TASK The space is dead. + * KERN_INVALID_NAME The name doesn't denote a right. + * KERN_INVALID_RIGHT Name doesn't denote receive rights. + */ + +kern_return_t +mach_port_clear_protected_payload( + ipc_space_t space, + mach_port_t name) +{ + ipc_port_t port; + kern_return_t kr; + + if (space == IS_NULL) + return KERN_INVALID_TASK; + + kr = ipc_port_translate_receive(space, name, &port); + if (kr != KERN_SUCCESS) + return kr; + /* port is locked and active */ + + ipc_port_clear_protected_payload(port); + + ip_unlock(port); + return KERN_SUCCESS; +} diff --git a/ipc/mach_port.h b/ipc/mach_port.h index a82228fe..c4d9a1c3 100644 --- a/ipc/mach_port.h +++ b/ipc/mach_port.h @@ -43,6 +43,11 @@ mach_port_allocate ( mach_port_t *namep); extern kern_return_t +mach_port_destroy( + ipc_space_t space, + mach_port_t name); + +extern kern_return_t mach_port_deallocate( ipc_space_t space, mach_port_t name); @@ -54,4 +59,10 @@ mach_port_insert_right( ipc_port_t poly, mach_msg_type_name_t polyPoly); +kern_return_t +mach_port_get_receive_status( + ipc_space_t space, + mach_port_t name, + mach_port_status_t *statusp); + #endif /* _IPC_MACH_PORT_H_ */ diff --git a/ipc/mach_rpc.c b/ipc/mach_rpc.c index 7f5b2eb2..6ca46cc9 100644 --- a/ipc/mach_rpc.c +++ b/ipc/mach_rpc.c @@ -58,9 +58,10 @@ * info to the other side. */ kern_return_t -mach_port_rpc_copy(portp, sact, dact) - struct rpc_port_desc *portp; - struct Act *sact, *dact; +mach_port_rpc_copy( + struct rpc_port_desc *portp, + struct Act *sact, + struct Act *dact) { ipc_space_t sspace, dspace; mach_msg_type_name_t tname; @@ -141,7 +142,7 @@ mach_port_rpc_copy(portp, sact, dact) } kern_return_t -mach_port_rpc_sig(space, name, buffer, buflen) +mach_port_rpc_sig(const ipc_space_t space, const char *name, const char *buffer, unsigned int buflen) { return KERN_FAILURE; } diff --git a/ipc/notify.defs b/ipc/notify.defs new file mode 100644 index 00000000..db059b8d --- /dev/null +++ b/ipc/notify.defs @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2015 Free Software Foundation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* We use custom functions to send notifications. These functions can + be found in `ipc_notify.c'. We use this file merely to produce the + list of message ids. */ + +#include <mach/notify.defs> @@ -29,7 +29,7 @@ /* */ /* - * File: ipc/ipc_port.h + * File: ipc/port.h * Author: Rich Draves * Date: 1989 * @@ -45,10 +45,7 @@ * mach_port_t must be an unsigned type. Port values * have two parts, a generation number and an index. * These macros encapsulate all knowledge of how - * a mach_port_t is layed out. However, ipc/ipc_entry.c - * implicitly assumes when it uses the splay tree functions - * that the generation number is in the low bits, so that - * names are ordered first by index and then by generation. + * a mach_port_t is laid out. * * If the size of generation numbers changes, * be sure to update IE_BITS_GEN_MASK and friends |