]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ipc/ipc_entry.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / osfmk / ipc / ipc_entry.c
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * @OSF_COPYRIGHT@
30 */
31 /*
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
34 * All Rights Reserved.
35 *
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.
41 *
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.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56 /*
57 */
58 /*
59 * File: ipc/ipc_entry.c
60 * Author: Rich Draves
61 * Date: 1989
62 *
63 * Primitive functions to manipulate translation entries.
64 */
65
66 #include <mach_debug.h>
67
68 #include <mach/kern_return.h>
69 #include <mach/port.h>
70 #include <kern/assert.h>
71 #include <kern/sched_prim.h>
72 #include <kern/zalloc.h>
73 #include <kern/misc_protos.h>
74 #include <ipc/port.h>
75 #include <ipc/ipc_entry.h>
76 #include <ipc/ipc_space.h>
77 #include <ipc/ipc_object.h>
78 #include <ipc/ipc_hash.h>
79 #include <ipc/ipc_table.h>
80 #include <ipc/ipc_port.h>
81 #include <string.h>
82 #include <sys/kdebug.h>
83
84 /*
85 * Routine: ipc_entry_lookup
86 * Purpose:
87 * Searches for an entry, given its name.
88 * Conditions:
89 * The space must be read or write locked throughout.
90 * The space must be active.
91 */
92
93 ipc_entry_t
94 ipc_entry_lookup(
95 ipc_space_t space,
96 mach_port_name_t name)
97 {
98 mach_port_index_t index;
99 ipc_entry_t entry;
100
101 assert(is_active(space));
102
103 index = MACH_PORT_INDEX(name);
104 if (index < space->is_table_size) {
105 entry = &space->is_table[index];
106 if (IE_BITS_GEN(entry->ie_bits) != MACH_PORT_GEN(name) ||
107 IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) {
108 entry = IE_NULL;
109 }
110 } else {
111 entry = IE_NULL;
112 }
113
114 assert((entry == IE_NULL) || IE_BITS_TYPE(entry->ie_bits));
115 return entry;
116 }
117
118
119 /*
120 * Routine: ipc_entries_hold
121 * Purpose:
122 * Verifies that there are at least 'entries_needed'
123 * free list members
124 * Conditions:
125 * The space is write-locked and active throughout.
126 * An object may be locked. Will not allocate memory.
127 * Returns:
128 * KERN_SUCCESS Free entries were found.
129 * KERN_NO_SPACE No entry allocated.
130 */
131
132 kern_return_t
133 ipc_entries_hold(
134 ipc_space_t space,
135 uint32_t entries_needed)
136 {
137 ipc_entry_t table;
138 mach_port_index_t next_free = 0;
139 uint32_t i;
140
141 /*
142 * Assume that all new entries will need hashing.
143 * If the table is more than 87.5% full pretend we didn't have space.
144 */
145 if (space->is_table_hashed + entries_needed >
146 space->is_table_size * 7 / 8) {
147 return KERN_NO_SPACE;
148 }
149
150 assert(is_active(space));
151
152 table = &space->is_table[0];
153
154 for (i = 0; i < entries_needed; i++) {
155 next_free = table[next_free].ie_next;
156 if (next_free == 0) {
157 return KERN_NO_SPACE;
158 }
159 assert(next_free < space->is_table_size);
160 assert(table[next_free].ie_object == IO_NULL);
161 }
162 return KERN_SUCCESS;
163 }
164
165 /*
166 * Routine: ipc_entry_claim
167 * Purpose:
168 * Take formal ownership of a held entry.
169 * Conditions:
170 * The space is write-locked and active throughout.
171 * An object may be locked. Will not allocate memory.
172 *
173 * Note: The returned entry must be marked as modified before
174 * releasing the space lock
175 */
176
177 kern_return_t
178 ipc_entry_claim(
179 ipc_space_t space,
180 mach_port_name_t *namep,
181 ipc_entry_t *entryp)
182 {
183 ipc_entry_t entry;
184 ipc_entry_t table;
185 mach_port_index_t first_free;
186 mach_port_gen_t gen;
187 mach_port_name_t new_name;
188
189 table = &space->is_table[0];
190
191 first_free = table->ie_next;
192 assert(first_free != 0);
193
194 entry = &table[first_free];
195 table->ie_next = entry->ie_next;
196 space->is_table_free--;
197
198 assert(table->ie_next < space->is_table_size);
199
200 /*
201 * Initialize the new entry: increment gencount and reset
202 * rollover point if it rolled over, and clear ie_request.
203 */
204 gen = ipc_entry_new_gen(entry->ie_bits);
205 if (__improbable(ipc_entry_gen_rolled(entry->ie_bits, gen))) {
206 ipc_entry_bits_t roll = ipc_space_get_rollpoint(space);
207 gen = ipc_entry_new_rollpoint(roll);
208 }
209 entry->ie_bits = gen;
210 entry->ie_request = IE_REQ_NONE;
211
212 /*
213 * The new name can't be MACH_PORT_NULL because index
214 * is non-zero. It can't be MACH_PORT_DEAD because
215 * the table isn't allowed to grow big enough.
216 * (See comment in ipc/ipc_table.h.)
217 */
218 new_name = MACH_PORT_MAKE(first_free, gen);
219 assert(MACH_PORT_VALID(new_name));
220 *namep = new_name;
221 *entryp = entry;
222
223 return KERN_SUCCESS;
224 }
225
226 /*
227 * Routine: ipc_entry_alloc
228 * Purpose:
229 * Allocate an entry out of the space.
230 * Conditions:
231 * The space is not locked before, but it is write-locked after
232 * if the call is successful. May allocate memory.
233 * Returns:
234 * KERN_SUCCESS An entry was allocated.
235 * KERN_INVALID_TASK The space is dead.
236 * KERN_NO_SPACE No room for an entry in the space.
237 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory for an entry.
238 */
239
240 kern_return_t
241 ipc_entry_alloc(
242 ipc_space_t space,
243 mach_port_name_t *namep,
244 ipc_entry_t *entryp)
245 {
246 kern_return_t kr;
247
248 is_write_lock(space);
249
250 for (;;) {
251 if (!is_active(space)) {
252 is_write_unlock(space);
253 return KERN_INVALID_TASK;
254 }
255
256 kr = ipc_entries_hold(space, 1);
257 if (kr == KERN_SUCCESS) {
258 return ipc_entry_claim(space, namep, entryp);
259 }
260
261 kr = ipc_entry_grow_table(space, ITS_SIZE_NONE);
262 if (kr != KERN_SUCCESS) {
263 return kr; /* space is unlocked */
264 }
265 }
266 }
267
268 /*
269 * Routine: ipc_entry_alloc_name
270 * Purpose:
271 * Allocates/finds an entry with a specific name.
272 * If an existing entry is returned, its type will be nonzero.
273 * Conditions:
274 * The space is not locked before, but it is write-locked after
275 * if the call is successful. May allocate memory.
276 * Returns:
277 * KERN_SUCCESS Found existing entry with same name.
278 * KERN_SUCCESS Allocated a new entry.
279 * KERN_INVALID_TASK The space is dead.
280 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
281 * KERN_FAILURE Couldn't allocate requested name.
282 */
283
284 kern_return_t
285 ipc_entry_alloc_name(
286 ipc_space_t space,
287 mach_port_name_t name,
288 ipc_entry_t *entryp)
289 {
290 mach_port_index_t index = MACH_PORT_INDEX(name);
291 mach_port_gen_t gen = MACH_PORT_GEN(name);
292
293 if (index > ipc_table_max_entries()) {
294 return KERN_NO_SPACE;
295 }
296
297 assert(MACH_PORT_VALID(name));
298
299
300 is_write_lock(space);
301
302 for (;;) {
303 ipc_entry_t entry;
304
305 if (!is_active(space)) {
306 is_write_unlock(space);
307 return KERN_INVALID_TASK;
308 }
309
310 /*
311 * If we are under the table cutoff,
312 * there are usually four cases:
313 * 1) The entry is reserved (index 0)
314 * 2) The entry is inuse, for the same name
315 * 3) The entry is inuse, for a different name
316 * 4) The entry is free
317 * For a task with a "fast" IPC space, we disallow
318 * cases 1) and 3), because ports cannot be renamed.
319 */
320 if (index < space->is_table_size) {
321 ipc_entry_t table = space->is_table;
322
323 entry = &table[index];
324
325 if (index == 0) {
326 /* case #1 - the entry is reserved */
327 assert(!IE_BITS_TYPE(entry->ie_bits));
328 assert(!IE_BITS_GEN(entry->ie_bits));
329 is_write_unlock(space);
330 return KERN_FAILURE;
331 } else if (IE_BITS_TYPE(entry->ie_bits)) {
332 if (IE_BITS_GEN(entry->ie_bits) == gen) {
333 /* case #2 -- the entry is inuse, for the same name */
334 *entryp = entry;
335 return KERN_SUCCESS;
336 } else {
337 /* case #3 -- the entry is inuse, for a different name. */
338 /* Collisions are not allowed */
339 is_write_unlock(space);
340 return KERN_FAILURE;
341 }
342 } else {
343 mach_port_index_t free_index, next_index;
344
345 /*
346 * case #4 -- the entry is free
347 * Rip the entry out of the free list.
348 */
349
350 for (free_index = 0;
351 (next_index = table[free_index].ie_next)
352 != index;
353 free_index = next_index) {
354 continue;
355 }
356
357 table[free_index].ie_next =
358 table[next_index].ie_next;
359 space->is_table_free--;
360
361 /* mark the previous entry modified - reconstructing the name */
362 ipc_entry_modified(space,
363 MACH_PORT_MAKE(free_index,
364 IE_BITS_GEN(table[free_index].ie_bits)),
365 &table[free_index]);
366
367 entry->ie_bits = gen;
368 entry->ie_request = IE_REQ_NONE;
369 *entryp = entry;
370
371 assert(entry->ie_object == IO_NULL);
372 return KERN_SUCCESS;
373 }
374 }
375
376 /*
377 * We grow the table so that the name
378 * index fits in the array space.
379 * Because the space will be unlocked,
380 * we must restart.
381 */
382 kern_return_t kr;
383 kr = ipc_entry_grow_table(space, index + 1);
384 if (kr != KERN_SUCCESS) {
385 /* space is unlocked */
386 return kr;
387 }
388 continue;
389 }
390 }
391
392 /*
393 * Routine: ipc_entry_dealloc
394 * Purpose:
395 * Deallocates an entry from a space.
396 * Conditions:
397 * The space must be write-locked throughout.
398 * The space must be active.
399 */
400
401 void
402 ipc_entry_dealloc(
403 ipc_space_t space,
404 mach_port_name_t name,
405 ipc_entry_t entry)
406 {
407 ipc_entry_t table;
408 ipc_entry_num_t size;
409 mach_port_index_t index;
410
411 assert(is_active(space));
412 assert(entry->ie_object == IO_NULL);
413 assert(entry->ie_request == IE_REQ_NONE);
414
415 #if 1
416 if (entry->ie_request != IE_REQ_NONE) {
417 panic("ipc_entry_dealloc()\n");
418 }
419 #endif
420
421 index = MACH_PORT_INDEX(name);
422 table = space->is_table;
423 size = space->is_table_size;
424
425 if ((index < size) && (entry == &table[index])) {
426 assert(IE_BITS_GEN(entry->ie_bits) == MACH_PORT_GEN(name));
427 entry->ie_bits &= (IE_BITS_GEN_MASK | IE_BITS_ROLL_MASK);
428 entry->ie_next = table->ie_next;
429 table->ie_next = index;
430 space->is_table_free++;
431 } else {
432 /*
433 * Nothing to do. The entry does not match
434 * so there is nothing to deallocate.
435 */
436 assert(index < size);
437 assert(entry == &table[index]);
438 assert(IE_BITS_GEN(entry->ie_bits) == MACH_PORT_GEN(name));
439 }
440 ipc_entry_modified(space, name, entry);
441 }
442
443 /*
444 * Routine: ipc_entry_modified
445 * Purpose:
446 * Note that an entry was modified in a space.
447 * Conditions:
448 * Assumes exclusive write access to the space,
449 * either through a write lock or being the cleaner
450 * on an inactive space.
451 */
452
453 void
454 ipc_entry_modified(
455 ipc_space_t space,
456 mach_port_name_t name,
457 __assert_only ipc_entry_t entry)
458 {
459 ipc_entry_t table;
460 ipc_entry_num_t size;
461 mach_port_index_t index;
462
463 index = MACH_PORT_INDEX(name);
464 table = space->is_table;
465 size = space->is_table_size;
466
467 assert(index < size);
468 assert(entry == &table[index]);
469
470 assert(space->is_low_mod <= size);
471 assert(space->is_high_mod < size);
472
473 if (index < space->is_low_mod) {
474 space->is_low_mod = index;
475 }
476 if (index > space->is_high_mod) {
477 space->is_high_mod = index;
478 }
479
480 KERNEL_DEBUG_CONSTANT(
481 MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_PORT_ENTRY_MODIFY) | DBG_FUNC_NONE,
482 space->is_task ? task_pid(space->is_task) : 0,
483 name,
484 entry->ie_bits,
485 0,
486 0);
487 }
488
489 #define IPC_ENTRY_GROW_STATS 1
490 #if IPC_ENTRY_GROW_STATS
491 static uint64_t ipc_entry_grow_count = 0;
492 static uint64_t ipc_entry_grow_rescan = 0;
493 static uint64_t ipc_entry_grow_rescan_max = 0;
494 static uint64_t ipc_entry_grow_rescan_entries = 0;
495 static uint64_t ipc_entry_grow_rescan_entries_max = 0;
496 static uint64_t ipc_entry_grow_freelist_entries = 0;
497 static uint64_t ipc_entry_grow_freelist_entries_max = 0;
498 #endif
499
500 /*
501 * Routine: ipc_entry_grow_table
502 * Purpose:
503 * Grows the table in a space.
504 * Conditions:
505 * The space must be write-locked and active before.
506 * If successful, the space is also returned locked.
507 * On failure, the space is returned unlocked.
508 * Allocates memory.
509 * Returns:
510 * KERN_SUCCESS Grew the table.
511 * KERN_SUCCESS Somebody else grew the table.
512 * KERN_SUCCESS The space died.
513 * KERN_NO_SPACE Table has maximum size already.
514 * KERN_RESOURCE_SHORTAGE Couldn't allocate a new table.
515 */
516
517 kern_return_t
518 ipc_entry_grow_table(
519 ipc_space_t space,
520 ipc_table_elems_t target_size)
521 {
522 ipc_entry_num_t osize, size, nsize, psize;
523
524 ipc_entry_t otable, table;
525 ipc_table_size_t oits, its, nits;
526 mach_port_index_t i, free_index;
527 mach_port_index_t low_mod, hi_mod;
528 ipc_table_index_t sanity;
529 #if IPC_ENTRY_GROW_STATS
530 uint64_t rescan_count = 0;
531 #endif
532 assert(is_active(space));
533
534 if (is_growing(space)) {
535 /*
536 * Somebody else is growing the table.
537 * We just wait for them to finish.
538 */
539
540 is_write_sleep(space);
541 return KERN_SUCCESS;
542 }
543
544 otable = space->is_table;
545
546 its = space->is_table_next;
547 size = its->its_size;
548
549 /*
550 * Since is_table_next points to the next natural size
551 * we can identify the current size entry.
552 */
553 oits = its - 1;
554 osize = oits->its_size;
555
556 /*
557 * If there is no target size, then the new size is simply
558 * specified by is_table_next. If there is a target
559 * size, then search for the next entry.
560 */
561 if (target_size != ITS_SIZE_NONE) {
562 if (target_size <= osize) {
563 /* the space is locked */
564 return KERN_SUCCESS;
565 }
566
567 psize = osize;
568 while ((psize != size) && (target_size > size)) {
569 psize = size;
570 its++;
571 size = its->its_size;
572 }
573 if (psize == size) {
574 is_write_unlock(space);
575 return KERN_NO_SPACE;
576 }
577 }
578
579 if (osize == size) {
580 is_write_unlock(space);
581 return KERN_NO_SPACE;
582 }
583
584 nits = its + 1;
585 nsize = nits->its_size;
586 assert((osize < size) && (size <= nsize));
587
588 /*
589 * We'll attempt to grow the table.
590 *
591 * Because we will be copying without the space lock, reset
592 * the lowest_mod index to just beyond the end of the current
593 * table. Modification of entries (other than hashes) will
594 * bump this downward, and we only have to reprocess entries
595 * above that mark. Eventually, we'll get done.
596 */
597 is_start_growing(space);
598 space->is_low_mod = osize;
599 space->is_high_mod = 0;
600 #if IPC_ENTRY_GROW_STATS
601 ipc_entry_grow_count++;
602 #endif
603 is_write_unlock(space);
604
605 table = it_entries_alloc(its);
606 if (table == IE_NULL) {
607 is_write_lock(space);
608 is_done_growing(space);
609 is_write_unlock(space);
610 thread_wakeup((event_t) space);
611 return KERN_RESOURCE_SHORTAGE;
612 }
613
614 ipc_space_rand_freelist(space, table, osize, size);
615
616 /* clear out old entries in new table */
617 memset((void *)table, 0, osize * sizeof(*table));
618
619 low_mod = 0;
620 hi_mod = osize - 1;
621 rescan:
622 /*
623 * Within the range of the table that changed, determine what we
624 * have to take action on. For each entry, take a snapshot of the
625 * corresponding entry in the old table (so it won't change
626 * during this iteration). The snapshot may not be self-consistent
627 * (if we caught it in the middle of being changed), so be very
628 * cautious with the values.
629 */
630 for (i = low_mod; i <= hi_mod; i++) {
631 ipc_entry_t entry = &table[i];
632 struct ipc_entry osnap = otable[i];
633
634 if (entry->ie_object != osnap.ie_object ||
635 IE_BITS_TYPE(entry->ie_bits) != IE_BITS_TYPE(osnap.ie_bits)) {
636 if (entry->ie_object != IO_NULL &&
637 IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_SEND) {
638 ipc_hash_table_delete(table, size, entry->ie_object, i, entry);
639 }
640
641 entry->ie_object = osnap.ie_object;
642 entry->ie_bits = osnap.ie_bits;
643 entry->ie_request = osnap.ie_request; /* or ie_next */
644
645 if (entry->ie_object != IO_NULL &&
646 IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_SEND) {
647 ipc_hash_table_insert(table, size, entry->ie_object, i, entry);
648 }
649 } else {
650 assert(entry->ie_object == osnap.ie_object);
651 entry->ie_bits = osnap.ie_bits;
652 entry->ie_request = osnap.ie_request; /* or ie_next */
653 }
654 }
655 table[0].ie_next = otable[0].ie_next; /* always rebase the freelist */
656
657 /*
658 * find the end of the freelist (should be short). But be careful,
659 * the list items can change so only follow through truly free entries
660 * (no problem stopping short in those cases, because we'll rescan).
661 */
662 free_index = 0;
663 for (sanity = 0; sanity < osize; sanity++) {
664 if (table[free_index].ie_object != IPC_OBJECT_NULL) {
665 break;
666 }
667 i = table[free_index].ie_next;
668 if (i == 0 || i >= osize) {
669 break;
670 }
671 free_index = i;
672 }
673 #if IPC_ENTRY_GROW_STATS
674 ipc_entry_grow_freelist_entries += sanity;
675 if (sanity > ipc_entry_grow_freelist_entries_max) {
676 ipc_entry_grow_freelist_entries_max = sanity;
677 }
678 #endif
679
680 is_write_lock(space);
681
682 /*
683 * We need to do a wakeup on the space,
684 * to rouse waiting threads. We defer
685 * this until the space is unlocked,
686 * because we don't want them to spin.
687 */
688
689 if (!is_active(space)) {
690 /*
691 * The space died while it was unlocked.
692 */
693
694 is_done_growing(space);
695 is_write_unlock(space);
696 thread_wakeup((event_t) space);
697 it_entries_free(its, table);
698 is_write_lock(space);
699 return KERN_SUCCESS;
700 }
701
702 /* If the space changed while unlocked, go back and process the changes */
703 if (space->is_low_mod < osize) {
704 assert(space->is_high_mod > 0);
705 low_mod = space->is_low_mod;
706 space->is_low_mod = osize;
707 hi_mod = space->is_high_mod;
708 space->is_high_mod = 0;
709 is_write_unlock(space);
710 #if IPC_ENTRY_GROW_STATS
711 rescan_count++;
712 if (rescan_count > ipc_entry_grow_rescan_max) {
713 ipc_entry_grow_rescan_max = rescan_count;
714 }
715
716 ipc_entry_grow_rescan++;
717 ipc_entry_grow_rescan_entries += hi_mod - low_mod + 1;
718 if (hi_mod - low_mod + 1 > ipc_entry_grow_rescan_entries_max) {
719 ipc_entry_grow_rescan_entries_max = hi_mod - low_mod + 1;
720 }
721 #endif
722 goto rescan;
723 }
724
725 /* link new free entries onto the rest of the freelist */
726 assert(table[free_index].ie_next == 0 &&
727 table[free_index].ie_object == IO_NULL);
728 table[free_index].ie_next = osize;
729
730 assert(space->is_table == otable);
731 assert((space->is_table_next == its) ||
732 (target_size != ITS_SIZE_NONE));
733 assert(space->is_table_size == osize);
734
735 space->is_table = table;
736 space->is_table_size = size;
737 space->is_table_next = nits;
738 space->is_table_free += size - osize;
739
740 is_done_growing(space);
741 is_write_unlock(space);
742
743 thread_wakeup((event_t) space);
744
745 /*
746 * Now we need to free the old table.
747 */
748 it_entries_free(oits, otable);
749 is_write_lock(space);
750
751 return KERN_SUCCESS;
752 }
753
754
755 /*
756 * Routine: ipc_entry_name_mask
757 * Purpose:
758 * Ensure a mach port name has the default ipc entry
759 * generation bits set. This can be used to ensure that
760 * a name passed in by user space matches names generated
761 * by the kernel.
762 * Conditions:
763 * None.
764 * Returns:
765 * 'name' input with default generation bits masked or added
766 * as appropriate.
767 */
768 mach_port_name_t
769 ipc_entry_name_mask(mach_port_name_t name)
770 {
771 #ifndef NO_PORT_GEN
772 static mach_port_name_t null_name = MACH_PORT_MAKE(0, IE_BITS_GEN_MASK + IE_BITS_GEN_ONE);
773 return name | null_name;
774 #else
775 static mach_port_name_t null_name = MACH_PORT_MAKE(0, ~(IE_BITS_GEN_MASK + IE_BITS_GEN_ONE));
776 return name & ~null_name;
777 #endif
778 }