|
|
1.1 root 1: /*
2: * Copyright (c) 2011-2015 Richard Braun.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: *
14: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24: *
25: *
26: * Upstream site with license notes :
27: * http://git.sceen.net/rbraun/librbraun.git/
28: */
29:
30: #include <kern/assert.h>
31: #include <kern/slab.h>
32: #include <mach/kern_return.h>
33: #include <stddef.h>
34: #include <string.h>
35:
36: #include "macros.h"
37: #include "rdxtree.h"
38: #include "rdxtree_i.h"
39:
40: /* XXX */
41: #define CHAR_BIT 8U
42: #define ERR_SUCCESS KERN_SUCCESS
43: #define ERR_BUSY KERN_INVALID_ARGUMENT
44: #define ERR_NOMEM KERN_RESOURCE_SHORTAGE
45:
46: /*
47: * Mask applied on an entry to obtain its address.
48: */
49: #define RDXTREE_ENTRY_ADDR_MASK (~0x3UL)
50:
51: /*
52: * Global properties used to shape radix trees.
53: */
54: #define RDXTREE_RADIX 6
55: #define RDXTREE_RADIX_SIZE (1UL << RDXTREE_RADIX)
56: #define RDXTREE_RADIX_MASK (RDXTREE_RADIX_SIZE - 1)
57:
58: #if RDXTREE_RADIX < 6
59: typedef unsigned long rdxtree_bm_t;
60: #define rdxtree_ffs(x) __builtin_ffsl(x)
61: #elif RDXTREE_RADIX == 6 /* RDXTREE_RADIX < 6 */
62: typedef unsigned long long rdxtree_bm_t;
63: #define rdxtree_ffs(x) __builtin_ffsll(x)
64: #else /* RDXTREE_RADIX < 6 */
65: #error "radix too high"
66: #endif /* RDXTREE_RADIX < 6 */
67:
68: /*
69: * Allocation bitmap size in bits.
70: */
71: #define RDXTREE_BM_SIZE (sizeof(rdxtree_bm_t) * CHAR_BIT)
72:
73: /*
74: * Empty/full allocation bitmap words.
75: */
76: #define RDXTREE_BM_EMPTY ((rdxtree_bm_t)0)
77: #define RDXTREE_BM_FULL \
78: ((~(rdxtree_bm_t)0) >> (RDXTREE_BM_SIZE - RDXTREE_RADIX_SIZE))
79:
80: /*
81: * These macros can be replaced by actual functions in an environment
82: * that provides lockless synchronization such as RCU.
83: */
84: #define llsync_assign_ptr(ptr, value) ((ptr) = (value))
85: #define llsync_read_ptr(ptr) (ptr)
86:
87: /*
88: * Radix tree node.
89: *
90: * The height of a tree is the number of nodes to traverse until stored
91: * pointers are reached. A height of 0 means the entries of a node (or the
92: * tree root) directly point to stored pointers.
93: *
94: * The index is valid if and only if the parent isn't NULL.
95: *
96: * Concerning the allocation bitmap, a bit is set when the node it denotes,
97: * or one of its children, can be used to allocate an entry. Conversely, a bit
98: * is clear when the matching node and all of its children have no free entry.
99: *
100: * In order to support safe lockless lookups, in particular during a resize,
101: * each node includes the height of its subtree, which is invariant during
102: * the entire node lifetime. Since the tree height does vary, it can't be
103: * used to determine whether the tree root is a node or a stored pointer.
104: * This implementation assumes that all nodes and stored pointers are at least
105: * 4-byte aligned, and uses the least significant bit of entries to indicate
106: * the pointer type. This bit is set for internal nodes, and clear for stored
107: * pointers so that they can be accessed from slots without conversion.
108: */
109: struct rdxtree_node {
110: struct rdxtree_node *parent;
111: unsigned int index;
112: unsigned int height;
113: unsigned int nr_entries;
114: rdxtree_bm_t alloc_bm;
115: void *entries[RDXTREE_RADIX_SIZE];
116: };
117:
118: /*
119: * We allocate nodes using the slab allocator.
120: */
121: static struct kmem_cache rdxtree_node_cache;
122:
123: void
124: rdxtree_cache_init(void)
125: {
126: kmem_cache_init(&rdxtree_node_cache, "rdxtree_node",
127: sizeof(struct rdxtree_node), 0, NULL, NULL, NULL, 0);
128: }
129:
130: #ifdef RDXTREE_ENABLE_NODE_CREATION_FAILURES
131: unsigned int rdxtree_fail_node_creation_threshold;
132: unsigned int rdxtree_nr_node_creations;
133: #endif /* RDXTREE_ENABLE_NODE_CREATION_FAILURES */
134:
135: static inline int
136: rdxtree_check_alignment(const void *ptr)
137: {
138: return ((unsigned long)ptr & ~RDXTREE_ENTRY_ADDR_MASK) == 0;
139: }
140:
141: static inline void *
142: rdxtree_entry_addr(void *entry)
143: {
144: return (void *)((unsigned long)entry & RDXTREE_ENTRY_ADDR_MASK);
145: }
146:
147: static inline int
148: rdxtree_entry_is_node(const void *entry)
149: {
150: return ((unsigned long)entry & 1) != 0;
151: }
152:
153: static inline void *
154: rdxtree_node_to_entry(struct rdxtree_node *node)
155: {
156: return (void *)((unsigned long)node | 1);
157: }
158:
159: static int
160: rdxtree_node_create(struct rdxtree_node **nodep, unsigned int height)
161: {
162: struct rdxtree_node *node;
163:
164: #ifdef RDXTREE_ENABLE_NODE_CREATION_FAILURES
165: if (rdxtree_fail_node_creation_threshold != 0) {
166: rdxtree_nr_node_creations++;
167:
168: if (rdxtree_nr_node_creations == rdxtree_fail_node_creation_threshold)
169: return ERR_NOMEM;
170: }
171: #endif /* RDXTREE_ENABLE_NODE_CREATION_FAILURES */
172:
173: node = (struct rdxtree_node *) kmem_cache_alloc(&rdxtree_node_cache);
174:
175: if (node == NULL)
176: return ERR_NOMEM;
177:
178: assert(rdxtree_check_alignment(node));
179: node->parent = NULL;
180: node->height = height;
181: node->nr_entries = 0;
182: node->alloc_bm = RDXTREE_BM_FULL;
183: memset(node->entries, 0, sizeof(node->entries));
184: *nodep = node;
185: return 0;
186: }
187:
188: static void
189: rdxtree_node_schedule_destruction(struct rdxtree_node *node)
190: {
191: /*
192: * This function is intended to use the appropriate interface to defer
193: * destruction until all read-side references are dropped in an
194: * environment that provides lockless synchronization.
195: *
196: * Otherwise, it simply "schedules" destruction immediately.
197: */
198: kmem_cache_free(&rdxtree_node_cache, (vm_offset_t) node);
199: }
200:
201: static inline void
202: rdxtree_node_link(struct rdxtree_node *node, struct rdxtree_node *parent,
203: unsigned int index)
204: {
205: node->parent = parent;
206: node->index = index;
207: }
208:
209: static inline void
210: rdxtree_node_unlink(struct rdxtree_node *node)
211: {
212: assert(node->parent != NULL);
213: node->parent = NULL;
214: }
215:
216: static inline int
217: rdxtree_node_full(struct rdxtree_node *node)
218: {
219: return (node->nr_entries == ARRAY_SIZE(node->entries));
220: }
221:
222: static inline int
223: rdxtree_node_empty(struct rdxtree_node *node)
224: {
225: return (node->nr_entries == 0);
226: }
227:
228: static inline void
229: rdxtree_node_insert(struct rdxtree_node *node, unsigned int index,
230: void *entry)
231: {
232: assert(index < ARRAY_SIZE(node->entries));
233: assert(node->entries[index] == NULL);
234:
235: node->nr_entries++;
236: llsync_assign_ptr(node->entries[index], entry);
237: }
238:
239: static inline void
240: rdxtree_node_insert_node(struct rdxtree_node *node, unsigned int index,
241: struct rdxtree_node *child)
242: {
243: rdxtree_node_insert(node, index, rdxtree_node_to_entry(child));
244: }
245:
246: static inline void
247: rdxtree_node_remove(struct rdxtree_node *node, unsigned int index)
248: {
249: assert(index < ARRAY_SIZE(node->entries));
250: assert(node->entries[index] != NULL);
251:
252: node->nr_entries--;
253: llsync_assign_ptr(node->entries[index], NULL);
254: }
255:
256: static inline void *
257: rdxtree_node_find(struct rdxtree_node *node, unsigned int *indexp)
258: {
259: unsigned int index;
260: void *ptr;
261:
262: index = *indexp;
263:
264: while (index < ARRAY_SIZE(node->entries)) {
265: ptr = rdxtree_entry_addr(llsync_read_ptr(node->entries[index]));
266:
267: if (ptr != NULL) {
268: *indexp = index;
269: return ptr;
270: }
271:
272: index++;
273: }
274:
275: return NULL;
276: }
277:
278: static inline void
279: rdxtree_node_bm_set(struct rdxtree_node *node, unsigned int index)
280: {
281: node->alloc_bm |= (rdxtree_bm_t)1 << index;
282: }
283:
284: static inline void
285: rdxtree_node_bm_clear(struct rdxtree_node *node, unsigned int index)
286: {
287: node->alloc_bm &= ~((rdxtree_bm_t)1 << index);
288: }
289:
290: static inline int
291: rdxtree_node_bm_is_set(struct rdxtree_node *node, unsigned int index)
292: {
293: return (node->alloc_bm & ((rdxtree_bm_t)1 << index));
294: }
295:
296: static inline int
297: rdxtree_node_bm_empty(struct rdxtree_node *node)
298: {
299: return (node->alloc_bm == RDXTREE_BM_EMPTY);
300: }
301:
302: static inline unsigned int
303: rdxtree_node_bm_first(struct rdxtree_node *node)
304: {
305: return rdxtree_ffs(node->alloc_bm) - 1;
306: }
307:
308: static inline rdxtree_key_t
309: rdxtree_max_key(unsigned int height)
310: {
311: size_t shift;
312:
313: shift = RDXTREE_RADIX * height;
314:
315: if (likely(shift < (sizeof(rdxtree_key_t) * CHAR_BIT)))
316: return ((rdxtree_key_t)1 << shift) - 1;
317: else
318: return ~((rdxtree_key_t)0);
319: }
320:
321: static void
322: rdxtree_shrink(struct rdxtree *tree)
323: {
324: struct rdxtree_node *node;
325: void *entry;
326:
327: while (tree->height > 0) {
328: node = rdxtree_entry_addr(tree->root);
329:
330: if (node->nr_entries != 1)
331: break;
332:
333: entry = node->entries[0];
334:
335: if (entry == NULL)
336: break;
337:
338: tree->height--;
339:
340: if (tree->height > 0)
341: rdxtree_node_unlink(rdxtree_entry_addr(entry));
342:
343: llsync_assign_ptr(tree->root, entry);
344: rdxtree_node_schedule_destruction(node);
345: }
346: }
347:
348: static int
349: rdxtree_grow(struct rdxtree *tree, rdxtree_key_t key)
350: {
351: struct rdxtree_node *root, *node;
352: unsigned int new_height;
353: int error;
354:
355: new_height = tree->height + 1;
356:
357: while (key > rdxtree_max_key(new_height))
358: new_height++;
359:
360: if (tree->root == NULL) {
361: tree->height = new_height;
362: return ERR_SUCCESS;
363: }
364:
365: root = rdxtree_entry_addr(tree->root);
366:
367: do {
368: error = rdxtree_node_create(&node, tree->height);
369:
370: if (error) {
371: rdxtree_shrink(tree);
372: return error;
373: }
374:
375: if (tree->height == 0)
376: rdxtree_node_bm_clear(node, 0);
377: else {
378: rdxtree_node_link(root, node, 0);
379:
380: if (rdxtree_node_bm_empty(root))
381: rdxtree_node_bm_clear(node, 0);
382: }
383:
384: rdxtree_node_insert(node, 0, tree->root);
385: tree->height++;
386: llsync_assign_ptr(tree->root, rdxtree_node_to_entry(node));
387: root = node;
388: } while (new_height > tree->height);
389:
390: return ERR_SUCCESS;
391: }
392:
393: static void
394: rdxtree_cleanup(struct rdxtree *tree, struct rdxtree_node *node)
395: {
396: struct rdxtree_node *prev;
397:
398: for (;;) {
399: if (likely(!rdxtree_node_empty(node))) {
400: if (unlikely(node->parent == NULL))
401: rdxtree_shrink(tree);
402:
403: break;
404: }
405:
406: if (node->parent == NULL) {
407: tree->height = 0;
408: llsync_assign_ptr(tree->root, NULL);
409: rdxtree_node_schedule_destruction(node);
410: break;
411: }
412:
413: prev = node;
414: node = node->parent;
415: rdxtree_node_unlink(prev);
416: rdxtree_node_remove(node, prev->index);
417: rdxtree_node_schedule_destruction(prev);
418: }
419: }
420:
421: static void
422: rdxtree_insert_bm_clear(struct rdxtree_node *node, unsigned int index)
423: {
424: for (;;) {
425: rdxtree_node_bm_clear(node, index);
426:
427: if (!rdxtree_node_full(node) || (node->parent == NULL))
428: break;
429:
430: index = node->index;
431: node = node->parent;
432: }
433: }
434:
435: int
436: rdxtree_insert_common(struct rdxtree *tree, rdxtree_key_t key,
437: void *ptr, void ***slotp)
438: {
439: struct rdxtree_node *node, *prev;
440: unsigned int height, shift, index = index;
441: int error;
442:
443: assert(ptr != NULL);
444: assert(rdxtree_check_alignment(ptr));
445:
446: if (unlikely(key > rdxtree_max_key(tree->height))) {
447: error = rdxtree_grow(tree, key);
448:
449: if (error)
450: return error;
451: }
452:
453: height = tree->height;
454:
455: if (unlikely(height == 0)) {
456: if (tree->root != NULL)
457: return ERR_BUSY;
458:
459: llsync_assign_ptr(tree->root, ptr);
460:
461: if (slotp != NULL)
462: *slotp = &tree->root;
463:
464: return ERR_SUCCESS;
465: }
466:
467: node = rdxtree_entry_addr(tree->root);
468: shift = (height - 1) * RDXTREE_RADIX;
469: prev = NULL;
470:
471: do {
472: if (node == NULL) {
473: error = rdxtree_node_create(&node, height - 1);
474:
475: if (error) {
476: if (prev == NULL)
477: tree->height = 0;
478: else
479: rdxtree_cleanup(tree, prev);
480:
481: return error;
482: }
483:
484: if (prev == NULL)
485: llsync_assign_ptr(tree->root, rdxtree_node_to_entry(node));
486: else {
487: rdxtree_node_link(node, prev, index);
488: rdxtree_node_insert_node(prev, index, node);
489: }
490: }
491:
492: prev = node;
493: index = (unsigned int)(key >> shift) & RDXTREE_RADIX_MASK;
494: node = rdxtree_entry_addr(prev->entries[index]);
495: shift -= RDXTREE_RADIX;
496: height--;
497: } while (height > 0);
498:
499: if (unlikely(node != NULL))
500: return ERR_BUSY;
501:
502: rdxtree_node_insert(prev, index, ptr);
503: rdxtree_insert_bm_clear(prev, index);
504:
505: if (slotp != NULL)
506: *slotp = &prev->entries[index];
507:
508: return ERR_SUCCESS;
509: }
510:
511: int
512: rdxtree_insert_alloc_common(struct rdxtree *tree, void *ptr,
513: rdxtree_key_t *keyp, void ***slotp)
514: {
515: struct rdxtree_node *node, *prev;
516: unsigned int height, shift, index = index;
517: rdxtree_key_t key;
518: int error;
519:
520: assert(ptr != NULL);
521: assert(rdxtree_check_alignment(ptr));
522:
523: height = tree->height;
524:
525: if (unlikely(height == 0)) {
526: if (tree->root == NULL) {
527: llsync_assign_ptr(tree->root, ptr);
528: *keyp = 0;
529:
530: if (slotp != NULL)
531: *slotp = &tree->root;
532:
533: return ERR_SUCCESS;
534: }
535:
536: goto grow;
537: }
538:
539: node = rdxtree_entry_addr(tree->root);
540: key = 0;
541: shift = (height - 1) * RDXTREE_RADIX;
542: prev = NULL;
543:
544: do {
545: if (node == NULL) {
546: error = rdxtree_node_create(&node, height - 1);
547:
548: if (error) {
549: rdxtree_cleanup(tree, prev);
550: return error;
551: }
552:
553: rdxtree_node_link(node, prev, index);
554: rdxtree_node_insert_node(prev, index, node);
555: }
556:
557: prev = node;
558: index = rdxtree_node_bm_first(node);
559:
560: if (index == (unsigned int)-1)
561: goto grow;
562:
563: key |= (rdxtree_key_t)index << shift;
564: node = rdxtree_entry_addr(node->entries[index]);
565: shift -= RDXTREE_RADIX;
566: height--;
567: } while (height > 0);
568:
569: rdxtree_node_insert(prev, index, ptr);
570: rdxtree_insert_bm_clear(prev, index);
571:
572: if (slotp != NULL)
573: *slotp = &prev->entries[index];
574:
575: goto out;
576:
577: grow:
578: key = rdxtree_max_key(height) + 1;
579: error = rdxtree_insert_common(tree, key, ptr, slotp);
580:
581: if (error)
582: return error;
583:
584: out:
585: *keyp = key;
586: return ERR_SUCCESS;
587: }
588:
589: static void
590: rdxtree_remove_bm_set(struct rdxtree_node *node, unsigned int index)
591: {
592: do {
593: rdxtree_node_bm_set(node, index);
594:
595: if (node->parent == NULL)
596: break;
597:
598: index = node->index;
599: node = node->parent;
600: } while (!rdxtree_node_bm_is_set(node, index));
601: }
602:
603: void *
604: rdxtree_remove(struct rdxtree *tree, rdxtree_key_t key)
605: {
606: struct rdxtree_node *node, *prev;
607: unsigned int height, shift, index;
608:
609: height = tree->height;
610:
611: if (unlikely(key > rdxtree_max_key(height)))
612: return NULL;
613:
614: node = rdxtree_entry_addr(tree->root);
615:
616: if (unlikely(height == 0)) {
617: llsync_assign_ptr(tree->root, NULL);
618: return node;
619: }
620:
621: shift = (height - 1) * RDXTREE_RADIX;
622:
623: do {
624: if (node == NULL)
625: return NULL;
626:
627: prev = node;
628: index = (unsigned int)(key >> shift) & RDXTREE_RADIX_MASK;
629: node = rdxtree_entry_addr(node->entries[index]);
630: shift -= RDXTREE_RADIX;
631: height--;
632: } while (height > 0);
633:
634: if (node == NULL)
635: return NULL;
636:
637: rdxtree_node_remove(prev, index);
638: rdxtree_remove_bm_set(prev, index);
639: rdxtree_cleanup(tree, prev);
640: return node;
641: }
642:
643: void *
644: rdxtree_lookup_common(const struct rdxtree *tree, rdxtree_key_t key,
645: int get_slot)
646: {
647: struct rdxtree_node *node, *prev;
648: unsigned int height, shift, index;
649: void *entry;
650:
651: entry = llsync_read_ptr(tree->root);
652:
653: if (entry == NULL) {
654: node = NULL;
655: height = 0;
656: } else {
657: node = rdxtree_entry_addr(entry);
658: height = rdxtree_entry_is_node(entry) ? node->height + 1 : 0;
659: }
660:
661: if (key > rdxtree_max_key(height))
662: return NULL;
663:
664: if (height == 0) {
665: if (node == NULL)
666: return NULL;
667:
668: return get_slot ? (void *)&tree->root : node;
669: }
670:
671: shift = (height - 1) * RDXTREE_RADIX;
672:
673: do {
674: if (node == NULL)
675: return NULL;
676:
677: prev = node;
678: index = (unsigned int)(key >> shift) & RDXTREE_RADIX_MASK;
679: entry = llsync_read_ptr(node->entries[index]);
680: node = rdxtree_entry_addr(entry);
681: shift -= RDXTREE_RADIX;
682: height--;
683: } while (height > 0);
684:
685: if (node == NULL)
686: return NULL;
687:
688: return get_slot ? (void *)&prev->entries[index] : node;
689: }
690:
691: void *
692: rdxtree_replace_slot(void **slot, void *ptr)
693: {
694: void *old;
695:
696: assert(ptr != NULL);
697: assert(rdxtree_check_alignment(ptr));
698:
699: old = *slot;
700: assert(old != NULL);
701: assert(rdxtree_check_alignment(old));
702: llsync_assign_ptr(*slot, ptr);
703: return old;
704: }
705:
706: static void *
707: rdxtree_walk_next(struct rdxtree *tree, struct rdxtree_iter *iter)
708: {
709: struct rdxtree_node *root, *node, *prev;
710: unsigned int height, shift, index, orig_index;
711: rdxtree_key_t key;
712: void *entry;
713:
714: entry = llsync_read_ptr(tree->root);
715:
716: if (entry == NULL)
717: return NULL;
718:
719: if (!rdxtree_entry_is_node(entry)) {
720: if (iter->key != (rdxtree_key_t)-1)
721: return NULL;
722: else {
723: iter->key = 0;
724: return rdxtree_entry_addr(entry);
725: }
726: }
727:
728: key = iter->key + 1;
729:
730: if ((key == 0) && (iter->node != NULL))
731: return NULL;
732:
733: root = rdxtree_entry_addr(entry);
734:
735: restart:
736: node = root;
737: height = root->height + 1;
738:
739: if (key > rdxtree_max_key(height))
740: return NULL;
741:
742: shift = (height - 1) * RDXTREE_RADIX;
743:
744: do {
745: prev = node;
746: index = (key >> shift) & RDXTREE_RADIX_MASK;
747: orig_index = index;
748: node = rdxtree_node_find(node, &index);
749:
750: if (node == NULL) {
751: shift += RDXTREE_RADIX;
752: key = ((key >> shift) + 1) << shift;
753:
754: if (key == 0)
755: return NULL;
756:
757: goto restart;
758: }
759:
760: if (orig_index != index)
761: key = ((key >> shift) + (index - orig_index)) << shift;
762:
763: shift -= RDXTREE_RADIX;
764: height--;
765: } while (height > 0);
766:
767: iter->node = prev;
768: iter->key = key;
769: return node;
770: }
771:
772: void *
773: rdxtree_walk(struct rdxtree *tree, struct rdxtree_iter *iter)
774: {
775: unsigned int index, orig_index;
776: void *ptr;
777:
778: if (iter->node == NULL)
779: return rdxtree_walk_next(tree, iter);
780:
781: index = (iter->key + 1) & RDXTREE_RADIX_MASK;
782:
783: if (index != 0) {
784: orig_index = index;
785: ptr = rdxtree_node_find(iter->node, &index);
786:
787: if (ptr != NULL) {
788: iter->key += (index - orig_index) + 1;
789: return ptr;
790: }
791: }
792:
793: return rdxtree_walk_next(tree, iter);
794: }
795:
796: void
797: rdxtree_remove_all(struct rdxtree *tree)
798: {
799: struct rdxtree_node *node, *parent;
800: struct rdxtree_iter iter;
801:
802: if (tree->height == 0) {
803: if (tree->root != NULL)
804: llsync_assign_ptr(tree->root, NULL);
805:
806: return;
807: }
808:
809: for (;;) {
810: rdxtree_iter_init(&iter);
811: rdxtree_walk_next(tree, &iter);
812:
813: if (iter.node == NULL)
814: break;
815:
816: node = iter.node;
817: parent = node->parent;
818:
819: if (parent == NULL)
820: rdxtree_init(tree);
821: else {
822: rdxtree_node_remove(parent, node->index);
823: rdxtree_remove_bm_set(parent, node->index);
824: rdxtree_cleanup(tree, parent);
825: node->parent = NULL;
826: }
827:
828: rdxtree_node_schedule_destruction(node);
829: }
830: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.