2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
34 * All Rights Reserved.
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
46 * Carnegie Mellon requests users of this software to return to
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
59 * File: ipc/ipc_hash.c
63 * Entry hash table operations.
66 #include <mach/boolean.h>
67 #include <mach/port.h>
68 #include <kern/lock.h>
69 #include <kern/kalloc.h>
71 #include <ipc/ipc_space.h>
72 #include <ipc/ipc_object.h>
73 #include <ipc/ipc_entry.h>
74 #include <ipc/ipc_hash.h>
75 #include <ipc/ipc_init.h>
77 #include <mach_ipc_debug.h>
80 #include <mach/kern_return.h>
81 #include <mach_debug/hash_info.h>
82 #include <vm/vm_map.h>
83 #include <vm/vm_kern.h>
84 #endif /* MACH_IPC_DEBUG */
87 * Forward declarations
90 /* Delete an entry from the local reverse hash table */
91 void ipc_hash_local_delete(
94 mach_port_index_t index
,
98 * Routine: ipc_hash_lookup
100 * Converts (space, obj) -> (name, entry).
101 * Returns TRUE if an entry was found.
103 * The space must be locked (read or write) throughout.
110 mach_port_name_t
*namep
,
113 return ipc_hash_table_lookup(space
->is_table
, space
->is_table_size
, obj
, namep
, entryp
);
117 * Routine: ipc_hash_insert
119 * Inserts an entry into the appropriate reverse hash table,
120 * so that ipc_hash_lookup will find it.
122 * The space must be write-locked.
129 mach_port_name_t name
,
132 mach_port_index_t index
;
134 index
= MACH_PORT_INDEX(name
);
135 ipc_hash_table_insert(space
->is_table
, space
->is_table_size
, obj
, index
, entry
);
139 * Routine: ipc_hash_delete
141 * Deletes an entry from the appropriate reverse hash table.
143 * The space must be write-locked.
150 mach_port_name_t name
,
153 mach_port_index_t index
;
155 index
= MACH_PORT_INDEX(name
);
156 ipc_hash_table_delete(space
->is_table
, space
->is_table_size
, obj
, index
, entry
);
160 * Each space has a local reverse hash table, which holds
161 * entries from the space's table. In fact, the hash table
162 * just uses a field (ie_index) in the table itself.
164 * The local hash table is an open-addressing hash table,
165 * which means that when a collision occurs, instead of
166 * throwing the entry into a bucket, the entry is rehashed
167 * to another position in the table. In this case the rehash
168 * is very simple: linear probing (ie, just increment the position).
169 * This simple rehash makes deletions tractable (they're still a pain),
170 * but it means that collisions tend to build up into clumps.
172 * Because at least one entry in the table (index 0) is always unused,
173 * there will always be room in the reverse hash table. If a table
174 * with n slots gets completely full, the reverse hash table will
175 * have one giant clump of n-1 slots and one free slot somewhere.
176 * Because entries are only entered into the reverse table if they
177 * are pure send rights (not receive, send-once, port-set,
178 * or dead-name rights), and free entries of course aren't entered,
179 * I expect the reverse hash table won't get unreasonably full.
181 * Ordered hash tables (Amble & Knuth, Computer Journal, v. 17, no. 2,
182 * pp. 135-142.) may be desirable here. They can dramatically help
183 * unsuccessful lookups. But unsuccessful lookups are almost always
184 * followed by insertions, and those slow down somewhat. They
185 * also can help deletions somewhat. Successful lookups aren't affected.
186 * So possibly a small win; probably nothing significant.
189 #define IH_TABLE_HASH(obj, size) \
190 ((mach_port_index_t)((((uintptr_t) (obj)) >> 6) % (size)))
193 * Routine: ipc_hash_table_lookup
195 * Converts (table, obj) -> (name, entry).
197 * Must have read consistency on the table.
201 ipc_hash_table_lookup(
203 ipc_entry_num_t size
,
205 mach_port_name_t
*namep
,
208 mach_port_index_t hindex
, index
;
210 assert(obj
!= IO_NULL
);
212 hindex
= IH_TABLE_HASH(obj
, size
);
215 * Ideally, table[hindex].ie_index is the name we want.
216 * However, must check ie_object to verify this,
217 * because collisions can happen. In case of a collision,
218 * search farther along in the clump.
221 while ((index
= table
[hindex
].ie_index
) != 0) {
224 assert(index
< size
);
225 entry
= &table
[index
];
226 if (entry
->ie_object
== obj
) {
228 *namep
= MACH_PORT_MAKE(index
,
229 IE_BITS_GEN(entry
->ie_bits
));
233 if (++hindex
== size
)
241 * Routine: ipc_hash_table_insert
243 * Inserts an entry into the space's reverse hash table.
245 * The space must be write-locked.
249 ipc_hash_table_insert(
251 ipc_entry_num_t size
,
253 mach_port_index_t index
,
254 __assert_only ipc_entry_t entry
)
256 mach_port_index_t hindex
;
259 assert(obj
!= IO_NULL
);
261 hindex
= IH_TABLE_HASH(obj
, size
);
263 assert(entry
== &table
[index
]);
264 assert(entry
->ie_object
== obj
);
267 * We want to insert at hindex, but there may be collisions.
268 * If a collision occurs, search for the end of the clump
272 while (table
[hindex
].ie_index
!= 0) {
273 if (++hindex
== size
)
277 table
[hindex
].ie_index
= index
;
281 * Routine: ipc_hash_table_delete
283 * Deletes an entry from the table's reverse hash.
285 * Exclusive access to the table.
289 ipc_hash_table_delete(
291 ipc_entry_num_t size
,
293 mach_port_index_t index
,
294 __assert_only ipc_entry_t entry
)
296 mach_port_index_t hindex
, dindex
;
298 assert(index
!= MACH_PORT_NULL
);
299 assert(obj
!= IO_NULL
);
301 hindex
= IH_TABLE_HASH(obj
, size
);
303 assert(entry
== &table
[index
]);
304 assert(entry
->ie_object
== obj
);
307 * First check we have the right hindex for this index.
308 * In case of collision, we have to search farther
309 * along in this clump.
312 while (table
[hindex
].ie_index
!= index
) {
313 if (++hindex
== size
)
318 * Now we want to set table[hindex].ie_index = 0.
319 * But if we aren't the last index in a clump,
320 * this might cause problems for lookups of objects
321 * farther along in the clump that are displaced
322 * due to collisions. Searches for them would fail
323 * at hindex instead of succeeding.
325 * So we must check the clump after hindex for objects
326 * that are so displaced, and move one up to the new hole.
328 * hindex - index of new hole in the clump
329 * dindex - index we are checking for a displaced object
331 * When we move a displaced object up into the hole,
332 * it creates a new hole, and we have to repeat the process
333 * until we get to the end of the clump.
336 for (dindex
= hindex
; index
!= 0; hindex
= dindex
) {
338 mach_port_index_t tindex
;
341 if (++dindex
== size
)
343 assert(dindex
!= hindex
);
345 /* are we at the end of the clump? */
347 index
= table
[dindex
].ie_index
;
351 /* is this a displaced object? */
353 tobj
= table
[index
].ie_object
;
354 assert(tobj
!= IO_NULL
);
355 tindex
= IH_TABLE_HASH(tobj
, size
);
357 if ((dindex
< hindex
) ?
358 ((dindex
< tindex
) && (tindex
<= hindex
)) :
359 ((dindex
< tindex
) || (tindex
<= hindex
)))
363 table
[hindex
].ie_index
= index
;