FreeBSD/Linux Kernel Cross Reference
sys/ipc/ipc_splay.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: ipc_splay.c,v $
29 * Revision 2.7 92/08/03 17:35:40 jfriedl
30 * removed silly prototypes
31 * [92/08/02 jfriedl]
32 *
33 * Revision 2.6 92/05/21 17:11:48 jfriedl
34 * tried prototypes.
35 * [92/05/20 jfriedl]
36 *
37 * Revision 2.5 91/10/09 16:10:41 af
38 * Revision 2.4.2.1 91/09/16 10:16:00 rpd
39 *
40 * Revision 2.4.2.1 91/09/16 10:16:00 rpd
41 * Added MACH_PORT_SMALLEST, MACH_PORT_LARGEST definitions to reduce lint.
42 * [91/09/02 rpd]
43 *
44 * Revision 2.4 91/05/14 16:37:08 mrt
45 * Correcting copyright
46 *
47 * Revision 2.3 91/02/05 17:23:52 mrt
48 * Changed to new Mach copyright
49 * [91/02/01 15:51:43 mrt]
50 *
51 * Revision 2.2 90/06/02 14:51:49 rpd
52 * Created for new IPC.
53 * [90/03/26 21:03:46 rpd]
54 *
55 */
56 /*
57 * File: ipc/ipc_splay.c
58 * Author: Rich Draves
59 * Date: 1989
60 *
61 * Primitive splay tree operations.
62 */
63
64 #include <mach/port.h>
65 #include <kern/assert.h>
66 #include <kern/macro_help.h>
67 #include <ipc/ipc_entry.h>
68 #include <ipc/ipc_splay.h>
69
70
71
72 /*
73 * Splay trees are self-adjusting binary search trees.
74 * They have the following attractive properties:
75 * 1) Space efficient; only two pointers per entry.
76 * 2) Robust performance; amortized O(log n) per operation.
77 * 3) Recursion not needed.
78 * This makes them a good fall-back data structure for those
79 * entries that don't fit into the lookup table.
80 *
81 * The paper by Sleator and Tarjan, JACM v. 32, no. 3, pp. 652-686,
82 * describes the splaying operation. ipc_splay_prim_lookup
83 * and ipc_splay_prim_assemble implement the top-down splay
84 * described on p. 669.
85 *
86 * The tree is stored in an unassembled form. If ist_root is null,
87 * then the tree has no entries. Otherwise, ist_name records
88 * the value used for the last lookup. ist_root points to the
89 * middle tree obtained from the top-down splay. ist_ltree and
90 * ist_rtree point to left and right subtrees, whose entries
91 * are all smaller (larger) than those in the middle tree.
92 * ist_ltreep and ist_rtreep are pointers to fields in the
93 * left and right subtrees. ist_ltreep points to the rchild field
94 * of the largest entry in ltree, and ist_rtreep points to the
95 * lchild field of the smallest entry in rtree. The pointed-to
96 * fields aren't initialized. If the left (right) subtree is null,
97 * then ist_ltreep (ist_rtreep) points to the ist_ltree (ist_rtree)
98 * field in the splay structure itself.
99 *
100 * The primary advantage of the unassembled form is that repeated
101 * unsuccessful lookups are efficient. In particular, an unsuccessful
102 * lookup followed by an insert only requires one splaying operation.
103 *
104 * The traversal algorithm works via pointer inversion.
105 * When descending down the tree, child pointers are reversed
106 * to point back to the parent entry. When ascending,
107 * the pointers are restored to their original value.
108 *
109 * The biggest potential problem with the splay tree implementation
110 * is that the operations, even lookup, require an exclusive lock.
111 * If IPC spaces are protected with exclusive locks, then
112 * the splay tree doesn't require its own lock, and ist_lock/ist_unlock
113 * needn't do anything. If IPC spaces are protected with read/write
114 * locks then ist_lock/ist_unlock should provide exclusive access.
115 *
116 * If it becomes important to let lookups run in parallel,
117 * or if the restructuring makes lookups too expensive, then
118 * there is hope. Use a read/write lock on the splay tree.
119 * Keep track of the number of entries in the tree. When doing
120 * a lookup, first try a non-restructuring lookup with a read lock held,
121 * with a bound (based on log of size of the tree) on the number of
122 * entries to traverse. If the lookup runs up against the bound,
123 * then take a write lock and do a reorganizing lookup.
124 * This way, if lookups only access roughly balanced parts
125 * of the tree, then lookups run in parallel and do no restructuring.
126 *
127 * The traversal algorithm currently requires an exclusive lock.
128 * If that is a problem, the tree could be changed from an lchild/rchild
129 * representation to a leftmost child/right sibling representation.
130 * In conjunction with non-restructing lookups, this would let
131 * lookups and traversals all run in parallel. But this representation
132 * is more complicated and would slow down the operations.
133 */
134
135 /*
136 * Boundary values to hand to ipc_splay_prim_lookup:
137 */
138
139 #define MACH_PORT_SMALLEST ((mach_port_t) 0)
140 #define MACH_PORT_LARGEST ((mach_port_t) ~0)
141
142 /*
143 * Routine: ipc_splay_prim_lookup
144 * Purpose:
145 * Searches for the node labeled name in the splay tree.
146 * Returns three nodes (treep, ltreep, rtreep) and
147 * two pointers to nodes (ltreepp, rtreepp).
148 *
149 * ipc_splay_prim_lookup splits the supplied tree into
150 * three subtrees, left, middle, and right, returned
151 * in ltreep, treep, and rtreep.
152 *
153 * If name is present in the tree, then it is at
154 * the root of the middle tree. Otherwise, the root
155 * of the middle tree is the last node traversed.
156 *
157 * ipc_splay_prim_lookup returns a pointer into
158 * the left subtree, to the rchild field of its
159 * largest node, in ltreepp. It returns a pointer
160 * into the right subtree, to the lchild field of its
161 * smallest node, in rtreepp.
162 */
163
164 static void
165 ipc_splay_prim_lookup(name, tree, treep, ltreep, ltreepp, rtreep, rtreepp)
166 mach_port_t name;
167 ipc_tree_entry_t tree, *treep;
168 ipc_tree_entry_t *ltreep, **ltreepp;
169 ipc_tree_entry_t *rtreep, **rtreepp;
170 {
171 mach_port_t tname; /* temp name */
172 ipc_tree_entry_t lchild, rchild; /* temp child pointers */
173
174 assert(tree != ITE_NULL);
175
176 #define link_left \
177 MACRO_BEGIN \
178 *ltreep = tree; \
179 ltreep = &tree->ite_rchild; \
180 tree = *ltreep; \
181 MACRO_END
182
183 #define link_right \
184 MACRO_BEGIN \
185 *rtreep = tree; \
186 rtreep = &tree->ite_lchild; \
187 tree = *rtreep; \
188 MACRO_END
189
190 #define rotate_left \
191 MACRO_BEGIN \
192 ipc_tree_entry_t temp = tree; \
193 \
194 tree = temp->ite_rchild; \
195 temp->ite_rchild = tree->ite_lchild; \
196 tree->ite_lchild = temp; \
197 MACRO_END
198
199 #define rotate_right \
200 MACRO_BEGIN \
201 ipc_tree_entry_t temp = tree; \
202 \
203 tree = temp->ite_lchild; \
204 temp->ite_lchild = tree->ite_rchild; \
205 tree->ite_rchild = temp; \
206 MACRO_END
207
208 while (name != (tname = tree->ite_name)) {
209 if (name < tname) {
210 /* descend to left */
211
212 lchild = tree->ite_lchild;
213 if (lchild == ITE_NULL)
214 break;
215 tname = lchild->ite_name;
216
217 if ((name < tname) &&
218 (lchild->ite_lchild != ITE_NULL))
219 rotate_right;
220 link_right;
221 if ((name > tname) &&
222 (lchild->ite_rchild != ITE_NULL))
223 link_left;
224 } else {
225 /* descend to right */
226
227 rchild = tree->ite_rchild;
228 if (rchild == ITE_NULL)
229 break;
230 tname = rchild->ite_name;
231
232 if ((name > tname) &&
233 (rchild->ite_rchild != ITE_NULL))
234 rotate_left;
235 link_left;
236 if ((name < tname) &&
237 (rchild->ite_lchild != ITE_NULL))
238 link_right;
239 }
240
241 assert(tree != ITE_NULL);
242 }
243
244 *treep = tree;
245 *ltreepp = ltreep;
246 *rtreepp = rtreep;
247
248 #undef link_left
249 #undef link_right
250 #undef rotate_left
251 #undef rotate_right
252 }
253
254 /*
255 * Routine: ipc_splay_prim_assemble
256 * Purpose:
257 * Assembles the results of ipc_splay_prim_lookup
258 * into a splay tree with the found node at the root.
259 *
260 * ltree and rtree are by-reference so storing
261 * through ltreep and rtreep can change them.
262 */
263
264 static void
265 ipc_splay_prim_assemble(tree, ltree, ltreep, rtree, rtreep)
266 ipc_tree_entry_t tree;
267 ipc_tree_entry_t *ltree, *ltreep;
268 ipc_tree_entry_t *rtree, *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
285 void
286 ipc_splay_tree_init(splay)
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
299 boolean_t
300 ipc_splay_tree_pick(splay, namep, entryp)
301 ipc_splay_tree_t splay;
302 mach_port_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
327 ipc_tree_entry_t
328 ipc_splay_tree_lookup(splay, name)
329 ipc_splay_tree_t splay;
330 mach_port_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
366 void
367 ipc_splay_tree_insert(splay, name, entry)
368 ipc_splay_tree_t splay;
369 mach_port_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
430 void
431 ipc_splay_tree_delete(splay, name, entry)
432 ipc_splay_tree_t splay;
433 mach_port_t name;
434 ipc_tree_entry_t entry;
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
501 void
502 ipc_splay_tree_split(splay, name, small)
503 ipc_splay_tree_t splay;
504 mach_port_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
581 void
582 ipc_splay_tree_join(splay, small)
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
667 void
668 ipc_splay_tree_bounds(splay, name, lowerp, upperp)
669 ipc_splay_tree_t splay;
670 mach_port_t name;
671 mach_port_t *lowerp, *upperp;
672 {
673 ipc_tree_entry_t root;
674
675 ist_lock(splay);
676
677 root = splay->ist_root;
678 if (root == ITE_NULL) {
679 *lowerp = MACH_PORT_LARGEST;
680 *upperp = MACH_PORT_SMALLEST;
681 } else {
682 mach_port_t rname;
683
684 if (splay->ist_name != name) {
685 ipc_splay_prim_assemble(root,
686 &splay->ist_ltree, splay->ist_ltreep,
687 &splay->ist_rtree, splay->ist_rtreep);
688 ipc_splay_prim_lookup(name, root, &root,
689 &splay->ist_ltree, &splay->ist_ltreep,
690 &splay->ist_rtree, &splay->ist_rtreep);
691 splay->ist_name = name;
692 splay->ist_root = root;
693 }
694
695 rname = root->ite_name;
696
697 /*
698 * OK, it's a hack. We convert the ltreep and rtreep
699 * pointers back into real entry pointers,
700 * so we can pick the names out of the entries.
701 */
702
703 if (rname <= name)
704 *lowerp = rname;
705 else if (splay->ist_ltreep == &splay->ist_ltree)
706 *lowerp = MACH_PORT_LARGEST;
707 else {
708 ipc_tree_entry_t entry;
709
710 entry = (ipc_tree_entry_t)
711 ((char *)splay->ist_ltreep -
712 ((char *)&root->ite_rchild -
713 (char *)root));
714 *lowerp = entry->ite_name;
715 }
716
717 if (rname >= name)
718 *upperp = rname;
719 else if (splay->ist_rtreep == &splay->ist_rtree)
720 *upperp = MACH_PORT_SMALLEST;
721 else {
722 ipc_tree_entry_t entry;
723
724 entry = (ipc_tree_entry_t)
725 ((char *)splay->ist_rtreep -
726 ((char *)&root->ite_lchild -
727 (char *)root));
728 *upperp = entry->ite_name;
729 }
730 }
731
732 ist_unlock(splay);
733 }
734
735 /*
736 * Routine: ipc_splay_traverse_start
737 * Routine: ipc_splay_traverse_next
738 * Routine: ipc_splay_traverse_finish
739 * Purpose:
740 * Perform a symmetric order traversal of a splay tree.
741 * Usage:
742 * for (entry = ipc_splay_traverse_start(splay);
743 * entry != ITE_NULL;
744 * entry = ipc_splay_traverse_next(splay, delete)) {
745 * do something with entry
746 * }
747 * ipc_splay_traverse_finish(splay);
748 *
749 * If "delete" is TRUE, then the current entry
750 * is removed from the tree and deallocated.
751 *
752 * During the traversal, the splay tree is locked.
753 */
754
755 ipc_tree_entry_t
756 ipc_splay_traverse_start(splay)
757 ipc_splay_tree_t splay;
758 {
759 ipc_tree_entry_t current, parent;
760
761 ist_lock(splay);
762
763 current = splay->ist_root;
764 if (current != ITE_NULL) {
765 ipc_splay_prim_assemble(current,
766 &splay->ist_ltree, splay->ist_ltreep,
767 &splay->ist_rtree, splay->ist_rtreep);
768
769 parent = ITE_NULL;
770
771 while (current->ite_lchild != ITE_NULL) {
772 ipc_tree_entry_t next;
773
774 next = current->ite_lchild;
775 current->ite_lchild = parent;
776 parent = current;
777 current = next;
778 }
779
780 splay->ist_ltree = current;
781 splay->ist_rtree = parent;
782 }
783
784 return current;
785 }
786
787 ipc_tree_entry_t
788 ipc_splay_traverse_next(splay, delete)
789 ipc_splay_tree_t splay;
790 boolean_t delete;
791 {
792 ipc_tree_entry_t current, parent;
793
794 /* pick up where traverse_entry left off */
795
796 current = splay->ist_ltree;
797 parent = splay->ist_rtree;
798 assert(current != ITE_NULL);
799
800 if (!delete)
801 goto traverse_right;
802
803 /* we must delete current and patch the tree */
804
805 if (current->ite_lchild == ITE_NULL) {
806 if (current->ite_rchild == ITE_NULL) {
807 /* like traverse_back, but with deletion */
808
809 if (parent == ITE_NULL) {
810 ite_free(current);
811
812 splay->ist_root = ITE_NULL;
813 return ITE_NULL;
814 }
815
816 if (current->ite_name < parent->ite_name) {
817 ite_free(current);
818
819 current = parent;
820 parent = current->ite_lchild;
821 current->ite_lchild = ITE_NULL;
822 goto traverse_entry;
823 } else {
824 ite_free(current);
825
826 current = parent;
827 parent = current->ite_rchild;
828 current->ite_rchild = ITE_NULL;
829 goto traverse_back;
830 }
831 } else {
832 ipc_tree_entry_t prev;
833
834 prev = current;
835 current = current->ite_rchild;
836 ite_free(prev);
837 goto traverse_left;
838 }
839 } else {
840 if (current->ite_rchild == ITE_NULL) {
841 ipc_tree_entry_t prev;
842
843 prev = current;
844 current = current->ite_lchild;
845 ite_free(prev);
846 goto traverse_back;
847 } else {
848 ipc_tree_entry_t prev;
849 ipc_tree_entry_t ltree, rtree;
850 ipc_tree_entry_t *ltreep, *rtreep;
851
852 /* replace current with largest of left children */
853
854 prev = current;
855 ipc_splay_prim_lookup(MACH_PORT_LARGEST,
856 current->ite_lchild, ¤t,
857 <ree, <reep, &rtree, &rtreep);
858 ipc_splay_prim_assemble(current,
859 <ree, ltreep, &rtree, rtreep);
860
861 assert(current->ite_rchild == ITE_NULL);
862 current->ite_rchild = prev->ite_rchild;
863 ite_free(prev);
864 goto traverse_right;
865 }
866 }
867 /*NOTREACHED*/
868
869 /*
870 * A state machine: for each entry, we
871 * 1) traverse left subtree
872 * 2) traverse the entry
873 * 3) traverse right subtree
874 * 4) traverse back to parent
875 */
876
877 traverse_left:
878 if (current->ite_lchild != ITE_NULL) {
879 ipc_tree_entry_t next;
880
881 next = current->ite_lchild;
882 current->ite_lchild = parent;
883 parent = current;
884 current = next;
885 goto traverse_left;
886 }
887
888 traverse_entry:
889 splay->ist_ltree = current;
890 splay->ist_rtree = parent;
891 return current;
892
893 traverse_right:
894 if (current->ite_rchild != ITE_NULL) {
895 ipc_tree_entry_t next;
896
897 next = current->ite_rchild;
898 current->ite_rchild = parent;
899 parent = current;
900 current = next;
901 goto traverse_left;
902 }
903
904 traverse_back:
905 if (parent == ITE_NULL) {
906 splay->ist_root = current;
907 return ITE_NULL;
908 }
909
910 if (current->ite_name < parent->ite_name) {
911 ipc_tree_entry_t prev;
912
913 prev = current;
914 current = parent;
915 parent = current->ite_lchild;
916 current->ite_lchild = prev;
917 goto traverse_entry;
918 } else {
919 ipc_tree_entry_t prev;
920
921 prev = current;
922 current = parent;
923 parent = current->ite_rchild;
924 current->ite_rchild = prev;
925 goto traverse_back;
926 }
927 }
928
929 void
930 ipc_splay_traverse_finish(splay)
931 ipc_splay_tree_t splay;
932 {
933 ipc_tree_entry_t root;
934
935 root = splay->ist_root;
936 if (root != ITE_NULL) {
937 splay->ist_name = root->ite_name;
938 splay->ist_ltreep = &splay->ist_ltree;
939 splay->ist_rtreep = &splay->ist_rtree;
940 }
941
942 ist_unlock(splay);
943 }
944
Cache object: 6fe3af8cb581d85d4b21682897b010a9
|