|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * @OSF_COPYRIGHT@
24: */
25: /*
26: * Mach Operating System
27: * Copyright (c) 1991,1990,1989 Carnegie Mellon University
28: * All Rights Reserved.
29: *
30: * Permission to use, copy, modify and distribute this software and its
31: * documentation is hereby granted, provided that both the copyright
32: * notice and this permission notice appear in all copies of the
33: * software, derivative works or modified versions, and any portions
34: * thereof, and that both notices appear in supporting documentation.
35: *
36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
39: *
40: * Carnegie Mellon requests users of this software to return to
41: *
42: * Software Distribution Coordinator or [email protected]
43: * School of Computer Science
44: * Carnegie Mellon University
45: * Pittsburgh PA 15213-3890
46: *
47: * any improvements or extensions that they make and grant Carnegie Mellon
48: * the rights to redistribute these changes.
49: */
50: /*
51: */
52: /*
53: * File: ipc/ipc_entry.c
54: * Author: Rich Draves
55: * Date: 1989
56: *
57: * Primitive functions to manipulate translation entries.
58: */
59:
60: #include <mach_kdb.h>
61: #include <mach_debug.h>
62:
63: #include <mach/kern_return.h>
64: #include <mach/port.h>
65: #include <kern/assert.h>
66: #include <kern/sched_prim.h>
67: #include <kern/zalloc.h>
68: #include <kern/misc_protos.h>
69: #if MACH_KDB
70: #include <kern/task.h>
71: #endif
72: #include <ipc/port.h>
73: #include <ipc/ipc_entry.h>
74: #include <ipc/ipc_space.h>
75: #include <ipc/ipc_splay.h>
76: #include <ipc/ipc_object.h>
77: #include <ipc/ipc_hash.h>
78: #include <ipc/ipc_table.h>
79: #include <ipc/ipc_port.h>
80: #include <string.h>
81:
82: zone_t ipc_tree_entry_zone;
83:
84:
85:
86: /*
87: * Forward declarations
88: */
89: boolean_t ipc_entry_tree_collision(
90: ipc_space_t space,
91: mach_port_name_t name);
92:
93: /*
94: * Routine: ipc_entry_tree_collision
95: * Purpose:
96: * Checks if "name" collides with an allocated name
97: * in the space's tree. That is, returns TRUE
98: * if the splay tree contains a name with the same
99: * index as "name".
100: * Conditions:
101: * The space is locked (read or write) and active.
102: */
103:
104: boolean_t
105: ipc_entry_tree_collision(
106: ipc_space_t space,
107: mach_port_name_t name)
108: {
109: mach_port_index_t index;
110: mach_port_name_t lower, upper;
111:
112: assert(space->is_active);
113:
114: /*
115: * Check if we collide with the next smaller name
116: * or the next larger name.
117: */
118:
119: ipc_splay_tree_bounds(&space->is_tree, name, &lower, &upper);
120:
121: index = MACH_PORT_INDEX(name);
122: return (((lower != ~0) && (MACH_PORT_INDEX(lower) == index)) ||
123: ((upper != 0) && (MACH_PORT_INDEX(upper) == index)));
124: }
125:
126: /*
127: * Routine: ipc_entry_lookup
128: * Purpose:
129: * Searches for an entry, given its name.
130: * Conditions:
131: * The space must be read or write locked throughout.
132: * The space must be active.
133: */
134:
135: ipc_entry_t
136: ipc_entry_lookup(
137: ipc_space_t space,
138: mach_port_name_t name)
139: {
140: mach_port_index_t index;
141: ipc_entry_t entry;
142:
143: assert(space->is_active);
144:
145:
146: index = MACH_PORT_INDEX(name);
147: /*
148: * If space is fast, we assume no splay tree and name within table
149: * bounds, but still check generation numbers (if enabled) and
150: * look for null entries.
151: */
152: if (is_fast_space(space)) {
153: entry = &space->is_table[index];
154: if (IE_BITS_GEN(entry->ie_bits) != MACH_PORT_GEN(name) ||
155: IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
156: entry = IE_NULL;
157: }
158: else
159: if (index < space->is_table_size) {
160: entry = &space->is_table[index];
161: if (IE_BITS_GEN(entry->ie_bits) != MACH_PORT_GEN(name))
162: if (entry->ie_bits & IE_BITS_COLLISION) {
163: assert(space->is_tree_total > 0);
164: goto tree_lookup;
165: } else
166: entry = IE_NULL;
167: else if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
168: entry = IE_NULL;
169: } else if (space->is_tree_total == 0)
170: entry = IE_NULL;
171: else {
172: tree_lookup:
173: entry = (ipc_entry_t)
174: ipc_splay_tree_lookup(&space->is_tree, name);
175: /* with sub-space introduction, an entry may appear in */
176: /* the splay tree and yet not show rights for this subspace */
177: if(entry != IE_NULL) {
178: if(!(IE_BITS_TYPE(entry->ie_bits)))
179: entry = IE_NULL;
180: }
181: }
182:
183: assert((entry == IE_NULL) || IE_BITS_TYPE(entry->ie_bits));
184: return entry;
185: }
186:
187: /*
188: * Routine: ipc_entry_get
189: * Purpose:
190: * Tries to allocate an entry out of the space.
191: * Conditions:
192: * The space is write-locked and active throughout.
193: * An object may be locked. Will not allocate memory.
194: * Returns:
195: * KERN_SUCCESS A free entry was found.
196: * KERN_NO_SPACE No entry allocated.
197: */
198:
199: kern_return_t
200: ipc_entry_get(
201: ipc_space_t space,
202: mach_port_name_t *namep,
203: ipc_entry_t *entryp)
204: {
205: ipc_entry_t table;
206: mach_port_index_t first_free;
207: ipc_entry_t free_entry;
208:
209: assert(space->is_active);
210:
211: {
212: table = space->is_table;
213: first_free = table->ie_next;
214:
215: if (first_free == 0)
216: return KERN_NO_SPACE;
217:
218: free_entry = &table[first_free];
219: table->ie_next = free_entry->ie_next;
220: }
221:
222: /*
223: * Initialize the new entry. We need only
224: * increment the generation number and clear ie_request.
225: */
226: {
227: mach_port_name_t new_name;
228: mach_port_gen_t gen;
229:
230: gen = IE_BITS_NEW_GEN(free_entry->ie_bits);
231: free_entry->ie_bits = gen;
232: free_entry->ie_request = 0;
233:
234: /*
235: * The new name can't be MACH_PORT_NULL because index
236: * is non-zero. It can't be MACH_PORT_DEAD because
237: * the table isn't allowed to grow big enough.
238: * (See comment in ipc/ipc_table.h.)
239: */
240: new_name = MACH_PORT_MAKE(first_free, gen);
241: assert(MACH_PORT_VALID(new_name));
242: *namep = new_name;
243: }
244:
245: assert(free_entry->ie_object == IO_NULL);
246:
247: *entryp = free_entry;
248: return KERN_SUCCESS;
249: }
250:
251: /*
252: * Routine: ipc_entry_alloc
253: * Purpose:
254: * Allocate an entry out of the space.
255: * Conditions:
256: * The space is not locked before, but it is write-locked after
257: * if the call is successful. May allocate memory.
258: * Returns:
259: * KERN_SUCCESS An entry was allocated.
260: * KERN_INVALID_TASK The space is dead.
261: * KERN_NO_SPACE No room for an entry in the space.
262: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory for an entry.
263: */
264:
265: kern_return_t
266: ipc_entry_alloc(
267: ipc_space_t space,
268: mach_port_name_t *namep,
269: ipc_entry_t *entryp)
270: {
271: kern_return_t kr;
272:
273: is_write_lock(space);
274:
275: for (;;) {
276: if (!space->is_active) {
277: is_write_unlock(space);
278: return KERN_INVALID_TASK;
279: }
280:
281: kr = ipc_entry_get(space, namep, entryp);
282: if (kr == KERN_SUCCESS)
283: return kr;
284:
285: kr = ipc_entry_grow_table(space, ITS_SIZE_NONE);
286: if (kr != KERN_SUCCESS)
287: return kr; /* space is unlocked */
288: }
289: }
290:
291: /*
292: * Routine: ipc_entry_alloc_name
293: * Purpose:
294: * Allocates/finds an entry with a specific name.
295: * If an existing entry is returned, its type will be nonzero.
296: * Conditions:
297: * The space is not locked before, but it is write-locked after
298: * if the call is successful. May allocate memory.
299: * Returns:
300: * KERN_SUCCESS Found existing entry with same name.
301: * KERN_SUCCESS Allocated a new entry.
302: * KERN_INVALID_TASK The space is dead.
303: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
304: */
305:
306: kern_return_t
307: ipc_entry_alloc_name(
308: ipc_space_t space,
309: mach_port_name_t name,
310: ipc_entry_t *entryp)
311: {
312: mach_port_index_t index = MACH_PORT_INDEX(name);
313: mach_port_gen_t gen = MACH_PORT_GEN(name);
314: ipc_tree_entry_t tentry = ITE_NULL;
315:
316: assert(MACH_PORT_VALID(name));
317:
318:
319: is_write_lock(space);
320:
321: for (;;) {
322: ipc_entry_t entry;
323: ipc_tree_entry_t tentry2;
324: ipc_table_size_t its;
325:
326: if (!space->is_active) {
327: is_write_unlock(space);
328: if (tentry) ite_free(tentry);
329: return KERN_INVALID_TASK;
330: }
331:
332: /*
333: * If we are under the table cutoff,
334: * there are usually four cases:
335: * 1) The entry is reserved (index 0)
336: * 2) The entry is inuse, for the same name
337: * 3) The entry is inuse, for a different name
338: * 4) The entry is free
339: * For a task with a "fast" IPC space, we disallow
340: * cases 1) and 3), because ports cannot be renamed.
341: */
342: if (index < space->is_table_size) {
343: ipc_entry_t table = space->is_table;
344:
345: entry = &table[index];
346:
347: if (index == 0) {
348: assert(!IE_BITS_TYPE(entry->ie_bits));
349: assert(!IE_BITS_GEN(entry->ie_bits));
350: } else if (IE_BITS_TYPE(entry->ie_bits)) {
351: if (IE_BITS_GEN(entry->ie_bits) == gen) {
352: *entryp = entry;
353: assert(!tentry);
354: return KERN_SUCCESS;
355: }
356: } else {
357: mach_port_index_t free_index, next_index;
358:
359: /*
360: * Rip the entry out of the free list.
361: */
362:
363: for (free_index = 0;
364: (next_index = table[free_index].ie_next)
365: != index;
366: free_index = next_index)
367: continue;
368:
369: table[free_index].ie_next =
370: table[next_index].ie_next;
371:
372: entry->ie_bits = gen;
373: entry->ie_request = 0;
374: *entryp = entry;
375:
376: assert(entry->ie_object == IO_NULL);
377: if (is_fast_space(space))
378: assert(!tentry);
379: else if (tentry)
380: ite_free(tentry);
381: return KERN_SUCCESS;
382: }
383: }
384:
385: /*
386: * In a fast space, ipc_entry_alloc_name may be
387: * used only to add a right to a port name already
388: * known in this space.
389: */
390: if (is_fast_space(space)) {
391: is_write_unlock(space);
392: assert(!tentry);
393: return KERN_FAILURE;
394: }
395:
396: /*
397: * Before trying to allocate any memory,
398: * check if the entry already exists in the tree.
399: * This avoids spurious resource errors.
400: * The splay tree makes a subsequent lookup/insert
401: * of the same name cheap, so this costs little.
402: */
403:
404: if ((space->is_tree_total > 0) &&
405: ((tentry2 = ipc_splay_tree_lookup(&space->is_tree, name))
406: != ITE_NULL)) {
407: assert(tentry2->ite_space == space);
408: assert(IE_BITS_TYPE(tentry2->ite_bits));
409:
410: *entryp = &tentry2->ite_entry;
411: if (tentry) ite_free(tentry);
412: return KERN_SUCCESS;
413: }
414:
415: its = space->is_table_next;
416:
417: /*
418: * Check if the table should be grown.
419: *
420: * Note that if space->is_table_size == its->its_size,
421: * then we won't ever try to grow the table.
422: *
423: * Note that we are optimistically assuming that name
424: * doesn't collide with any existing names. (So if
425: * it were entered into the tree, is_tree_small would
426: * be incremented.) This is OK, because even in that
427: * case, we don't lose memory by growing the table.
428: */
429: if ((space->is_table_size <= index) &&
430: (index < its->its_size) &&
431: (((its->its_size - space->is_table_size) *
432: sizeof(struct ipc_entry)) <
433: ((space->is_tree_small + 1) *
434: sizeof(struct ipc_tree_entry)))) {
435: kern_return_t kr;
436:
437: /*
438: * Can save space by growing the table.
439: * Because the space will be unlocked,
440: * we must restart.
441: */
442:
443: kr = ipc_entry_grow_table(space, ITS_SIZE_NONE);
444: assert(kr != KERN_NO_SPACE);
445: if (kr != KERN_SUCCESS) {
446: /* space is unlocked */
447: if (tentry) ite_free(tentry);
448: return kr;
449: }
450:
451: continue;
452: }
453:
454: /*
455: * If a splay-tree entry was allocated previously,
456: * go ahead and insert it into the tree.
457: */
458:
459: if (tentry != ITE_NULL) {
460:
461: space->is_tree_total++;
462:
463: if (index < space->is_table_size) {
464: entry = &space->is_table[index];
465: entry->ie_bits |= IE_BITS_COLLISION;
466: } else if ((index < its->its_size) &&
467: !ipc_entry_tree_collision(space, name))
468: space->is_tree_small++;
469:
470: ipc_splay_tree_insert(&space->is_tree, name, tentry);
471: tentry->ite_bits = 0;
472: tentry->ite_request = 0;
473: tentry->ite_object = IO_NULL;
474: tentry->ite_space = space;
475: *entryp = &tentry->ite_entry;
476: return KERN_SUCCESS;
477: }
478:
479: /*
480: * Allocate a tree entry and try again.
481: */
482:
483: is_write_unlock(space);
484: tentry = ite_alloc();
485: if (tentry == ITE_NULL)
486: return KERN_RESOURCE_SHORTAGE;
487: is_write_lock(space);
488: }
489: }
490:
491: /*
492: * Routine: ipc_entry_dealloc
493: * Purpose:
494: * Deallocates an entry from a space.
495: * Conditions:
496: * The space must be write-locked throughout.
497: * The space must be active.
498: */
499:
500: void
501: ipc_entry_dealloc(
502: ipc_space_t space,
503: mach_port_name_t name,
504: ipc_entry_t entry)
505: {
506: ipc_entry_t table;
507: ipc_entry_num_t size;
508: mach_port_index_t index;
509:
510: assert(space->is_active);
511: assert(entry->ie_object == IO_NULL);
512: assert(entry->ie_request == 0);
513:
514: index = MACH_PORT_INDEX(name);
515: table = space->is_table;
516: size = space->is_table_size;
517:
518: if (is_fast_space(space)) {
519: assert(index < size);
520: assert(entry == &table[index]);
521: assert(IE_BITS_GEN(entry->ie_bits) == MACH_PORT_GEN(name));
522: assert(!(entry->ie_bits & IE_BITS_COLLISION));
523: entry->ie_bits &= IE_BITS_GEN_MASK;
524: entry->ie_next = table->ie_next;
525: table->ie_next = index;
526: return;
527: }
528:
529:
530: if ((index < size) && (entry == &table[index])) {
531: assert(IE_BITS_GEN(entry->ie_bits) == MACH_PORT_GEN(name));
532:
533: if (entry->ie_bits & IE_BITS_COLLISION) {
534: struct ipc_splay_tree small, collisions;
535: ipc_tree_entry_t tentry;
536: mach_port_name_t tname;
537: boolean_t pick;
538: ipc_entry_bits_t bits;
539: ipc_object_t obj;
540:
541: /* must move an entry from tree to table */
542:
543: ipc_splay_tree_split(&space->is_tree,
544: MACH_PORT_MAKE(index+1, 0),
545: &collisions);
546: ipc_splay_tree_split(&collisions,
547: MACH_PORT_MAKE(index, 0),
548: &small);
549:
550: pick = ipc_splay_tree_pick(&collisions,
551: &tname, &tentry);
552: assert(pick);
553: assert(MACH_PORT_INDEX(tname) == index);
554:
555: entry->ie_object = obj = tentry->ite_object;
556: entry->ie_bits = tentry->ite_bits|MACH_PORT_GEN(tname);
557: entry->ie_request = tentry->ite_request;
558:
559: assert(tentry->ite_space == space);
560:
561: if (IE_BITS_TYPE(tentry->ite_bits)==MACH_PORT_TYPE_SEND) {
562: ipc_hash_global_delete(space, obj,
563: tname, tentry);
564: ipc_hash_local_insert(space, obj,
565: index, entry);
566: }
567:
568: ipc_splay_tree_delete(&collisions, tname, tentry);
569:
570: assert(space->is_tree_total > 0);
571: space->is_tree_total--;
572:
573: /* check if collision bit should still be on */
574:
575: pick = ipc_splay_tree_pick(&collisions,
576: &tname, &tentry);
577: if (pick) {
578: entry->ie_bits |= IE_BITS_COLLISION;
579: ipc_splay_tree_join(&space->is_tree,
580: &collisions);
581: }
582:
583: ipc_splay_tree_join(&space->is_tree, &small);
584:
585: } else {
586: entry->ie_bits &= IE_BITS_GEN_MASK;
587: entry->ie_next = table->ie_next;
588: table->ie_next = index;
589: }
590:
591: } else {
592: ipc_tree_entry_t tentry = (ipc_tree_entry_t) entry;
593:
594: assert(tentry->ite_space == space);
595:
596: ipc_splay_tree_delete(&space->is_tree, name, tentry);
597:
598: assert(space->is_tree_total > 0);
599: space->is_tree_total--;
600:
601: if (index < size) {
602: ipc_entry_t ientry = &table[index];
603:
604: assert(ientry->ie_bits & IE_BITS_COLLISION);
605:
606: if (!ipc_entry_tree_collision(space, name))
607: ientry->ie_bits &= ~IE_BITS_COLLISION;
608:
609: } else if ((index < space->is_table_next->its_size) &&
610: !ipc_entry_tree_collision(space, name)) {
611:
612: assert(space->is_tree_small > 0);
613:
614: space->is_tree_small--;
615: }
616: }
617: }
618:
619: /*
620: * Routine: ipc_entry_grow_table
621: * Purpose:
622: * Grows the table in a space.
623: * Conditions:
624: * The space must be write-locked and active before.
625: * If successful, it is also returned locked.
626: * Allocates memory.
627: * Returns:
628: * KERN_SUCCESS Grew the table.
629: * KERN_SUCCESS Somebody else grew the table.
630: * KERN_SUCCESS The space died.
631: * KERN_NO_SPACE Table has maximum size already.
632: * KERN_RESOURCE_SHORTAGE Couldn't allocate a new table.
633: */
634:
635: kern_return_t
636: ipc_entry_grow_table(
637: ipc_space_t space,
638: int target_size)
639: {
640: ipc_entry_num_t osize, size, nsize, psize;
641:
642: do {
643: boolean_t reallocated=FALSE;
644:
645: ipc_entry_t otable, table;
646: ipc_table_size_t oits, its, nits;
647: mach_port_index_t i, free_index;
648:
649: assert(space->is_active);
650:
651: if (space->is_growing) {
652: /*
653: * Somebody else is growing the table.
654: * We just wait for them to finish.
655: */
656:
657: assert_wait((event_t) space, THREAD_UNINT);
658: is_write_unlock(space);
659: thread_block((void (*)(void)) 0);
660: is_write_lock(space);
661: return KERN_SUCCESS;
662: }
663:
664: otable = space->is_table;
665:
666: its = space->is_table_next;
667: size = its->its_size;
668:
669: /*
670: * Since is_table_next points to the next natural size
671: * we can identify the current size entry.
672: */
673: oits = its - 1;
674: osize = oits->its_size;
675:
676: /*
677: * If there is no target size, then the new size is simply
678: * specified by is_table_next. If there is a target
679: * size, then search for the next entry.
680: */
681: if (target_size != ITS_SIZE_NONE) {
682: if (target_size <= osize) {
683: is_write_unlock(space);
684: return KERN_SUCCESS;
685: }
686:
687: psize = osize;
688: while ((psize != size) && (target_size > size)) {
689: psize = size;
690: its++;
691: size = its->its_size;
692: }
693: if (psize == size) {
694: is_write_unlock(space);
695: return KERN_NO_SPACE;
696: }
697: }
698: nits = its + 1;
699: nsize = nits->its_size;
700:
701: if (osize == size) {
702: is_write_unlock(space);
703: return KERN_NO_SPACE;
704: }
705:
706: assert((osize < size) && (size <= nsize));
707:
708: /*
709: * OK, we'll attempt to grow the table.
710: * The realloc requires that the old table
711: * remain in existence.
712: */
713:
714: space->is_growing = TRUE;
715: is_write_unlock(space);
716:
717: if (it_entries_reallocable(oits)) {
718: table = it_entries_realloc(oits, otable, its);
719: reallocated=TRUE;
720: }
721: else {
722: table = it_entries_alloc(its);
723: }
724:
725: is_write_lock(space);
726: space->is_growing = FALSE;
727:
728: /*
729: * We need to do a wakeup on the space,
730: * to rouse waiting threads. We defer
731: * this until the space is unlocked,
732: * because we don't want them to spin.
733: */
734:
735: if (table == IE_NULL) {
736: is_write_unlock(space);
737: thread_wakeup((event_t) space);
738: return KERN_RESOURCE_SHORTAGE;
739: }
740:
741: if (!space->is_active) {
742: /*
743: * The space died while it was unlocked.
744: */
745:
746: is_write_unlock(space);
747: thread_wakeup((event_t) space);
748: it_entries_free(its, table);
749: is_write_lock(space);
750: return KERN_SUCCESS;
751: }
752:
753: assert(space->is_table == otable);
754: assert((space->is_table_next == its) ||
755: (target_size != ITS_SIZE_NONE));
756: assert(space->is_table_size == osize);
757:
758: space->is_table = table;
759: space->is_table_size = size;
760: space->is_table_next = nits;
761:
762: /*
763: * If we did a realloc, it remapped the data.
764: * Otherwise we copy by hand first. Then we have
765: * to zero the new part and the old local hash
766: * values.
767: */
768: if (!reallocated)
769: (void) memcpy((void *) table, (const void *) otable,
770: osize * (sizeof(struct ipc_entry)));
771:
772: for (i = 0; i < osize; i++)
773: table[i].ie_index = 0;
774:
775: (void) memset((void *) (table + osize) , 0,
776: ((size - osize) * (sizeof(struct ipc_entry))));
777:
778: /*
779: * Put old entries into the reverse hash table.
780: */
781: for (i = 0; i < osize; i++) {
782: ipc_entry_t entry = &table[i];
783:
784: if (IE_BITS_TYPE(entry->ie_bits)==MACH_PORT_TYPE_SEND) {
785: ipc_hash_local_insert(space, entry->ie_object,
786: i, entry);
787: }
788: }
789:
790: /*
791: * If there are entries in the splay tree,
792: * then we have work to do:
793: * 1) transfer entries to the table
794: * 2) update is_tree_small
795: */
796: assert(!is_fast_space(space) || space->is_tree_total == 0);
797: if (space->is_tree_total > 0) {
798: mach_port_index_t index;
799: boolean_t delete;
800: struct ipc_splay_tree ignore;
801: struct ipc_splay_tree move;
802: struct ipc_splay_tree small;
803: ipc_entry_num_t nosmall;
804: ipc_tree_entry_t tentry;
805:
806: /*
807: * The splay tree divides into four regions,
808: * based on the index of the entries:
809: * 1) 0 <= index < osize
810: * 2) osize <= index < size
811: * 3) size <= index < nsize
812: * 4) nsize <= index
813: *
814: * Entries in the first part are ignored.
815: * Entries in the second part, that don't
816: * collide, are moved into the table.
817: * Entries in the third part, that don't
818: * collide, are counted for is_tree_small.
819: * Entries in the fourth part are ignored.
820: */
821:
822: ipc_splay_tree_split(&space->is_tree,
823: MACH_PORT_MAKE(nsize, 0),
824: &small);
825: ipc_splay_tree_split(&small,
826: MACH_PORT_MAKE(size, 0),
827: &move);
828: ipc_splay_tree_split(&move,
829: MACH_PORT_MAKE(osize, 0),
830: &ignore);
831:
832: /* move entries into the table */
833:
834: for (tentry = ipc_splay_traverse_start(&move);
835: tentry != ITE_NULL;
836: tentry = ipc_splay_traverse_next(&move, delete)) {
837:
838: mach_port_name_t name;
839: mach_port_gen_t gen;
840: mach_port_type_t type;
841: ipc_entry_bits_t bits;
842: ipc_object_t obj;
843: ipc_entry_t entry;
844:
845: name = tentry->ite_name;
846: gen = MACH_PORT_GEN(name);
847: index = MACH_PORT_INDEX(name);
848:
849: assert(tentry->ite_space == space);
850: assert((osize <= index) && (index < size));
851:
852: entry = &table[index];
853: bits = entry->ie_bits;
854: if (IE_BITS_TYPE(bits)) {
855: assert(IE_BITS_GEN(bits) != gen);
856: entry->ie_bits |= IE_BITS_COLLISION;
857: delete = FALSE;
858: continue;
859: }
860:
861: bits = tentry->ite_bits;
862: type = IE_BITS_TYPE(bits);
863: assert(type != MACH_PORT_TYPE_NONE);
864:
865: entry->ie_bits = bits | gen;
866: entry->ie_request = tentry->ite_request;
867: entry->ie_object = obj = tentry->ite_object;
868:
869: if (type == MACH_PORT_TYPE_SEND) {
870: ipc_hash_global_delete(space, obj,
871: name, tentry);
872: ipc_hash_local_insert(space, obj,
873: index, entry);
874: }
875: space->is_tree_total--;
876: delete = TRUE;
877: }
878: ipc_splay_traverse_finish(&move);
879:
880: /* count entries for is_tree_small */
881:
882: nosmall = 0; index = 0;
883: for (tentry = ipc_splay_traverse_start(&small);
884: tentry != ITE_NULL;
885: tentry = ipc_splay_traverse_next(&small, FALSE)) {
886: mach_port_index_t nindex;
887:
888: nindex = MACH_PORT_INDEX(tentry->ite_name);
889:
890: if (nindex != index) {
891: nosmall++;
892: index = nindex;
893: }
894: }
895: ipc_splay_traverse_finish(&small);
896:
897: assert(nosmall <= (nsize - size));
898: assert(nosmall <= space->is_tree_total);
899: space->is_tree_small = nosmall;
900:
901: /* put the splay tree back together */
902:
903: ipc_splay_tree_join(&space->is_tree, &small);
904: ipc_splay_tree_join(&space->is_tree, &move);
905: ipc_splay_tree_join(&space->is_tree, &ignore);
906: }
907:
908: /*
909: * Add entries in the new part which still aren't used
910: * to the free list. Add them in reverse order,
911: * and set the generation number to -1, so that
912: * early allocations produce "natural" names.
913: */
914:
915: free_index = table[0].ie_next;
916: for (i = size-1; i >= osize; --i) {
917: ipc_entry_t entry = &table[i];
918:
919: if (entry->ie_bits == 0) {
920: entry->ie_bits = IE_BITS_GEN_MASK;
921: entry->ie_next = free_index;
922: free_index = i;
923: }
924: }
925: table[0].ie_next = free_index;
926:
927: /*
928: * Now we need to free the old table.
929: * If the space dies or grows while unlocked,
930: * then we can quit here.
931: */
932: is_write_unlock(space);
933: thread_wakeup((event_t) space);
934:
935: it_entries_free(oits, otable);
936: is_write_lock(space);
937: if (!space->is_active || (space->is_table_next != nits))
938: return KERN_SUCCESS;
939:
940: /*
941: * We might have moved enough entries from
942: * the splay tree into the table that
943: * the table can be profitably grown again.
944: *
945: * Note that if size == nsize, then
946: * space->is_tree_small == 0.
947: */
948: } while ((space->is_tree_small > 0) &&
949: (((nsize - size) * sizeof(struct ipc_entry)) <
950: (space->is_tree_small * sizeof(struct ipc_tree_entry))));
951:
952: return KERN_SUCCESS;
953: }
954:
955:
956: #if MACH_KDB
957: #include <ddb/db_output.h>
958: #define printf kdbprintf
959:
960: ipc_entry_t db_ipc_object_by_name(
961: task_t task,
962: mach_port_name_t name);
963:
964:
965: ipc_entry_t
966: db_ipc_object_by_name(
967: task_t task,
968: mach_port_name_t name)
969: {
970: ipc_space_t space = task->itk_space;
971: ipc_entry_t entry;
972:
973:
974: entry = ipc_entry_lookup(space, name);
975: if(entry != IE_NULL) {
976: iprintf("(task 0x%x, name 0x%x) ==> object 0x%x\n",
977: task, name, entry->ie_object);
978: return (ipc_entry_t) entry->ie_object;
979: }
980: return entry;
981: }
982: #endif /* MACH_KDB */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.