]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ipc/ipc_splay.c
xnu-792.6.56.tar.gz
[apple/xnu.git] / osfmk / ipc / ipc_splay.c
CommitLineData
1c79356b 1/*
91447636 2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
1c79356b
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
ff6e181a
A
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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
1c79356b 12 *
ff6e181a
A
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
ff6e181a
A
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
1c79356b
A
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*
24 * @OSF_COPYRIGHT@
25 */
1c79356b
A
26/*
27 * Mach Operating System
28 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
29 * All Rights Reserved.
30 *
31 * Permission to use, copy, modify and distribute this software and its
32 * documentation is hereby granted, provided that both the copyright
33 * notice and this permission notice appear in all copies of the
34 * software, derivative works or modified versions, and any portions
35 * thereof, and that both notices appear in supporting documentation.
36 *
37 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
38 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
39 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
40 *
41 * Carnegie Mellon requests users of this software to return to
42 *
43 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
44 * School of Computer Science
45 * Carnegie Mellon University
46 * Pittsburgh PA 15213-3890
47 *
48 * any improvements or extensions that they make and grant Carnegie Mellon
49 * the rights to redistribute these changes.
50 */
51/*
52 */
53/*
54 * File: ipc/ipc_splay.c
55 * Author: Rich Draves
56 * Date: 1989
57 *
58 * Primitive splay tree operations.
59 */
60
61#include <mach/port.h>
62#include <kern/assert.h>
63#include <kern/macro_help.h>
64#include <ipc/ipc_entry.h>
65#include <ipc/ipc_splay.h>
66
67/*
68 * Splay trees are self-adjusting binary search trees.
69 * They have the following attractive properties:
70 * 1) Space efficient; only two pointers per entry.
71 * 2) Robust performance; amortized O(log n) per operation.
72 * 3) Recursion not needed.
73 * This makes them a good fall-back data structure for those
74 * entries that don't fit into the lookup table.
75 *
76 * The paper by Sleator and Tarjan, JACM v. 32, no. 3, pp. 652-686,
77 * describes the splaying operation. ipc_splay_prim_lookup
78 * and ipc_splay_prim_assemble implement the top-down splay
79 * described on p. 669.
80 *
81 * The tree is stored in an unassembled form. If ist_root is null,
82 * then the tree has no entries. Otherwise, ist_name records
83 * the value used for the last lookup. ist_root points to the
84 * middle tree obtained from the top-down splay. ist_ltree and
85 * ist_rtree point to left and right subtrees, whose entries
86 * are all smaller (larger) than those in the middle tree.
87 * ist_ltreep and ist_rtreep are pointers to fields in the
88 * left and right subtrees. ist_ltreep points to the rchild field
89 * of the largest entry in ltree, and ist_rtreep points to the
90 * lchild field of the smallest entry in rtree. The pointed-to
91 * fields aren't initialized. If the left (right) subtree is null,
92 * then ist_ltreep (ist_rtreep) points to the ist_ltree (ist_rtree)
93 * field in the splay structure itself.
94 *
95 * The primary advantage of the unassembled form is that repeated
96 * unsuccessful lookups are efficient. In particular, an unsuccessful
97 * lookup followed by an insert only requires one splaying operation.
98 *
99 * The traversal algorithm works via pointer inversion.
100 * When descending down the tree, child pointers are reversed
101 * to point back to the parent entry. When ascending,
102 * the pointers are restored to their original value.
103 *
104 * The biggest potential problem with the splay tree implementation
105 * is that the operations, even lookup, require an exclusive lock.
106 * If IPC spaces are protected with exclusive locks, then
107 * the splay tree doesn't require its own lock, and ist_lock/ist_unlock
108 * needn't do anything. If IPC spaces are protected with read/write
109 * locks then ist_lock/ist_unlock should provide exclusive access.
110 *
111 * If it becomes important to let lookups run in parallel,
112 * or if the restructuring makes lookups too expensive, then
113 * there is hope. Use a read/write lock on the splay tree.
114 * Keep track of the number of entries in the tree. When doing
115 * a lookup, first try a non-restructuring lookup with a read lock held,
116 * with a bound (based on log of size of the tree) on the number of
117 * entries to traverse. If the lookup runs up against the bound,
118 * then take a write lock and do a reorganizing lookup.
119 * This way, if lookups only access roughly balanced parts
120 * of the tree, then lookups run in parallel and do no restructuring.
121 *
122 * The traversal algorithm currently requires an exclusive lock.
123 * If that is a problem, the tree could be changed from an lchild/rchild
124 * representation to a leftmost child/right sibling representation.
125 * In conjunction with non-restructing lookups, this would let
126 * lookups and traversals all run in parallel. But this representation
127 * is more complicated and would slow down the operations.
128 */
129
130/*
131 * Boundary values to hand to ipc_splay_prim_lookup:
132 */
133
134#define MACH_PORT_SMALLEST ((mach_port_name_t) 0)
135#define MACH_PORT_LARGEST ((mach_port_name_t) ~0)
136
137/*
138 * Routine: ipc_splay_prim_lookup
139 * Purpose:
140 * Searches for the node labeled name in the splay tree.
141 * Returns three nodes (treep, ltreep, rtreep) and
142 * two pointers to nodes (ltreepp, rtreepp).
143 *
144 * ipc_splay_prim_lookup splits the supplied tree into
145 * three subtrees, left, middle, and right, returned
146 * in ltreep, treep, and rtreep.
147 *
148 * If name is present in the tree, then it is at
149 * the root of the middle tree. Otherwise, the root
150 * of the middle tree is the last node traversed.
151 *
152 * ipc_splay_prim_lookup returns a pointer into
153 * the left subtree, to the rchild field of its
154 * largest node, in ltreepp. It returns a pointer
155 * into the right subtree, to the lchild field of its
156 * smallest node, in rtreepp.
157 */
158
159static void
160ipc_splay_prim_lookup(
161 mach_port_name_t name,
162 ipc_tree_entry_t tree,
163 ipc_tree_entry_t *treep,
164 ipc_tree_entry_t *ltreep,
165 ipc_tree_entry_t **ltreepp,
166 ipc_tree_entry_t *rtreep,
167 ipc_tree_entry_t **rtreepp)
168{
169 mach_port_name_t tname; /* temp name */
170 ipc_tree_entry_t lchild, rchild; /* temp child pointers */
171
172 assert(tree != ITE_NULL);
173
174#define link_left \
175MACRO_BEGIN \
176 *ltreep = tree; \
177 ltreep = &tree->ite_rchild; \
178 tree = *ltreep; \
179MACRO_END
180
181#define link_right \
182MACRO_BEGIN \
183 *rtreep = tree; \
184 rtreep = &tree->ite_lchild; \
185 tree = *rtreep; \
186MACRO_END
187
188#define rotate_left \
189MACRO_BEGIN \
190 ipc_tree_entry_t temp = tree; \
191 \
192 tree = temp->ite_rchild; \
193 temp->ite_rchild = tree->ite_lchild; \
194 tree->ite_lchild = temp; \
195MACRO_END
196
197#define rotate_right \
198MACRO_BEGIN \
199 ipc_tree_entry_t temp = tree; \
200 \
201 tree = temp->ite_lchild; \
202 temp->ite_lchild = tree->ite_rchild; \
203 tree->ite_rchild = temp; \
204MACRO_END
205
206 while (name != (tname = tree->ite_name)) {
207 if (name < tname) {
208 /* descend to left */
209
210 lchild = tree->ite_lchild;
211 if (lchild == ITE_NULL)
212 break;
213 tname = lchild->ite_name;
214
215 if ((name < tname) &&
216 (lchild->ite_lchild != ITE_NULL))
217 rotate_right;
218 link_right;
219 if ((name > tname) &&
220 (lchild->ite_rchild != ITE_NULL))
221 link_left;
222 } else {
223 /* descend to right */
224
225 rchild = tree->ite_rchild;
226 if (rchild == ITE_NULL)
227 break;
228 tname = rchild->ite_name;
229
230 if ((name > tname) &&
231 (rchild->ite_rchild != ITE_NULL))
232 rotate_left;
233 link_left;
234 if ((name < tname) &&
235 (rchild->ite_lchild != ITE_NULL))
236 link_right;
237 }
238
239 assert(tree != ITE_NULL);
240 }
241
242 *treep = tree;
243 *ltreepp = ltreep;
244 *rtreepp = rtreep;
245
246#undef link_left
247#undef link_right
248#undef rotate_left
249#undef rotate_right
250}
251
252/*
253 * Routine: ipc_splay_prim_assemble
254 * Purpose:
255 * Assembles the results of ipc_splay_prim_lookup
256 * into a splay tree with the found node at the root.
257 *
258 * ltree and rtree are by-reference so storing
259 * through ltreep and rtreep can change them.
260 */
261
262static void
263ipc_splay_prim_assemble(
264 ipc_tree_entry_t tree,
265 ipc_tree_entry_t *ltree,
266 ipc_tree_entry_t *ltreep,
267 ipc_tree_entry_t *rtree,
268 ipc_tree_entry_t *rtreep)
269{
270 assert(tree != ITE_NULL);
271
272 *ltreep = tree->ite_lchild;
273 *rtreep = tree->ite_rchild;
274
275 tree->ite_lchild = *ltree;
276 tree->ite_rchild = *rtree;
277}
278
279/*
280 * Routine: ipc_splay_tree_init
281 * Purpose:
282 * Initialize a raw splay tree for use.
283 */
284
285void
286ipc_splay_tree_init(
287 ipc_splay_tree_t splay)
288{
289 splay->ist_root = ITE_NULL;
290}
291
292/*
293 * Routine: ipc_splay_tree_pick
294 * Purpose:
295 * Picks and returns a random entry in a splay tree.
296 * Returns FALSE if the splay tree is empty.
297 */
298
299boolean_t
300ipc_splay_tree_pick(
301 ipc_splay_tree_t splay,
302 mach_port_name_t *namep,
303 ipc_tree_entry_t *entryp)
304{
305 ipc_tree_entry_t root;
306
307 ist_lock(splay);
308
309 root = splay->ist_root;
310 if (root != ITE_NULL) {
311 *namep = root->ite_name;
312 *entryp = root;
313 }
314
315 ist_unlock(splay);
316
317 return root != ITE_NULL;
318}
319
320/*
321 * Routine: ipc_splay_tree_lookup
322 * Purpose:
323 * Finds an entry in a splay tree.
324 * Returns ITE_NULL if not found.
325 */
326
327ipc_tree_entry_t
328ipc_splay_tree_lookup(
329 ipc_splay_tree_t splay,
330 mach_port_name_t name)
331{
332 ipc_tree_entry_t root;
333
334 ist_lock(splay);
335
336 root = splay->ist_root;
337 if (root != ITE_NULL) {
338 if (splay->ist_name != name) {
339 ipc_splay_prim_assemble(root,
340 &splay->ist_ltree, splay->ist_ltreep,
341 &splay->ist_rtree, splay->ist_rtreep);
342 ipc_splay_prim_lookup(name, root, &root,
343 &splay->ist_ltree, &splay->ist_ltreep,
344 &splay->ist_rtree, &splay->ist_rtreep);
345 splay->ist_name = name;
346 splay->ist_root = root;
347 }
348
349 if (name != root->ite_name)
350 root = ITE_NULL;
351 }
352
353 ist_unlock(splay);
354
355 return root;
356}
357
358/*
359 * Routine: ipc_splay_tree_insert
360 * Purpose:
361 * Inserts a new entry into a splay tree.
362 * The caller supplies a new entry.
363 * The name can't already be present in the tree.
364 */
365
366void
367ipc_splay_tree_insert(
368 ipc_splay_tree_t splay,
369 mach_port_name_t name,
370 ipc_tree_entry_t entry)
371{
372 ipc_tree_entry_t root;
373
374 assert(entry != ITE_NULL);
375
376 ist_lock(splay);
377
378 root = splay->ist_root;
379 if (root == ITE_NULL) {
380 entry->ite_lchild = ITE_NULL;
381 entry->ite_rchild = ITE_NULL;
382 } else {
383 if (splay->ist_name != name) {
384 ipc_splay_prim_assemble(root,
385 &splay->ist_ltree, splay->ist_ltreep,
386 &splay->ist_rtree, splay->ist_rtreep);
387 ipc_splay_prim_lookup(name, root, &root,
388 &splay->ist_ltree, &splay->ist_ltreep,
389 &splay->ist_rtree, &splay->ist_rtreep);
390 }
391
392 assert(root->ite_name != name);
393
394 if (name < root->ite_name) {
395 assert(root->ite_lchild == ITE_NULL);
396
397 *splay->ist_ltreep = ITE_NULL;
398 *splay->ist_rtreep = root;
399 } else {
400 assert(root->ite_rchild == ITE_NULL);
401
402 *splay->ist_ltreep = root;
403 *splay->ist_rtreep = ITE_NULL;
404 }
405
406 entry->ite_lchild = splay->ist_ltree;
407 entry->ite_rchild = splay->ist_rtree;
408 }
409
410 entry->ite_name = name;
411 splay->ist_root = entry;
412 splay->ist_name = name;
413 splay->ist_ltreep = &splay->ist_ltree;
414 splay->ist_rtreep = &splay->ist_rtree;
415
416 ist_unlock(splay);
417}
418
419/*
420 * Routine: ipc_splay_tree_delete
421 * Purpose:
422 * Deletes an entry from a splay tree.
423 * The name must be present in the tree.
424 * Frees the entry.
425 *
426 * The "entry" argument isn't currently used.
427 * Other implementations might want it, though.
428 */
429
430void
431ipc_splay_tree_delete(
91447636
A
432 ipc_splay_tree_t splay,
433 mach_port_name_t name,
434 __assert_only ipc_tree_entry_t entry)
1c79356b
A
435{
436 ipc_tree_entry_t root, saved;
437
438 ist_lock(splay);
439
440 root = splay->ist_root;
441 assert(root != ITE_NULL);
442
443 if (splay->ist_name != name) {
444 ipc_splay_prim_assemble(root,
445 &splay->ist_ltree, splay->ist_ltreep,
446 &splay->ist_rtree, splay->ist_rtreep);
447 ipc_splay_prim_lookup(name, root, &root,
448 &splay->ist_ltree, &splay->ist_ltreep,
449 &splay->ist_rtree, &splay->ist_rtreep);
450 }
451
452 assert(root->ite_name == name);
453 assert(root == entry);
454
455 *splay->ist_ltreep = root->ite_lchild;
456 *splay->ist_rtreep = root->ite_rchild;
457 ite_free(root);
458
459 root = splay->ist_ltree;
460 saved = splay->ist_rtree;
461
462 if (root == ITE_NULL)
463 root = saved;
464 else if (saved != ITE_NULL) {
465 /*
466 * Find the largest node in the left subtree, and splay it
467 * to the root. Then add the saved right subtree.
468 */
469
470 ipc_splay_prim_lookup(MACH_PORT_LARGEST, root, &root,
471 &splay->ist_ltree, &splay->ist_ltreep,
472 &splay->ist_rtree, &splay->ist_rtreep);
473 ipc_splay_prim_assemble(root,
474 &splay->ist_ltree, splay->ist_ltreep,
475 &splay->ist_rtree, splay->ist_rtreep);
476
477 assert(root->ite_rchild == ITE_NULL);
478 root->ite_rchild = saved;
479 }
480
481 splay->ist_root = root;
482 if (root != ITE_NULL) {
483 splay->ist_name = root->ite_name;
484 splay->ist_ltreep = &splay->ist_ltree;
485 splay->ist_rtreep = &splay->ist_rtree;
486 }
487
488 ist_unlock(splay);
489}
490
491/*
492 * Routine: ipc_splay_tree_split
493 * Purpose:
494 * Split a splay tree. Puts all entries smaller than "name"
495 * into a new tree, "small".
496 *
497 * Doesn't do locking on "small", because nobody else
498 * should be fiddling with the uninitialized tree.
499 */
500
501void
502ipc_splay_tree_split(
503 ipc_splay_tree_t splay,
504 mach_port_name_t name,
505 ipc_splay_tree_t small)
506{
507 ipc_tree_entry_t root;
508
509 ipc_splay_tree_init(small);
510
511 ist_lock(splay);
512
513 root = splay->ist_root;
514 if (root != ITE_NULL) {
515 /* lookup name, to get it (or last traversed) to the top */
516
517 if (splay->ist_name != name) {
518 ipc_splay_prim_assemble(root,
519 &splay->ist_ltree, splay->ist_ltreep,
520 &splay->ist_rtree, splay->ist_rtreep);
521 ipc_splay_prim_lookup(name, root, &root,
522 &splay->ist_ltree, &splay->ist_ltreep,
523 &splay->ist_rtree, &splay->ist_rtreep);
524 }
525
526 if (root->ite_name < name) {
527 /* root goes into small */
528
529 *splay->ist_ltreep = root->ite_lchild;
530 *splay->ist_rtreep = ITE_NULL;
531 root->ite_lchild = splay->ist_ltree;
532 assert(root->ite_rchild == ITE_NULL);
533
534 small->ist_root = root;
535 small->ist_name = root->ite_name;
536 small->ist_ltreep = &small->ist_ltree;
537 small->ist_rtreep = &small->ist_rtree;
538
539 /* rtree goes into splay */
540
541 root = splay->ist_rtree;
542 splay->ist_root = root;
543 if (root != ITE_NULL) {
544 splay->ist_name = root->ite_name;
545 splay->ist_ltreep = &splay->ist_ltree;
546 splay->ist_rtreep = &splay->ist_rtree;
547 }
548 } else {
549 /* root stays in splay */
550
551 *splay->ist_ltreep = root->ite_lchild;
552 root->ite_lchild = ITE_NULL;
553
554 splay->ist_root = root;
555 splay->ist_name = name;
556 splay->ist_ltreep = &splay->ist_ltree;
557
558 /* ltree goes into small */
559
560 root = splay->ist_ltree;
561 small->ist_root = root;
562 if (root != ITE_NULL) {
563 small->ist_name = root->ite_name;
564 small->ist_ltreep = &small->ist_ltree;
565 small->ist_rtreep = &small->ist_rtree;
566 }
567 }
568 }
569
570 ist_unlock(splay);
571}
572
573/*
574 * Routine: ipc_splay_tree_join
575 * Purpose:
576 * Joins two splay trees. Merges the entries in "small",
577 * which must all be smaller than the entries in "splay",
578 * into "splay".
579 */
580
581void
582ipc_splay_tree_join(
583 ipc_splay_tree_t splay,
584 ipc_splay_tree_t small)
585{
586 ipc_tree_entry_t sroot;
587
588 /* pull entries out of small */
589
590 ist_lock(small);
591
592 sroot = small->ist_root;
593 if (sroot != ITE_NULL) {
594 ipc_splay_prim_assemble(sroot,
595 &small->ist_ltree, small->ist_ltreep,
596 &small->ist_rtree, small->ist_rtreep);
597 small->ist_root = ITE_NULL;
598 }
599
600 ist_unlock(small);
601
602 /* put entries, if any, into splay */
603
604 if (sroot != ITE_NULL) {
605 ipc_tree_entry_t root;
606
607 ist_lock(splay);
608
609 root = splay->ist_root;
610 if (root == ITE_NULL) {
611 root = sroot;
612 } else {
613 /* get smallest entry in splay tree to top */
614
615 if (splay->ist_name != MACH_PORT_SMALLEST) {
616 ipc_splay_prim_assemble(root,
617 &splay->ist_ltree, splay->ist_ltreep,
618 &splay->ist_rtree, splay->ist_rtreep);
619 ipc_splay_prim_lookup(MACH_PORT_SMALLEST,
620 root, &root,
621 &splay->ist_ltree, &splay->ist_ltreep,
622 &splay->ist_rtree, &splay->ist_rtreep);
623 }
624
625 ipc_splay_prim_assemble(root,
626 &splay->ist_ltree, splay->ist_ltreep,
627 &splay->ist_rtree, splay->ist_rtreep);
628
629 assert(root->ite_lchild == ITE_NULL);
630 assert(sroot->ite_name < root->ite_name);
631 root->ite_lchild = sroot;
632 }
633
634 splay->ist_root = root;
635 splay->ist_name = root->ite_name;
636 splay->ist_ltreep = &splay->ist_ltree;
637 splay->ist_rtreep = &splay->ist_rtree;
638
639 ist_unlock(splay);
640 }
641}
642
643/*
644 * Routine: ipc_splay_tree_bounds
645 * Purpose:
646 * Given a name, returns the largest value present
647 * in the tree that is smaller than or equal to the name,
648 * or ~0 if no such value exists. Similarly, returns
649 * the smallest value present that is greater than or
650 * equal to the name, or 0 if no such value exists.
651 *
652 * Hence, if
653 * lower = upper, then lower = name = upper
654 * and name is present in the tree
655 * lower = ~0 and upper = 0,
656 * then the tree is empty
657 * lower = ~0 and upper > 0, then name < upper
658 * and upper is smallest value in tree
659 * lower < ~0 and upper = 0, then lower < name
660 * and lower is largest value in tree
661 * lower < ~0 and upper > 0, then lower < name < upper
662 * and they are tight bounds on name
663 *
664 * (Note MACH_PORT_SMALLEST = 0 and MACH_PORT_LARGEST = ~0.)
665 */
666
667void
668ipc_splay_tree_bounds(
669 ipc_splay_tree_t splay,
670 mach_port_name_t name,
671 mach_port_name_t *lowerp,
672 mach_port_name_t *upperp)
673{
674 ipc_tree_entry_t root;
675
676 ist_lock(splay);
677
678 root = splay->ist_root;
679 if (root == ITE_NULL) {
680 *lowerp = MACH_PORT_LARGEST;
681 *upperp = MACH_PORT_SMALLEST;
682 } else {
683 mach_port_name_t rname;
684
685 if (splay->ist_name != name) {
686 ipc_splay_prim_assemble(root,
687 &splay->ist_ltree, splay->ist_ltreep,
688 &splay->ist_rtree, splay->ist_rtreep);
689 ipc_splay_prim_lookup(name, root, &root,
690 &splay->ist_ltree, &splay->ist_ltreep,
691 &splay->ist_rtree, &splay->ist_rtreep);
692 splay->ist_name = name;
693 splay->ist_root = root;
694 }
695
696 rname = root->ite_name;
697
698 /*
699 * OK, it's a hack. We convert the ltreep and rtreep
700 * pointers back into real entry pointers,
701 * so we can pick the names out of the entries.
702 */
703
704 if (rname <= name)
705 *lowerp = rname;
706 else if (splay->ist_ltreep == &splay->ist_ltree)
707 *lowerp = MACH_PORT_LARGEST;
708 else {
709 ipc_tree_entry_t entry;
710
711 entry = (ipc_tree_entry_t)
712 ((char *)splay->ist_ltreep -
713 ((char *)&root->ite_rchild -
714 (char *)root));
715 *lowerp = entry->ite_name;
716 }
717
718 if (rname >= name)
719 *upperp = rname;
720 else if (splay->ist_rtreep == &splay->ist_rtree)
721 *upperp = MACH_PORT_SMALLEST;
722 else {
723 ipc_tree_entry_t entry;
724
725 entry = (ipc_tree_entry_t)
726 ((char *)splay->ist_rtreep -
727 ((char *)&root->ite_lchild -
728 (char *)root));
729 *upperp = entry->ite_name;
730 }
731 }
732
733 ist_unlock(splay);
734}
735
736/*
737 * Routine: ipc_splay_traverse_start
738 * Routine: ipc_splay_traverse_next
739 * Routine: ipc_splay_traverse_finish
740 * Purpose:
741 * Perform a symmetric order traversal of a splay tree.
742 * Usage:
743 * for (entry = ipc_splay_traverse_start(splay);
744 * entry != ITE_NULL;
745 * entry = ipc_splay_traverse_next(splay, delete)) {
746 * do something with entry
747 * }
748 * ipc_splay_traverse_finish(splay);
749 *
750 * If "delete" is TRUE, then the current entry
751 * is removed from the tree and deallocated.
752 *
753 * During the traversal, the splay tree is locked.
754 */
755
756ipc_tree_entry_t
757ipc_splay_traverse_start(
758 ipc_splay_tree_t splay)
759{
760 ipc_tree_entry_t current, parent;
761
762 ist_lock(splay);
763
764 current = splay->ist_root;
765 if (current != ITE_NULL) {
766 ipc_splay_prim_assemble(current,
767 &splay->ist_ltree, splay->ist_ltreep,
768 &splay->ist_rtree, splay->ist_rtreep);
769
770 parent = ITE_NULL;
771
772 while (current->ite_lchild != ITE_NULL) {
773 ipc_tree_entry_t next;
774
775 next = current->ite_lchild;
776 current->ite_lchild = parent;
777 parent = current;
778 current = next;
779 }
780
781 splay->ist_ltree = current;
782 splay->ist_rtree = parent;
783 }
784
785 return current;
786}
787
788ipc_tree_entry_t
789ipc_splay_traverse_next(
790 ipc_splay_tree_t splay,
791 boolean_t delete)
792{
793 ipc_tree_entry_t current, parent;
794
795 /* pick up where traverse_entry left off */
796
797 current = splay->ist_ltree;
798 parent = splay->ist_rtree;
799 assert(current != ITE_NULL);
800
801 if (!delete)
802 goto traverse_right;
803
804 /* we must delete current and patch the tree */
805
806 if (current->ite_lchild == ITE_NULL) {
807 if (current->ite_rchild == ITE_NULL) {
808 /* like traverse_back, but with deletion */
809
810 if (parent == ITE_NULL) {
811 ite_free(current);
812
813 splay->ist_root = ITE_NULL;
814 return ITE_NULL;
815 }
816
817 if (current->ite_name < parent->ite_name) {
818 ite_free(current);
819
820 current = parent;
821 parent = current->ite_lchild;
822 current->ite_lchild = ITE_NULL;
823 goto traverse_entry;
824 } else {
825 ite_free(current);
826
827 current = parent;
828 parent = current->ite_rchild;
829 current->ite_rchild = ITE_NULL;
830 goto traverse_back;
831 }
832 } else {
833 ipc_tree_entry_t prev;
834
835 prev = current;
836 current = current->ite_rchild;
837 ite_free(prev);
838 goto traverse_left;
839 }
840 } else {
841 if (current->ite_rchild == ITE_NULL) {
842 ipc_tree_entry_t prev;
843
844 prev = current;
845 current = current->ite_lchild;
846 ite_free(prev);
847 goto traverse_back;
848 } else {
849 ipc_tree_entry_t prev;
850 ipc_tree_entry_t ltree, rtree;
851 ipc_tree_entry_t *ltreep, *rtreep;
852
853 /* replace current with largest of left children */
854
855 prev = current;
856 ipc_splay_prim_lookup(MACH_PORT_LARGEST,
857 current->ite_lchild, &current,
858 &ltree, &ltreep, &rtree, &rtreep);
859 ipc_splay_prim_assemble(current,
860 &ltree, ltreep, &rtree, rtreep);
861
862 assert(current->ite_rchild == ITE_NULL);
863 current->ite_rchild = prev->ite_rchild;
864 ite_free(prev);
865 goto traverse_right;
866 }
867 }
868 /*NOTREACHED*/
869
870 /*
871 * A state machine: for each entry, we
872 * 1) traverse left subtree
873 * 2) traverse the entry
874 * 3) traverse right subtree
875 * 4) traverse back to parent
876 */
877
878 traverse_left:
879 if (current->ite_lchild != ITE_NULL) {
880 ipc_tree_entry_t next;
881
882 next = current->ite_lchild;
883 current->ite_lchild = parent;
884 parent = current;
885 current = next;
886 goto traverse_left;
887 }
888
889 traverse_entry:
890 splay->ist_ltree = current;
891 splay->ist_rtree = parent;
892 return current;
893
894 traverse_right:
895 if (current->ite_rchild != ITE_NULL) {
896 ipc_tree_entry_t next;
897
898 next = current->ite_rchild;
899 current->ite_rchild = parent;
900 parent = current;
901 current = next;
902 goto traverse_left;
903 }
904
905 traverse_back:
906 if (parent == ITE_NULL) {
907 splay->ist_root = current;
908 return ITE_NULL;
909 }
910
911 if (current->ite_name < parent->ite_name) {
912 ipc_tree_entry_t prev;
913
914 prev = current;
915 current = parent;
916 parent = current->ite_lchild;
917 current->ite_lchild = prev;
918 goto traverse_entry;
919 } else {
920 ipc_tree_entry_t prev;
921
922 prev = current;
923 current = parent;
924 parent = current->ite_rchild;
925 current->ite_rchild = prev;
926 goto traverse_back;
927 }
928}
929
930void
931ipc_splay_traverse_finish(
932 ipc_splay_tree_t splay)
933{
934 ipc_tree_entry_t root;
935
936 root = splay->ist_root;
937 if (root != ITE_NULL) {
938 splay->ist_name = root->ite_name;
939 splay->ist_ltreep = &splay->ist_ltree;
940 splay->ist_rtreep = &splay->ist_rtree;
941 }
942
943 ist_unlock(splay);
944}
945