summaryrefslogtreecommitdiff
path: root/debian/patches/0005-ipc-replace-the-IPC-table-with-a-radix-tree.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/0005-ipc-replace-the-IPC-table-with-a-radix-tree.patch')
-rw-r--r--debian/patches/0005-ipc-replace-the-IPC-table-with-a-radix-tree.patch855
1 files changed, 0 insertions, 855 deletions
diff --git a/debian/patches/0005-ipc-replace-the-IPC-table-with-a-radix-tree.patch b/debian/patches/0005-ipc-replace-the-IPC-table-with-a-radix-tree.patch
deleted file mode 100644
index 2264083..0000000
--- a/debian/patches/0005-ipc-replace-the-IPC-table-with-a-radix-tree.patch
+++ /dev/null
@@ -1,855 +0,0 @@
-From fed1a9ce424fe6268568e6ae6e68fd5dba6797f5 Mon Sep 17 00:00:00 2001
-From: Justus Winter <4winter@informatik.uni-hamburg.de>
-Date: Fri, 20 Mar 2015 00:21:14 +0100
-Subject: [PATCH gnumach 5/7] ipc: replace the IPC table with a radix tree
-
-Currently, the port names are mapped to an IPC object (e.g. a port)
-using a table. This, however, requires large chunks of continuous
-memory, and leads to scalability problems as virtual kernel memory is
-a scarce resource. To avoid excessive overhead, non-contiguous port
-names are spilled into a splay tree.
-
-Replace the IPC table with a radix tree. As the radix tree is able to
-store non-contiguous names with reasonable overhead, we can drop the
-splay tree as well.
-
-* ipc/ipc_entry.c (ipc_entry_cache): New variable.
-(ipc_entry_lookup): Replace with a radix tree lookup.
-(ipc_entry_get): The free list handling is changed a little. Adopt
-accordingly.
-(ipc_entry_free_name): New function.
-(ipc_entry_alloc): Adopt accordingly.
-(ipc_entry_alloc_name): Likewise.
-(ipc_entry_dealloc): Likewise.
-* ipc/ipc_entry.h (struct ipc_entry): Update comment, add field for
-free list.
-(ipc_entry_cache, ie_alloc, ie_free): New declarations.
-* ipc/ipc_hash.c: We no longer use splay trees, so we do not need the
-global reverse hash table.
-* ipc/ipc_init.c (ipc_bootstrap): Initialize `ipc_entry' cache.
-* ipc/ipc_kmsg.c (ipc_kmsg_copyout_header): Use `ipc_entry_alloc'
-instead of re-coding it.
-* ipc/ipc_object.c (ipc_object_copyout): Likewise.
-(ipc_object_copyout_multiname): Likewise.
-* ipc/ipc_space.c (ipc_space_create): Initialize radix tree and free list.
-(ipc_space_destroy): Free ipc entries and radix tree.
-* ipc/ipc_space.h (struct ipc_space): Add radix tree, free list, and size.
----
- ipc/ipc_entry.c | 373 ++++++++++++++++---------------------------------------
- ipc/ipc_entry.h | 11 +-
- ipc/ipc_hash.c | 23 +---
- ipc/ipc_init.c | 3 +
- ipc/ipc_kmsg.c | 24 ++--
- ipc/ipc_object.c | 22 +---
- ipc/ipc_space.c | 42 +++----
- ipc/ipc_space.h | 8 +-
- 8 files changed, 163 insertions(+), 343 deletions(-)
-
-diff --git a/ipc/ipc_entry.c b/ipc/ipc_entry.c
-index 5b9fd98..dfef3cf 100644
---- a/ipc/ipc_entry.c
-+++ b/ipc/ipc_entry.c
-@@ -51,6 +51,8 @@
- #include <ipc/ipc_table.h>
- #include <ipc/ipc_object.h>
-
-+struct kmem_cache ipc_entry_cache;
-+
- struct kmem_cache ipc_tree_entry_cache;
-
- /*
-@@ -69,6 +71,7 @@ ipc_entry_tree_collision(
- ipc_space_t space,
- mach_port_t name)
- {
-+ assert(!"reached");
- mach_port_index_t index;
- mach_port_t lower, upper;
-
-@@ -100,29 +103,13 @@ ipc_entry_lookup(
- 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);
--
-+ 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;
- }
-@@ -145,21 +132,18 @@ ipc_entry_get(
- 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)
-+ /* Get entry from the free list. */
-+ free_entry = space->is_free_list;
-+ if (free_entry == IE_NULL)
- return KERN_NO_SPACE;
-
-- free_entry = &table[first_free];
-- table->ie_next = free_entry->ie_next;
-+ space->is_free_list = free_entry->ie_next_free;
-+ space->is_free_list_size -= 1;
-
- /*
- * Initialize the new entry. We need only
-@@ -173,7 +157,7 @@ ipc_entry_get(
- 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);
-+ new_name = MACH_PORT_MAKE(free_entry->ie_name, gen);
- }
-
- /*
-@@ -186,6 +170,7 @@ ipc_entry_get(
- 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;
-@@ -212,23 +197,44 @@ ipc_entry_alloc(
- ipc_entry_t *entryp)
- {
- kern_return_t kr;
-+ ipc_entry_t entry;
-+ rdxtree_key_t key;
-
- is_write_lock(space);
-
-- for (;;) {
-- if (!space->is_active) {
-- is_write_unlock(space);
-- return KERN_INVALID_TASK;
-- }
-+ if (!space->is_active) {
-+ is_write_unlock(space);
-+ return KERN_INVALID_TASK;
-+ }
-+
-+ kr = ipc_entry_get(space, namep, entryp);
-+ if (kr == KERN_SUCCESS)
-+ /* Success. Space is write-locked. */
-+ return kr;
-
-- kr = ipc_entry_get(space, namep, entryp);
-- if (kr == KERN_SUCCESS)
-- return kr;
-+ entry = ie_alloc();
-+ if (entry == IE_NULL) {
-+ is_write_unlock(space);
-+ 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) {
-+ is_write_unlock(space);
-+ 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;
-+ /* Success. Space is write-locked. */
-+ return KERN_SUCCESS;
- }
-
- /*
-@@ -252,166 +258,80 @@ ipc_entry_alloc_name(
- mach_port_t name,
- ipc_entry_t *entryp)
- {
-+ kern_return_t kr;
- 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;
-
-+ ipc_entry_t entry, e, *prevp;
-+ void **slot;
- assert(MACH_PORT_VALID(name));
-
--
- 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_active) {
-+ is_write_unlock(space);
-+ return KERN_INVALID_TASK;
-+ }
-
-- 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) {
-+ is_write_unlock(space);
-+ return KERN_RESOURCE_SHORTAGE;
- }
-
-- its = space->is_table_next;
-+ entry->ie_bits = 0;
-+ entry->ie_object = IO_NULL;
-+ entry->ie_request = 0;
-+ entry->ie_name = name;
-
-- /*
-- * 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.
-- */
--
-- 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);
-+ is_write_unlock(space);
-+ ie_free(entry);
- return kr;
- }
--
-- continue;
- }
-+ space->is_size += 1;
-
-- /*
-- * If a splay-tree entry was allocated previously,
-- * go ahead and insert it into the tree.
-- */
-+ *entryp = entry;
-+ /* Success. Space is write-locked. */
-+ return KERN_SUCCESS;
-+ }
-
-- if (tree_entry != ITE_NULL) {
-- space->is_tree_total++;
-+ if (IE_BITS_TYPE(entry->ie_bits)) {
-+ /* Used entry. */
-+ *entryp = entry;
-+ /* Success. Space is write-locked. */
-+ return KERN_SUCCESS;
-+ }
-
-- 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++;
-+ /* 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;
-
-- ipc_splay_tree_insert(&space->is_tree,
-- name, tree_entry);
-+ *prevp = entry->ie_next_free;
-+ space->is_free_list_size -= 1;
-
-- 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;
-- }
--
-- /*
-- * Allocate a tree entry and try again.
-- */
-+ entry->ie_bits = gen;
-+ assert(entry->ie_object == IO_NULL);
-+ assert(entry->ie_name == name);
-+ entry->ie_request = 0;
-
-- is_write_unlock(space);
-- tree_entry = ite_alloc();
-- if (tree_entry == ITE_NULL)
-- return KERN_RESOURCE_SHORTAGE;
-- is_write_lock(space);
-- }
-+ space->is_size += 1;
-+ *entryp = entry;
-+ /* Success. Space is write-locked. */
-+ return KERN_SUCCESS;
- }
-
- /*
-@@ -429,100 +349,20 @@ ipc_entry_dealloc(
- 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;
-- }
-+ 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 {
-- 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--;
-- }
-+ rdxtree_remove(&space->is_map, (rdxtree_key_t) name);
-+ ie_free(entry);
- }
-+ space->is_size -= 1;
- }
-
- /*
-@@ -544,6 +384,7 @@ ipc_entry_dealloc(
- kern_return_t
- ipc_entry_grow_table(ipc_space_t space)
- {
-+ assert(!"reached");
- ipc_entry_num_t osize, size, nsize;
-
- do {
-diff --git a/ipc/ipc_entry.h b/ipc/ipc_entry.h
-index 0caa70b..09e1223 100644
---- a/ipc/ipc_entry.h
-+++ b/ipc/ipc_entry.h
-@@ -56,10 +56,7 @@
- *
- * 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.
-+ * The ie_next_free field links free entries into a free list.
- */
-
- typedef unsigned int ipc_entry_bits_t;
-@@ -69,6 +66,7 @@ typedef struct ipc_entry {
- ipc_entry_bits_t ie_bits;
- struct ipc_object *ie_object;
- union {
-+ struct ipc_entry *next_free;
- mach_port_index_t next;
- /*XXX ipc_port_request_index_t request;*/
- unsigned int request;
-@@ -84,6 +82,8 @@ typedef struct ipc_entry {
- #define ie_request index.request
- #define ie_next index.next
- #define ie_index hash.table
-+#define ie_name 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)
-@@ -129,6 +129,9 @@ 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 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 ipc_entry_t
- ipc_entry_lookup(ipc_space_t space, mach_port_t name);
-diff --git a/ipc/ipc_hash.c b/ipc/ipc_hash.c
-index 87952a7..682b854 100644
---- a/ipc/ipc_hash.c
-+++ b/ipc/ipc_hash.c
-@@ -70,10 +70,7 @@ ipc_hash_lookup(
- 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)));
-+ return ipc_hash_local_lookup(space, obj, namep, entryp);
- }
-
- /*
-@@ -95,12 +92,7 @@ ipc_hash_insert(
- 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);
-+ ipc_hash_local_insert(space, obj, index, entry);
- }
-
- /*
-@@ -121,12 +113,7 @@ ipc_hash_delete(
- 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);
-+ ipc_hash_local_delete(space, obj, index, entry);
- }
-
- /*
-@@ -174,6 +161,7 @@ ipc_hash_global_lookup(
- mach_port_t *namep,
- ipc_tree_entry_t *entryp)
- {
-+ assert(!"reached");
- ipc_hash_global_bucket_t bucket;
- ipc_tree_entry_t this, *last;
-
-@@ -227,6 +215,7 @@ ipc_hash_global_insert(
- mach_port_t name,
- ipc_tree_entry_t entry)
- {
-+ assert(!"reached");
- ipc_hash_global_bucket_t bucket;
-
-
-@@ -265,6 +254,7 @@ ipc_hash_global_delete(
- mach_port_t name,
- ipc_tree_entry_t entry)
- {
-+ assert(!"reached");
- ipc_hash_global_bucket_t bucket;
- ipc_tree_entry_t this, *last;
-
-@@ -307,7 +297,6 @@ ipc_hash_global_delete(
- IE_BITS_TYPE((E)->ie_bits) == MACH_PORT_TYPE_NONE); \
- assert((E)->ie_object == (O)); \
- assert((E)->ie_index == (N)); \
-- assert(&(S)->is_table[N] == (E)); \
- MACRO_END
-
- /*
-diff --git a/ipc/ipc_init.c b/ipc/ipc_init.c
-index debda47..096e0fb 100644
---- a/ipc/ipc_init.c
-+++ b/ipc/ipc_init.c
-@@ -79,6 +79,9 @@ ipc_bootstrap(void)
- 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);
-
-diff --git a/ipc/ipc_kmsg.c b/ipc/ipc_kmsg.c
-index cae700f..03f07a0 100644
---- a/ipc/ipc_kmsg.c
-+++ b/ipc/ipc_kmsg.c
-@@ -2003,28 +2003,20 @@ ipc_kmsg_copyout_header(
- 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)
-diff --git a/ipc/ipc_object.c b/ipc/ipc_object.c
-index db6ef01..ec40062 100644
---- a/ipc/ipc_object.c
-+++ b/ipc/ipc_object.c
-@@ -630,15 +630,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);
-@@ -691,15 +686,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);
-diff --git a/ipc/ipc_space.c b/ipc/ipc_space.c
-index dcc96b3..5f939bb 100644
---- a/ipc/ipc_space.c
-+++ b/ipc/ipc_space.c
-@@ -82,6 +82,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:
-@@ -148,7 +151,13 @@ ipc_space_create(
- 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;
-@@ -218,30 +227,12 @@ 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.
-- */
--
-- 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.
-- */
-+ ipc_entry_t entry;
-+ struct rdxtree_iter iter;
-+ rdxtree_for_each(&space->is_map, &iter, entry) {
-+ if (entry->ie_name == MACH_PORT_NULL)
-+ continue;
-
-- 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) {
-@@ -272,6 +263,11 @@ ipc_space_destroy(
- }
- ipc_splay_traverse_finish(&space->is_tree);
-
-+ ipc_entry_t entry;
-+ struct rdxtree_iter iter;
-+ rdxtree_for_each(&space->is_map, &iter, entry)
-+ ie_free(entry);
-+ rdxtree_remove_all(&space->is_map);
- rdxtree_remove_all(&space->is_reverse_map);
-
- /*
-diff --git a/ipc/ipc_space.h b/ipc/ipc_space.h
-index 04eb0dd..17d5b75 100644
---- a/ipc/ipc_space.h
-+++ b/ipc/ipc_space.h
-@@ -81,10 +81,16 @@ struct ipc_space {
- 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;
---
-2.1.4
-