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