]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. | |
7 | * | |
8 | * This file contains Original Code and/or Modifications of Original Code | |
9 | * as defined in and that are subject to the Apple Public Source License | |
10 | * Version 2.0 (the 'License'). You may not use this file except in | |
11 | * compliance with the License. Please obtain a copy of the License at | |
12 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
13 | * file. | |
14 | * | |
15 | * The Original Code and all software distributed under the License are | |
16 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
17 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
18 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
19 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
20 | * Please see the License for the specific language governing rights and | |
21 | * limitations under the License. | |
22 | * | |
23 | * @APPLE_LICENSE_HEADER_END@ | |
24 | */ | |
25 | /* | |
26 | * @OSF_COPYRIGHT@ | |
27 | */ | |
28 | /* | |
29 | * Mach Operating System | |
30 | * Copyright (c) 1991,1990,1989 Carnegie Mellon University | |
31 | * All Rights Reserved. | |
32 | * | |
33 | * Permission to use, copy, modify and distribute this software and its | |
34 | * documentation is hereby granted, provided that both the copyright | |
35 | * notice and this permission notice appear in all copies of the | |
36 | * software, derivative works or modified versions, and any portions | |
37 | * thereof, and that both notices appear in supporting documentation. | |
38 | * | |
39 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" | |
40 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR | |
41 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. | |
42 | * | |
43 | * Carnegie Mellon requests users of this software to return to | |
44 | * | |
45 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU | |
46 | * School of Computer Science | |
47 | * Carnegie Mellon University | |
48 | * Pittsburgh PA 15213-3890 | |
49 | * | |
50 | * any improvements or extensions that they make and grant Carnegie Mellon | |
51 | * the rights to redistribute these changes. | |
52 | */ | |
53 | /* | |
54 | */ | |
55 | /* | |
56 | * File: ipc/ipc_hash.c | |
57 | * Author: Rich Draves | |
58 | * Date: 1989 | |
59 | * | |
60 | * Entry hash table operations. | |
61 | */ | |
62 | ||
63 | #include <mach/boolean.h> | |
64 | #include <mach/port.h> | |
65 | #include <kern/lock.h> | |
66 | #include <kern/kalloc.h> | |
67 | #include <ipc/port.h> | |
68 | #include <ipc/ipc_space.h> | |
69 | #include <ipc/ipc_object.h> | |
70 | #include <ipc/ipc_entry.h> | |
71 | #include <ipc/ipc_hash.h> | |
72 | #include <ipc/ipc_init.h> | |
73 | ||
74 | #include <mach_ipc_debug.h> | |
75 | ||
76 | #if MACH_IPC_DEBUG | |
77 | #include <mach/kern_return.h> | |
78 | #include <mach_debug/hash_info.h> | |
79 | #include <vm/vm_map.h> | |
80 | #include <vm/vm_kern.h> | |
81 | #endif /* MACH_IPC_DEBUG */ | |
82 | ||
83 | /* | |
84 | * Forward declarations | |
85 | */ | |
86 | ||
87 | /* Lookup (space, obj) in global hash table */ | |
88 | boolean_t ipc_hash_global_lookup( | |
89 | ipc_space_t space, | |
90 | ipc_object_t obj, | |
91 | mach_port_name_t *namep, | |
92 | ipc_tree_entry_t *entryp); | |
93 | ||
94 | /* Insert an entry into the global reverse hash table */ | |
95 | void ipc_hash_global_insert( | |
96 | ipc_space_t space, | |
97 | ipc_object_t obj, | |
98 | mach_port_name_t name, | |
99 | ipc_tree_entry_t entry); | |
100 | ||
101 | /* Delete an entry from the local reverse hash table */ | |
102 | void ipc_hash_local_delete( | |
103 | ipc_space_t space, | |
104 | ipc_object_t obj, | |
105 | mach_port_index_t index, | |
106 | ipc_entry_t entry); | |
107 | ||
108 | /* | |
109 | * Routine: ipc_hash_lookup | |
110 | * Purpose: | |
111 | * Converts (space, obj) -> (name, entry). | |
112 | * Returns TRUE if an entry was found. | |
113 | * Conditions: | |
114 | * The space must be locked (read or write) throughout. | |
115 | */ | |
116 | ||
117 | boolean_t | |
118 | ipc_hash_lookup( | |
119 | ipc_space_t space, | |
120 | ipc_object_t obj, | |
121 | mach_port_name_t *namep, | |
122 | ipc_entry_t *entryp) | |
123 | { | |
124 | boolean_t rv; | |
125 | ||
126 | rv = ipc_hash_local_lookup(space, obj, namep, entryp); | |
127 | if (!rv) { | |
128 | assert(!is_fast_space(space) || space->is_tree_hash == 0); | |
129 | if (space->is_tree_hash > 0) | |
130 | rv = ipc_hash_global_lookup(space, obj, namep, | |
131 | (ipc_tree_entry_t *) entryp); | |
132 | } | |
133 | return (rv); | |
134 | } | |
135 | ||
136 | /* | |
137 | * Routine: ipc_hash_insert | |
138 | * Purpose: | |
139 | * Inserts an entry into the appropriate reverse hash table, | |
140 | * so that ipc_hash_lookup will find it. | |
141 | * Conditions: | |
142 | * The space must be write-locked. | |
143 | */ | |
144 | ||
145 | void | |
146 | ipc_hash_insert( | |
147 | ipc_space_t space, | |
148 | ipc_object_t obj, | |
149 | mach_port_name_t name, | |
150 | ipc_entry_t entry) | |
151 | { | |
152 | mach_port_index_t index; | |
153 | ||
154 | index = MACH_PORT_INDEX(name); | |
155 | if ((index < space->is_table_size) && | |
156 | (entry == &space->is_table[index])) | |
157 | ipc_hash_local_insert(space, obj, index, entry); | |
158 | else { | |
159 | assert(!is_fast_space(space)); | |
160 | ipc_hash_global_insert(space, obj, name, | |
161 | (ipc_tree_entry_t) entry); | |
162 | } | |
163 | } | |
164 | ||
165 | /* | |
166 | * Routine: ipc_hash_delete | |
167 | * Purpose: | |
168 | * Deletes an entry from the appropriate reverse hash table. | |
169 | * Conditions: | |
170 | * The space must be write-locked. | |
171 | */ | |
172 | ||
173 | void | |
174 | ipc_hash_delete( | |
175 | ipc_space_t space, | |
176 | ipc_object_t obj, | |
177 | mach_port_name_t name, | |
178 | ipc_entry_t entry) | |
179 | { | |
180 | mach_port_index_t index; | |
181 | ||
182 | index = MACH_PORT_INDEX(name); | |
183 | if ((index < space->is_table_size) && | |
184 | (entry == &space->is_table[index])) | |
185 | ipc_hash_local_delete(space, obj, index, entry); | |
186 | else { | |
187 | assert(!is_fast_space(space)); | |
188 | ipc_hash_global_delete(space, obj, name, | |
189 | (ipc_tree_entry_t) entry); | |
190 | } | |
191 | } | |
192 | ||
193 | /* | |
194 | * The global reverse hash table holds splay tree entries. | |
195 | * It is a simple open-chaining hash table with singly-linked buckets. | |
196 | * Each bucket is locked separately, with an exclusive lock. | |
197 | * Within each bucket, move-to-front is used. | |
198 | */ | |
199 | ||
200 | typedef natural_t ipc_hash_index_t; | |
201 | ||
202 | ipc_hash_index_t ipc_hash_global_size; | |
203 | ipc_hash_index_t ipc_hash_global_mask; | |
204 | ||
205 | #define IH_GLOBAL_HASH(space, obj) \ | |
206 | (((((ipc_hash_index_t) ((vm_offset_t)space)) >> 4) + \ | |
207 | (((ipc_hash_index_t) ((vm_offset_t)obj)) >> 6)) & \ | |
208 | ipc_hash_global_mask) | |
209 | ||
210 | typedef struct ipc_hash_global_bucket { | |
211 | decl_mutex_data(, ihgb_lock_data) | |
212 | ipc_tree_entry_t ihgb_head; | |
213 | } *ipc_hash_global_bucket_t; | |
214 | ||
215 | #define IHGB_NULL ((ipc_hash_global_bucket_t) 0) | |
216 | ||
217 | #define ihgb_lock_init(ihgb) mutex_init(&(ihgb)->ihgb_lock_data, \ | |
218 | ETAP_IPC_IHGB) | |
219 | #define ihgb_lock(ihgb) mutex_lock(&(ihgb)->ihgb_lock_data) | |
220 | #define ihgb_unlock(ihgb) mutex_unlock(&(ihgb)->ihgb_lock_data) | |
221 | ||
222 | ipc_hash_global_bucket_t ipc_hash_global_table; | |
223 | ||
224 | /* | |
225 | * Routine: ipc_hash_global_lookup | |
226 | * Purpose: | |
227 | * Converts (space, obj) -> (name, entry). | |
228 | * Looks in the global table, for splay tree entries. | |
229 | * Returns TRUE if an entry was found. | |
230 | * Conditions: | |
231 | * The space must be locked (read or write) throughout. | |
232 | */ | |
233 | ||
234 | boolean_t | |
235 | ipc_hash_global_lookup( | |
236 | ipc_space_t space, | |
237 | ipc_object_t obj, | |
238 | mach_port_name_t *namep, | |
239 | ipc_tree_entry_t *entryp) | |
240 | { | |
241 | ipc_hash_global_bucket_t bucket; | |
242 | ipc_tree_entry_t this, *last; | |
243 | ||
244 | assert(space != IS_NULL); | |
245 | assert(obj != IO_NULL); | |
246 | ||
247 | assert(!is_fast_space(space)); | |
248 | bucket = &ipc_hash_global_table[IH_GLOBAL_HASH(space, obj)]; | |
249 | ihgb_lock(bucket); | |
250 | ||
251 | if ((this = bucket->ihgb_head) != ITE_NULL) { | |
252 | if ((this->ite_object == obj) && | |
253 | (this->ite_space == space)) { | |
254 | /* found it at front; no need to move */ | |
255 | ||
256 | *namep = this->ite_name; | |
257 | *entryp = this; | |
258 | } else for (last = &this->ite_next; | |
259 | (this = *last) != ITE_NULL; | |
260 | last = &this->ite_next) { | |
261 | if ((this->ite_object == obj) && | |
262 | (this->ite_space == space)) { | |
263 | /* found it; move to front */ | |
264 | ||
265 | *last = this->ite_next; | |
266 | this->ite_next = bucket->ihgb_head; | |
267 | bucket->ihgb_head = this; | |
268 | ||
269 | *namep = this->ite_name; | |
270 | *entryp = this; | |
271 | break; | |
272 | } | |
273 | } | |
274 | } | |
275 | ||
276 | ihgb_unlock(bucket); | |
277 | return this != ITE_NULL; | |
278 | } | |
279 | ||
280 | /* | |
281 | * Routine: ipc_hash_global_insert | |
282 | * Purpose: | |
283 | * Inserts an entry into the global reverse hash table. | |
284 | * Conditions: | |
285 | * The space must be write-locked. | |
286 | */ | |
287 | ||
288 | void | |
289 | ipc_hash_global_insert( | |
290 | ipc_space_t space, | |
291 | ipc_object_t obj, | |
292 | mach_port_name_t name, | |
293 | ipc_tree_entry_t entry) | |
294 | { | |
295 | ipc_hash_global_bucket_t bucket; | |
296 | ||
297 | ||
298 | assert(!is_fast_space(space)); | |
299 | ||
300 | ||
301 | assert(entry->ite_name == name); | |
302 | assert(space != IS_NULL); | |
303 | assert(entry->ite_space == space); | |
304 | assert(obj != IO_NULL); | |
305 | assert(entry->ite_object == obj); | |
306 | ||
307 | space->is_tree_hash++; | |
308 | assert(space->is_tree_hash <= space->is_tree_total); | |
309 | ||
310 | bucket = &ipc_hash_global_table[IH_GLOBAL_HASH(space, obj)]; | |
311 | ihgb_lock(bucket); | |
312 | ||
313 | /* insert at front of bucket */ | |
314 | ||
315 | entry->ite_next = bucket->ihgb_head; | |
316 | bucket->ihgb_head = entry; | |
317 | ||
318 | ihgb_unlock(bucket); | |
319 | } | |
320 | ||
321 | /* | |
322 | * Routine: ipc_hash_global_delete | |
323 | * Purpose: | |
324 | * Deletes an entry from the global reverse hash table. | |
325 | * Conditions: | |
326 | * The space must be write-locked. | |
327 | */ | |
328 | ||
329 | void | |
330 | ipc_hash_global_delete( | |
331 | ipc_space_t space, | |
332 | ipc_object_t obj, | |
333 | mach_port_name_t name, | |
334 | ipc_tree_entry_t entry) | |
335 | { | |
336 | ipc_hash_global_bucket_t bucket; | |
337 | ipc_tree_entry_t this, *last; | |
338 | ||
339 | assert(!is_fast_space(space)); | |
340 | ||
341 | assert(entry->ite_name == name); | |
342 | assert(space != IS_NULL); | |
343 | assert(entry->ite_space == space); | |
344 | assert(obj != IO_NULL); | |
345 | assert(entry->ite_object == obj); | |
346 | ||
347 | assert(space->is_tree_hash > 0); | |
348 | space->is_tree_hash--; | |
349 | ||
350 | bucket = &ipc_hash_global_table[IH_GLOBAL_HASH(space, obj)]; | |
351 | ihgb_lock(bucket); | |
352 | ||
353 | for (last = &bucket->ihgb_head; | |
354 | (this = *last) != ITE_NULL; | |
355 | last = &this->ite_next) { | |
356 | if (this == entry) { | |
357 | /* found it; remove from bucket */ | |
358 | ||
359 | *last = this->ite_next; | |
360 | break; | |
361 | } | |
362 | } | |
363 | assert(this != ITE_NULL); | |
364 | ||
365 | ihgb_unlock(bucket); | |
366 | } | |
367 | ||
368 | /* | |
369 | * Each space has a local reverse hash table, which holds | |
370 | * entries from the space's table. In fact, the hash table | |
371 | * just uses a field (ie_index) in the table itself. | |
372 | * | |
373 | * The local hash table is an open-addressing hash table, | |
374 | * which means that when a collision occurs, instead of | |
375 | * throwing the entry into a bucket, the entry is rehashed | |
376 | * to another position in the table. In this case the rehash | |
377 | * is very simple: linear probing (ie, just increment the position). | |
378 | * This simple rehash makes deletions tractable (they're still a pain), | |
379 | * but it means that collisions tend to build up into clumps. | |
380 | * | |
381 | * Because at least one entry in the table (index 0) is always unused, | |
382 | * there will always be room in the reverse hash table. If a table | |
383 | * with n slots gets completely full, the reverse hash table will | |
384 | * have one giant clump of n-1 slots and one free slot somewhere. | |
385 | * Because entries are only entered into the reverse table if they | |
386 | * are pure send rights (not receive, send-once, port-set, | |
387 | * or dead-name rights), and free entries of course aren't entered, | |
388 | * I expect the reverse hash table won't get unreasonably full. | |
389 | * | |
390 | * Ordered hash tables (Amble & Knuth, Computer Journal, v. 17, no. 2, | |
391 | * pp. 135-142.) may be desirable here. They can dramatically help | |
392 | * unsuccessful lookups. But unsuccessful lookups are almost always | |
393 | * followed by insertions, and those slow down somewhat. They | |
394 | * also can help deletions somewhat. Successful lookups aren't affected. | |
395 | * So possibly a small win; probably nothing significant. | |
396 | */ | |
397 | ||
398 | #define IH_LOCAL_HASH(obj, size) \ | |
399 | ((((mach_port_index_t) (obj)) >> 6) % (size)) | |
400 | ||
401 | /* | |
402 | * Routine: ipc_hash_local_lookup | |
403 | * Purpose: | |
404 | * Converts (space, obj) -> (name, entry). | |
405 | * Looks in the space's local table, for table entries. | |
406 | * Returns TRUE if an entry was found. | |
407 | * Conditions: | |
408 | * The space must be locked (read or write) throughout. | |
409 | */ | |
410 | ||
411 | boolean_t | |
412 | ipc_hash_local_lookup( | |
413 | ipc_space_t space, | |
414 | ipc_object_t obj, | |
415 | mach_port_name_t *namep, | |
416 | ipc_entry_t *entryp) | |
417 | { | |
418 | ipc_entry_t table; | |
419 | ipc_entry_num_t size; | |
420 | mach_port_index_t hindex, index; | |
421 | ||
422 | assert(space != IS_NULL); | |
423 | assert(obj != IO_NULL); | |
424 | ||
425 | table = space->is_table; | |
426 | size = space->is_table_size; | |
427 | hindex = IH_LOCAL_HASH(obj, size); | |
428 | ||
429 | /* | |
430 | * Ideally, table[hindex].ie_index is the name we want. | |
431 | * However, must check ie_object to verify this, | |
432 | * because collisions can happen. In case of a collision, | |
433 | * search farther along in the clump. | |
434 | */ | |
435 | ||
436 | while ((index = table[hindex].ie_index) != 0) { | |
437 | ipc_entry_t entry = &table[index]; | |
438 | ||
439 | if (entry->ie_object == obj) { | |
440 | *entryp = entry; | |
441 | *namep = MACH_PORT_MAKE(index, | |
442 | IE_BITS_GEN(entry->ie_bits)); | |
443 | return TRUE; | |
444 | } | |
445 | ||
446 | if (++hindex == size) | |
447 | hindex = 0; | |
448 | } | |
449 | ||
450 | return FALSE; | |
451 | } | |
452 | ||
453 | /* | |
454 | * Routine: ipc_hash_local_insert | |
455 | * Purpose: | |
456 | * Inserts an entry into the space's reverse hash table. | |
457 | * Conditions: | |
458 | * The space must be write-locked. | |
459 | */ | |
460 | ||
461 | void | |
462 | ipc_hash_local_insert( | |
463 | ipc_space_t space, | |
464 | ipc_object_t obj, | |
465 | mach_port_index_t index, | |
466 | ipc_entry_t entry) | |
467 | { | |
468 | ipc_entry_t table; | |
469 | ipc_entry_num_t size; | |
470 | mach_port_index_t hindex; | |
471 | ||
472 | assert(index != 0); | |
473 | assert(space != IS_NULL); | |
474 | assert(obj != IO_NULL); | |
475 | ||
476 | table = space->is_table; | |
477 | size = space->is_table_size; | |
478 | hindex = IH_LOCAL_HASH(obj, size); | |
479 | ||
480 | assert(entry == &table[index]); | |
481 | assert(entry->ie_object == obj); | |
482 | ||
483 | /* | |
484 | * We want to insert at hindex, but there may be collisions. | |
485 | * If a collision occurs, search for the end of the clump | |
486 | * and insert there. | |
487 | */ | |
488 | ||
489 | while (table[hindex].ie_index != 0) { | |
490 | if (++hindex == size) | |
491 | hindex = 0; | |
492 | } | |
493 | ||
494 | table[hindex].ie_index = index; | |
495 | } | |
496 | ||
497 | /* | |
498 | * Routine: ipc_hash_local_delete | |
499 | * Purpose: | |
500 | * Deletes an entry from the space's reverse hash table. | |
501 | * Conditions: | |
502 | * The space must be write-locked. | |
503 | */ | |
504 | ||
505 | void | |
506 | ipc_hash_local_delete( | |
507 | ipc_space_t space, | |
508 | ipc_object_t obj, | |
509 | mach_port_index_t index, | |
510 | ipc_entry_t entry) | |
511 | { | |
512 | ipc_entry_t table; | |
513 | ipc_entry_num_t size; | |
514 | mach_port_index_t hindex, dindex; | |
515 | ||
516 | assert(index != MACH_PORT_NULL); | |
517 | assert(space != IS_NULL); | |
518 | assert(obj != IO_NULL); | |
519 | ||
520 | table = space->is_table; | |
521 | size = space->is_table_size; | |
522 | hindex = IH_LOCAL_HASH(obj, size); | |
523 | ||
524 | assert(entry == &table[index]); | |
525 | assert(entry->ie_object == obj); | |
526 | ||
527 | /* | |
528 | * First check we have the right hindex for this index. | |
529 | * In case of collision, we have to search farther | |
530 | * along in this clump. | |
531 | */ | |
532 | ||
533 | while (table[hindex].ie_index != index) { | |
534 | if (++hindex == size) | |
535 | hindex = 0; | |
536 | } | |
537 | ||
538 | /* | |
539 | * Now we want to set table[hindex].ie_index = 0. | |
540 | * But if we aren't the last index in a clump, | |
541 | * this might cause problems for lookups of objects | |
542 | * farther along in the clump that are displaced | |
543 | * due to collisions. Searches for them would fail | |
544 | * at hindex instead of succeeding. | |
545 | * | |
546 | * So we must check the clump after hindex for objects | |
547 | * that are so displaced, and move one up to the new hole. | |
548 | * | |
549 | * hindex - index of new hole in the clump | |
550 | * dindex - index we are checking for a displaced object | |
551 | * | |
552 | * When we move a displaced object up into the hole, | |
553 | * it creates a new hole, and we have to repeat the process | |
554 | * until we get to the end of the clump. | |
555 | */ | |
556 | ||
557 | for (dindex = hindex; index != 0; hindex = dindex) { | |
558 | for (;;) { | |
559 | mach_port_index_t tindex; | |
560 | ipc_object_t tobj; | |
561 | ||
562 | if (++dindex == size) | |
563 | dindex = 0; | |
564 | assert(dindex != hindex); | |
565 | ||
566 | /* are we at the end of the clump? */ | |
567 | ||
568 | index = table[dindex].ie_index; | |
569 | if (index == 0) | |
570 | break; | |
571 | ||
572 | /* is this a displaced object? */ | |
573 | ||
574 | tobj = table[index].ie_object; | |
575 | assert(tobj != IO_NULL); | |
576 | tindex = IH_LOCAL_HASH(tobj, size); | |
577 | ||
578 | if ((dindex < hindex) ? | |
579 | ((dindex < tindex) && (tindex <= hindex)) : | |
580 | ((dindex < tindex) || (tindex <= hindex))) | |
581 | break; | |
582 | } | |
583 | ||
584 | table[hindex].ie_index = index; | |
585 | } | |
586 | } | |
587 | ||
588 | /* | |
589 | * Routine: ipc_hash_init | |
590 | * Purpose: | |
591 | * Initialize the reverse hash table implementation. | |
592 | */ | |
593 | ||
594 | void | |
595 | ipc_hash_init(void) | |
596 | { | |
597 | ipc_hash_index_t i; | |
598 | ||
599 | /* if not configured, initialize ipc_hash_global_size */ | |
600 | ||
601 | if (ipc_hash_global_size == 0) { | |
602 | ipc_hash_global_size = ipc_tree_entry_max >> 8; | |
603 | if (ipc_hash_global_size < 32) | |
604 | ipc_hash_global_size = 32; | |
605 | } | |
606 | ||
607 | /* make sure it is a power of two */ | |
608 | ||
609 | ipc_hash_global_mask = ipc_hash_global_size - 1; | |
610 | if ((ipc_hash_global_size & ipc_hash_global_mask) != 0) { | |
611 | natural_t bit; | |
612 | ||
613 | /* round up to closest power of two */ | |
614 | ||
615 | for (bit = 1;; bit <<= 1) { | |
616 | ipc_hash_global_mask |= bit; | |
617 | ipc_hash_global_size = ipc_hash_global_mask + 1; | |
618 | ||
619 | if ((ipc_hash_global_size & ipc_hash_global_mask) == 0) | |
620 | break; | |
621 | } | |
622 | } | |
623 | ||
624 | /* allocate ipc_hash_global_table */ | |
625 | ||
626 | ipc_hash_global_table = (ipc_hash_global_bucket_t) | |
627 | kalloc((vm_size_t) (ipc_hash_global_size * | |
628 | sizeof(struct ipc_hash_global_bucket))); | |
629 | assert(ipc_hash_global_table != IHGB_NULL); | |
630 | ||
631 | /* and initialize it */ | |
632 | ||
633 | for (i = 0; i < ipc_hash_global_size; i++) { | |
634 | ipc_hash_global_bucket_t bucket; | |
635 | ||
636 | bucket = &ipc_hash_global_table[i]; | |
637 | ihgb_lock_init(bucket); | |
638 | bucket->ihgb_head = ITE_NULL; | |
639 | } | |
640 | } | |
641 | ||
642 | #if MACH_IPC_DEBUG | |
643 | ||
644 | /* | |
645 | * Routine: ipc_hash_info | |
646 | * Purpose: | |
647 | * Return information about the global reverse hash table. | |
648 | * Fills the buffer with as much information as possible | |
649 | * and returns the desired size of the buffer. | |
650 | * Conditions: | |
651 | * Nothing locked. The caller should provide | |
652 | * possibly-pageable memory. | |
653 | */ | |
654 | ||
655 | ||
656 | ipc_hash_index_t | |
657 | ipc_hash_info( | |
658 | hash_info_bucket_t *info, | |
659 | mach_msg_type_number_t count) | |
660 | { | |
661 | ipc_hash_index_t i; | |
662 | ||
663 | if (ipc_hash_global_size < count) | |
664 | count = ipc_hash_global_size; | |
665 | ||
666 | for (i = 0; i < count; i++) { | |
667 | ipc_hash_global_bucket_t bucket = &ipc_hash_global_table[i]; | |
668 | unsigned int bucket_count = 0; | |
669 | ipc_tree_entry_t entry; | |
670 | ||
671 | ihgb_lock(bucket); | |
672 | for (entry = bucket->ihgb_head; | |
673 | entry != ITE_NULL; | |
674 | entry = entry->ite_next) | |
675 | bucket_count++; | |
676 | ihgb_unlock(bucket); | |
677 | ||
678 | /* don't touch pageable memory while holding locks */ | |
679 | info[i].hib_count = bucket_count; | |
680 | } | |
681 | ||
682 | return ipc_hash_global_size; | |
683 | } | |
684 | ||
685 | #endif /* MACH_IPC_DEBUG */ |