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