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