1*eda14cbcSMatt Macy /* 2*eda14cbcSMatt Macy * CDDL HEADER START 3*eda14cbcSMatt Macy * 4*eda14cbcSMatt Macy * The contents of this file are subject to the terms of the 5*eda14cbcSMatt Macy * Common Development and Distribution License (the "License"). 6*eda14cbcSMatt Macy * You may not use this file except in compliance with the License. 7*eda14cbcSMatt Macy * 8*eda14cbcSMatt Macy * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*eda14cbcSMatt Macy * or http://www.opensolaris.org/os/licensing. 10*eda14cbcSMatt Macy * See the License for the specific language governing permissions 11*eda14cbcSMatt Macy * and limitations under the License. 12*eda14cbcSMatt Macy * 13*eda14cbcSMatt Macy * When distributing Covered Code, include this CDDL HEADER in each 14*eda14cbcSMatt Macy * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*eda14cbcSMatt Macy * If applicable, add the following below this CDDL HEADER, with the 16*eda14cbcSMatt Macy * fields enclosed by brackets "[]" replaced with your own identifying 17*eda14cbcSMatt Macy * information: Portions Copyright [yyyy] [name of copyright owner] 18*eda14cbcSMatt Macy * 19*eda14cbcSMatt Macy * CDDL HEADER END 20*eda14cbcSMatt Macy */ 21*eda14cbcSMatt Macy /* 22*eda14cbcSMatt Macy * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23*eda14cbcSMatt Macy * Use is subject to license terms. 24*eda14cbcSMatt Macy */ 25*eda14cbcSMatt Macy 26*eda14cbcSMatt Macy 27*eda14cbcSMatt Macy 28*eda14cbcSMatt Macy #include "libuutil_common.h" 29*eda14cbcSMatt Macy 30*eda14cbcSMatt Macy #include <stdlib.h> 31*eda14cbcSMatt Macy #include <string.h> 32*eda14cbcSMatt Macy #include <unistd.h> 33*eda14cbcSMatt Macy #include <sys/avl.h> 34*eda14cbcSMatt Macy 35*eda14cbcSMatt Macy static uu_avl_pool_t uu_null_apool = { &uu_null_apool, &uu_null_apool }; 36*eda14cbcSMatt Macy static pthread_mutex_t uu_apool_list_lock = PTHREAD_MUTEX_INITIALIZER; 37*eda14cbcSMatt Macy 38*eda14cbcSMatt Macy /* 39*eda14cbcSMatt Macy * The index mark change on every insert and delete, to catch stale 40*eda14cbcSMatt Macy * references. 41*eda14cbcSMatt Macy * 42*eda14cbcSMatt Macy * We leave the low bit alone, since the avl code uses it. 43*eda14cbcSMatt Macy */ 44*eda14cbcSMatt Macy #define INDEX_MAX (sizeof (uintptr_t) - 2) 45*eda14cbcSMatt Macy #define INDEX_NEXT(m) (((m) == INDEX_MAX)? 2 : ((m) + 2) & INDEX_MAX) 46*eda14cbcSMatt Macy 47*eda14cbcSMatt Macy #define INDEX_DECODE(i) ((i) & ~INDEX_MAX) 48*eda14cbcSMatt Macy #define INDEX_ENCODE(p, n) (((n) & ~INDEX_MAX) | (p)->ua_index) 49*eda14cbcSMatt Macy #define INDEX_VALID(p, i) (((i) & INDEX_MAX) == (p)->ua_index) 50*eda14cbcSMatt Macy #define INDEX_CHECK(i) (((i) & INDEX_MAX) != 0) 51*eda14cbcSMatt Macy 52*eda14cbcSMatt Macy /* 53*eda14cbcSMatt Macy * When an element is inactive (not in a tree), we keep a marked pointer to 54*eda14cbcSMatt Macy * its containing pool in its first word, and a NULL pointer in its second. 55*eda14cbcSMatt Macy * 56*eda14cbcSMatt Macy * On insert, we use these to verify that it comes from the correct pool. 57*eda14cbcSMatt Macy */ 58*eda14cbcSMatt Macy #define NODE_ARRAY(p, n) ((uintptr_t *)((uintptr_t)(n) + \ 59*eda14cbcSMatt Macy (pp)->uap_nodeoffset)) 60*eda14cbcSMatt Macy 61*eda14cbcSMatt Macy #define POOL_TO_MARKER(pp) (((uintptr_t)(pp) | 1)) 62*eda14cbcSMatt Macy 63*eda14cbcSMatt Macy #define DEAD_MARKER 0xc4 64*eda14cbcSMatt Macy 65*eda14cbcSMatt Macy uu_avl_pool_t * 66*eda14cbcSMatt Macy uu_avl_pool_create(const char *name, size_t objsize, size_t nodeoffset, 67*eda14cbcSMatt Macy uu_compare_fn_t *compare_func, uint32_t flags) 68*eda14cbcSMatt Macy { 69*eda14cbcSMatt Macy uu_avl_pool_t *pp, *next, *prev; 70*eda14cbcSMatt Macy 71*eda14cbcSMatt Macy if (name == NULL || 72*eda14cbcSMatt Macy uu_check_name(name, UU_NAME_DOMAIN) == -1 || 73*eda14cbcSMatt Macy nodeoffset + sizeof (uu_avl_node_t) > objsize || 74*eda14cbcSMatt Macy compare_func == NULL) { 75*eda14cbcSMatt Macy uu_set_error(UU_ERROR_INVALID_ARGUMENT); 76*eda14cbcSMatt Macy return (NULL); 77*eda14cbcSMatt Macy } 78*eda14cbcSMatt Macy 79*eda14cbcSMatt Macy if (flags & ~UU_AVL_POOL_DEBUG) { 80*eda14cbcSMatt Macy uu_set_error(UU_ERROR_UNKNOWN_FLAG); 81*eda14cbcSMatt Macy return (NULL); 82*eda14cbcSMatt Macy } 83*eda14cbcSMatt Macy 84*eda14cbcSMatt Macy pp = uu_zalloc(sizeof (uu_avl_pool_t)); 85*eda14cbcSMatt Macy if (pp == NULL) { 86*eda14cbcSMatt Macy uu_set_error(UU_ERROR_NO_MEMORY); 87*eda14cbcSMatt Macy return (NULL); 88*eda14cbcSMatt Macy } 89*eda14cbcSMatt Macy 90*eda14cbcSMatt Macy (void) strlcpy(pp->uap_name, name, sizeof (pp->uap_name)); 91*eda14cbcSMatt Macy pp->uap_nodeoffset = nodeoffset; 92*eda14cbcSMatt Macy pp->uap_objsize = objsize; 93*eda14cbcSMatt Macy pp->uap_cmp = compare_func; 94*eda14cbcSMatt Macy if (flags & UU_AVL_POOL_DEBUG) 95*eda14cbcSMatt Macy pp->uap_debug = 1; 96*eda14cbcSMatt Macy pp->uap_last_index = 0; 97*eda14cbcSMatt Macy 98*eda14cbcSMatt Macy (void) pthread_mutex_init(&pp->uap_lock, NULL); 99*eda14cbcSMatt Macy 100*eda14cbcSMatt Macy pp->uap_null_avl.ua_next_enc = UU_PTR_ENCODE(&pp->uap_null_avl); 101*eda14cbcSMatt Macy pp->uap_null_avl.ua_prev_enc = UU_PTR_ENCODE(&pp->uap_null_avl); 102*eda14cbcSMatt Macy 103*eda14cbcSMatt Macy (void) pthread_mutex_lock(&uu_apool_list_lock); 104*eda14cbcSMatt Macy pp->uap_next = next = &uu_null_apool; 105*eda14cbcSMatt Macy pp->uap_prev = prev = next->uap_prev; 106*eda14cbcSMatt Macy next->uap_prev = pp; 107*eda14cbcSMatt Macy prev->uap_next = pp; 108*eda14cbcSMatt Macy (void) pthread_mutex_unlock(&uu_apool_list_lock); 109*eda14cbcSMatt Macy 110*eda14cbcSMatt Macy return (pp); 111*eda14cbcSMatt Macy } 112*eda14cbcSMatt Macy 113*eda14cbcSMatt Macy void 114*eda14cbcSMatt Macy uu_avl_pool_destroy(uu_avl_pool_t *pp) 115*eda14cbcSMatt Macy { 116*eda14cbcSMatt Macy if (pp->uap_debug) { 117*eda14cbcSMatt Macy if (pp->uap_null_avl.ua_next_enc != 118*eda14cbcSMatt Macy UU_PTR_ENCODE(&pp->uap_null_avl) || 119*eda14cbcSMatt Macy pp->uap_null_avl.ua_prev_enc != 120*eda14cbcSMatt Macy UU_PTR_ENCODE(&pp->uap_null_avl)) { 121*eda14cbcSMatt Macy uu_panic("uu_avl_pool_destroy: Pool \"%.*s\" (%p) has " 122*eda14cbcSMatt Macy "outstanding avls, or is corrupt.\n", 123*eda14cbcSMatt Macy (int)sizeof (pp->uap_name), pp->uap_name, 124*eda14cbcSMatt Macy (void *)pp); 125*eda14cbcSMatt Macy } 126*eda14cbcSMatt Macy } 127*eda14cbcSMatt Macy (void) pthread_mutex_lock(&uu_apool_list_lock); 128*eda14cbcSMatt Macy pp->uap_next->uap_prev = pp->uap_prev; 129*eda14cbcSMatt Macy pp->uap_prev->uap_next = pp->uap_next; 130*eda14cbcSMatt Macy (void) pthread_mutex_unlock(&uu_apool_list_lock); 131*eda14cbcSMatt Macy pp->uap_prev = NULL; 132*eda14cbcSMatt Macy pp->uap_next = NULL; 133*eda14cbcSMatt Macy uu_free(pp); 134*eda14cbcSMatt Macy } 135*eda14cbcSMatt Macy 136*eda14cbcSMatt Macy void 137*eda14cbcSMatt Macy uu_avl_node_init(void *base, uu_avl_node_t *np, uu_avl_pool_t *pp) 138*eda14cbcSMatt Macy { 139*eda14cbcSMatt Macy uintptr_t *na = (uintptr_t *)np; 140*eda14cbcSMatt Macy 141*eda14cbcSMatt Macy if (pp->uap_debug) { 142*eda14cbcSMatt Macy uintptr_t offset = (uintptr_t)np - (uintptr_t)base; 143*eda14cbcSMatt Macy if (offset + sizeof (*np) > pp->uap_objsize) { 144*eda14cbcSMatt Macy uu_panic("uu_avl_node_init(%p, %p, %p (\"%s\")): " 145*eda14cbcSMatt Macy "offset %ld doesn't fit in object (size %ld)\n", 146*eda14cbcSMatt Macy base, (void *)np, (void *)pp, pp->uap_name, 147*eda14cbcSMatt Macy (long)offset, (long)pp->uap_objsize); 148*eda14cbcSMatt Macy } 149*eda14cbcSMatt Macy if (offset != pp->uap_nodeoffset) { 150*eda14cbcSMatt Macy uu_panic("uu_avl_node_init(%p, %p, %p (\"%s\")): " 151*eda14cbcSMatt Macy "offset %ld doesn't match pool's offset (%ld)\n", 152*eda14cbcSMatt Macy base, (void *)np, (void *)pp, pp->uap_name, 153*eda14cbcSMatt Macy (long)offset, (long)pp->uap_objsize); 154*eda14cbcSMatt Macy } 155*eda14cbcSMatt Macy } 156*eda14cbcSMatt Macy 157*eda14cbcSMatt Macy na[0] = POOL_TO_MARKER(pp); 158*eda14cbcSMatt Macy na[1] = 0; 159*eda14cbcSMatt Macy } 160*eda14cbcSMatt Macy 161*eda14cbcSMatt Macy void 162*eda14cbcSMatt Macy uu_avl_node_fini(void *base, uu_avl_node_t *np, uu_avl_pool_t *pp) 163*eda14cbcSMatt Macy { 164*eda14cbcSMatt Macy uintptr_t *na = (uintptr_t *)np; 165*eda14cbcSMatt Macy 166*eda14cbcSMatt Macy if (pp->uap_debug) { 167*eda14cbcSMatt Macy if (na[0] == DEAD_MARKER && na[1] == DEAD_MARKER) { 168*eda14cbcSMatt Macy uu_panic("uu_avl_node_fini(%p, %p, %p (\"%s\")): " 169*eda14cbcSMatt Macy "node already finied\n", 170*eda14cbcSMatt Macy base, (void *)np, (void *)pp, pp->uap_name); 171*eda14cbcSMatt Macy } 172*eda14cbcSMatt Macy if (na[0] != POOL_TO_MARKER(pp) || na[1] != 0) { 173*eda14cbcSMatt Macy uu_panic("uu_avl_node_fini(%p, %p, %p (\"%s\")): " 174*eda14cbcSMatt Macy "node corrupt, in tree, or in different pool\n", 175*eda14cbcSMatt Macy base, (void *)np, (void *)pp, pp->uap_name); 176*eda14cbcSMatt Macy } 177*eda14cbcSMatt Macy } 178*eda14cbcSMatt Macy 179*eda14cbcSMatt Macy na[0] = DEAD_MARKER; 180*eda14cbcSMatt Macy na[1] = DEAD_MARKER; 181*eda14cbcSMatt Macy na[2] = DEAD_MARKER; 182*eda14cbcSMatt Macy } 183*eda14cbcSMatt Macy 184*eda14cbcSMatt Macy struct uu_avl_node_compare_info { 185*eda14cbcSMatt Macy uu_compare_fn_t *ac_compare; 186*eda14cbcSMatt Macy void *ac_private; 187*eda14cbcSMatt Macy void *ac_right; 188*eda14cbcSMatt Macy void *ac_found; 189*eda14cbcSMatt Macy }; 190*eda14cbcSMatt Macy 191*eda14cbcSMatt Macy static int 192*eda14cbcSMatt Macy uu_avl_node_compare(const void *l, const void *r) 193*eda14cbcSMatt Macy { 194*eda14cbcSMatt Macy struct uu_avl_node_compare_info *info = 195*eda14cbcSMatt Macy (struct uu_avl_node_compare_info *)l; 196*eda14cbcSMatt Macy 197*eda14cbcSMatt Macy int res = info->ac_compare(r, info->ac_right, info->ac_private); 198*eda14cbcSMatt Macy 199*eda14cbcSMatt Macy if (res == 0) { 200*eda14cbcSMatt Macy if (info->ac_found == NULL) 201*eda14cbcSMatt Macy info->ac_found = (void *)r; 202*eda14cbcSMatt Macy return (-1); 203*eda14cbcSMatt Macy } 204*eda14cbcSMatt Macy if (res < 0) 205*eda14cbcSMatt Macy return (1); 206*eda14cbcSMatt Macy return (-1); 207*eda14cbcSMatt Macy } 208*eda14cbcSMatt Macy 209*eda14cbcSMatt Macy uu_avl_t * 210*eda14cbcSMatt Macy uu_avl_create(uu_avl_pool_t *pp, void *parent, uint32_t flags) 211*eda14cbcSMatt Macy { 212*eda14cbcSMatt Macy uu_avl_t *ap, *next, *prev; 213*eda14cbcSMatt Macy 214*eda14cbcSMatt Macy if (flags & ~UU_AVL_DEBUG) { 215*eda14cbcSMatt Macy uu_set_error(UU_ERROR_UNKNOWN_FLAG); 216*eda14cbcSMatt Macy return (NULL); 217*eda14cbcSMatt Macy } 218*eda14cbcSMatt Macy 219*eda14cbcSMatt Macy ap = uu_zalloc(sizeof (*ap)); 220*eda14cbcSMatt Macy if (ap == NULL) { 221*eda14cbcSMatt Macy uu_set_error(UU_ERROR_NO_MEMORY); 222*eda14cbcSMatt Macy return (NULL); 223*eda14cbcSMatt Macy } 224*eda14cbcSMatt Macy 225*eda14cbcSMatt Macy ap->ua_pool = pp; 226*eda14cbcSMatt Macy ap->ua_parent_enc = UU_PTR_ENCODE(parent); 227*eda14cbcSMatt Macy ap->ua_debug = pp->uap_debug || (flags & UU_AVL_DEBUG); 228*eda14cbcSMatt Macy ap->ua_index = (pp->uap_last_index = INDEX_NEXT(pp->uap_last_index)); 229*eda14cbcSMatt Macy 230*eda14cbcSMatt Macy avl_create(&ap->ua_tree, &uu_avl_node_compare, pp->uap_objsize, 231*eda14cbcSMatt Macy pp->uap_nodeoffset); 232*eda14cbcSMatt Macy 233*eda14cbcSMatt Macy ap->ua_null_walk.uaw_next = &ap->ua_null_walk; 234*eda14cbcSMatt Macy ap->ua_null_walk.uaw_prev = &ap->ua_null_walk; 235*eda14cbcSMatt Macy 236*eda14cbcSMatt Macy (void) pthread_mutex_lock(&pp->uap_lock); 237*eda14cbcSMatt Macy next = &pp->uap_null_avl; 238*eda14cbcSMatt Macy prev = UU_PTR_DECODE(next->ua_prev_enc); 239*eda14cbcSMatt Macy ap->ua_next_enc = UU_PTR_ENCODE(next); 240*eda14cbcSMatt Macy ap->ua_prev_enc = UU_PTR_ENCODE(prev); 241*eda14cbcSMatt Macy next->ua_prev_enc = UU_PTR_ENCODE(ap); 242*eda14cbcSMatt Macy prev->ua_next_enc = UU_PTR_ENCODE(ap); 243*eda14cbcSMatt Macy (void) pthread_mutex_unlock(&pp->uap_lock); 244*eda14cbcSMatt Macy 245*eda14cbcSMatt Macy return (ap); 246*eda14cbcSMatt Macy } 247*eda14cbcSMatt Macy 248*eda14cbcSMatt Macy void 249*eda14cbcSMatt Macy uu_avl_destroy(uu_avl_t *ap) 250*eda14cbcSMatt Macy { 251*eda14cbcSMatt Macy uu_avl_pool_t *pp = ap->ua_pool; 252*eda14cbcSMatt Macy 253*eda14cbcSMatt Macy if (ap->ua_debug) { 254*eda14cbcSMatt Macy if (avl_numnodes(&ap->ua_tree) != 0) { 255*eda14cbcSMatt Macy uu_panic("uu_avl_destroy(%p): tree not empty\n", 256*eda14cbcSMatt Macy (void *)ap); 257*eda14cbcSMatt Macy } 258*eda14cbcSMatt Macy if (ap->ua_null_walk.uaw_next != &ap->ua_null_walk || 259*eda14cbcSMatt Macy ap->ua_null_walk.uaw_prev != &ap->ua_null_walk) { 260*eda14cbcSMatt Macy uu_panic("uu_avl_destroy(%p): outstanding walkers\n", 261*eda14cbcSMatt Macy (void *)ap); 262*eda14cbcSMatt Macy } 263*eda14cbcSMatt Macy } 264*eda14cbcSMatt Macy (void) pthread_mutex_lock(&pp->uap_lock); 265*eda14cbcSMatt Macy UU_AVL_PTR(ap->ua_next_enc)->ua_prev_enc = ap->ua_prev_enc; 266*eda14cbcSMatt Macy UU_AVL_PTR(ap->ua_prev_enc)->ua_next_enc = ap->ua_next_enc; 267*eda14cbcSMatt Macy (void) pthread_mutex_unlock(&pp->uap_lock); 268*eda14cbcSMatt Macy ap->ua_prev_enc = UU_PTR_ENCODE(NULL); 269*eda14cbcSMatt Macy ap->ua_next_enc = UU_PTR_ENCODE(NULL); 270*eda14cbcSMatt Macy 271*eda14cbcSMatt Macy ap->ua_pool = NULL; 272*eda14cbcSMatt Macy avl_destroy(&ap->ua_tree); 273*eda14cbcSMatt Macy 274*eda14cbcSMatt Macy uu_free(ap); 275*eda14cbcSMatt Macy } 276*eda14cbcSMatt Macy 277*eda14cbcSMatt Macy size_t 278*eda14cbcSMatt Macy uu_avl_numnodes(uu_avl_t *ap) 279*eda14cbcSMatt Macy { 280*eda14cbcSMatt Macy return (avl_numnodes(&ap->ua_tree)); 281*eda14cbcSMatt Macy } 282*eda14cbcSMatt Macy 283*eda14cbcSMatt Macy void * 284*eda14cbcSMatt Macy uu_avl_first(uu_avl_t *ap) 285*eda14cbcSMatt Macy { 286*eda14cbcSMatt Macy return (avl_first(&ap->ua_tree)); 287*eda14cbcSMatt Macy } 288*eda14cbcSMatt Macy 289*eda14cbcSMatt Macy void * 290*eda14cbcSMatt Macy uu_avl_last(uu_avl_t *ap) 291*eda14cbcSMatt Macy { 292*eda14cbcSMatt Macy return (avl_last(&ap->ua_tree)); 293*eda14cbcSMatt Macy } 294*eda14cbcSMatt Macy 295*eda14cbcSMatt Macy void * 296*eda14cbcSMatt Macy uu_avl_next(uu_avl_t *ap, void *node) 297*eda14cbcSMatt Macy { 298*eda14cbcSMatt Macy return (AVL_NEXT(&ap->ua_tree, node)); 299*eda14cbcSMatt Macy } 300*eda14cbcSMatt Macy 301*eda14cbcSMatt Macy void * 302*eda14cbcSMatt Macy uu_avl_prev(uu_avl_t *ap, void *node) 303*eda14cbcSMatt Macy { 304*eda14cbcSMatt Macy return (AVL_PREV(&ap->ua_tree, node)); 305*eda14cbcSMatt Macy } 306*eda14cbcSMatt Macy 307*eda14cbcSMatt Macy static void 308*eda14cbcSMatt Macy _avl_walk_init(uu_avl_walk_t *wp, uu_avl_t *ap, uint32_t flags) 309*eda14cbcSMatt Macy { 310*eda14cbcSMatt Macy uu_avl_walk_t *next, *prev; 311*eda14cbcSMatt Macy 312*eda14cbcSMatt Macy int robust = (flags & UU_WALK_ROBUST); 313*eda14cbcSMatt Macy int direction = (flags & UU_WALK_REVERSE)? -1 : 1; 314*eda14cbcSMatt Macy 315*eda14cbcSMatt Macy (void) memset(wp, 0, sizeof (*wp)); 316*eda14cbcSMatt Macy wp->uaw_avl = ap; 317*eda14cbcSMatt Macy wp->uaw_robust = robust; 318*eda14cbcSMatt Macy wp->uaw_dir = direction; 319*eda14cbcSMatt Macy 320*eda14cbcSMatt Macy if (direction > 0) 321*eda14cbcSMatt Macy wp->uaw_next_result = avl_first(&ap->ua_tree); 322*eda14cbcSMatt Macy else 323*eda14cbcSMatt Macy wp->uaw_next_result = avl_last(&ap->ua_tree); 324*eda14cbcSMatt Macy 325*eda14cbcSMatt Macy if (ap->ua_debug || robust) { 326*eda14cbcSMatt Macy wp->uaw_next = next = &ap->ua_null_walk; 327*eda14cbcSMatt Macy wp->uaw_prev = prev = next->uaw_prev; 328*eda14cbcSMatt Macy next->uaw_prev = wp; 329*eda14cbcSMatt Macy prev->uaw_next = wp; 330*eda14cbcSMatt Macy } 331*eda14cbcSMatt Macy } 332*eda14cbcSMatt Macy 333*eda14cbcSMatt Macy static void * 334*eda14cbcSMatt Macy _avl_walk_advance(uu_avl_walk_t *wp, uu_avl_t *ap) 335*eda14cbcSMatt Macy { 336*eda14cbcSMatt Macy void *np = wp->uaw_next_result; 337*eda14cbcSMatt Macy 338*eda14cbcSMatt Macy avl_tree_t *t = &ap->ua_tree; 339*eda14cbcSMatt Macy 340*eda14cbcSMatt Macy if (np == NULL) 341*eda14cbcSMatt Macy return (NULL); 342*eda14cbcSMatt Macy 343*eda14cbcSMatt Macy wp->uaw_next_result = (wp->uaw_dir > 0)? AVL_NEXT(t, np) : 344*eda14cbcSMatt Macy AVL_PREV(t, np); 345*eda14cbcSMatt Macy 346*eda14cbcSMatt Macy return (np); 347*eda14cbcSMatt Macy } 348*eda14cbcSMatt Macy 349*eda14cbcSMatt Macy static void 350*eda14cbcSMatt Macy _avl_walk_fini(uu_avl_walk_t *wp) 351*eda14cbcSMatt Macy { 352*eda14cbcSMatt Macy if (wp->uaw_next != NULL) { 353*eda14cbcSMatt Macy wp->uaw_next->uaw_prev = wp->uaw_prev; 354*eda14cbcSMatt Macy wp->uaw_prev->uaw_next = wp->uaw_next; 355*eda14cbcSMatt Macy wp->uaw_next = NULL; 356*eda14cbcSMatt Macy wp->uaw_prev = NULL; 357*eda14cbcSMatt Macy } 358*eda14cbcSMatt Macy wp->uaw_avl = NULL; 359*eda14cbcSMatt Macy wp->uaw_next_result = NULL; 360*eda14cbcSMatt Macy } 361*eda14cbcSMatt Macy 362*eda14cbcSMatt Macy uu_avl_walk_t * 363*eda14cbcSMatt Macy uu_avl_walk_start(uu_avl_t *ap, uint32_t flags) 364*eda14cbcSMatt Macy { 365*eda14cbcSMatt Macy uu_avl_walk_t *wp; 366*eda14cbcSMatt Macy 367*eda14cbcSMatt Macy if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) { 368*eda14cbcSMatt Macy uu_set_error(UU_ERROR_UNKNOWN_FLAG); 369*eda14cbcSMatt Macy return (NULL); 370*eda14cbcSMatt Macy } 371*eda14cbcSMatt Macy 372*eda14cbcSMatt Macy wp = uu_zalloc(sizeof (*wp)); 373*eda14cbcSMatt Macy if (wp == NULL) { 374*eda14cbcSMatt Macy uu_set_error(UU_ERROR_NO_MEMORY); 375*eda14cbcSMatt Macy return (NULL); 376*eda14cbcSMatt Macy } 377*eda14cbcSMatt Macy 378*eda14cbcSMatt Macy _avl_walk_init(wp, ap, flags); 379*eda14cbcSMatt Macy return (wp); 380*eda14cbcSMatt Macy } 381*eda14cbcSMatt Macy 382*eda14cbcSMatt Macy void * 383*eda14cbcSMatt Macy uu_avl_walk_next(uu_avl_walk_t *wp) 384*eda14cbcSMatt Macy { 385*eda14cbcSMatt Macy return (_avl_walk_advance(wp, wp->uaw_avl)); 386*eda14cbcSMatt Macy } 387*eda14cbcSMatt Macy 388*eda14cbcSMatt Macy void 389*eda14cbcSMatt Macy uu_avl_walk_end(uu_avl_walk_t *wp) 390*eda14cbcSMatt Macy { 391*eda14cbcSMatt Macy _avl_walk_fini(wp); 392*eda14cbcSMatt Macy uu_free(wp); 393*eda14cbcSMatt Macy } 394*eda14cbcSMatt Macy 395*eda14cbcSMatt Macy int 396*eda14cbcSMatt Macy uu_avl_walk(uu_avl_t *ap, uu_walk_fn_t *func, void *private, uint32_t flags) 397*eda14cbcSMatt Macy { 398*eda14cbcSMatt Macy void *e; 399*eda14cbcSMatt Macy uu_avl_walk_t my_walk; 400*eda14cbcSMatt Macy 401*eda14cbcSMatt Macy int status = UU_WALK_NEXT; 402*eda14cbcSMatt Macy 403*eda14cbcSMatt Macy if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) { 404*eda14cbcSMatt Macy uu_set_error(UU_ERROR_UNKNOWN_FLAG); 405*eda14cbcSMatt Macy return (-1); 406*eda14cbcSMatt Macy } 407*eda14cbcSMatt Macy 408*eda14cbcSMatt Macy _avl_walk_init(&my_walk, ap, flags); 409*eda14cbcSMatt Macy while (status == UU_WALK_NEXT && 410*eda14cbcSMatt Macy (e = _avl_walk_advance(&my_walk, ap)) != NULL) 411*eda14cbcSMatt Macy status = (*func)(e, private); 412*eda14cbcSMatt Macy _avl_walk_fini(&my_walk); 413*eda14cbcSMatt Macy 414*eda14cbcSMatt Macy if (status >= 0) 415*eda14cbcSMatt Macy return (0); 416*eda14cbcSMatt Macy uu_set_error(UU_ERROR_CALLBACK_FAILED); 417*eda14cbcSMatt Macy return (-1); 418*eda14cbcSMatt Macy } 419*eda14cbcSMatt Macy 420*eda14cbcSMatt Macy void 421*eda14cbcSMatt Macy uu_avl_remove(uu_avl_t *ap, void *elem) 422*eda14cbcSMatt Macy { 423*eda14cbcSMatt Macy uu_avl_walk_t *wp; 424*eda14cbcSMatt Macy uu_avl_pool_t *pp = ap->ua_pool; 425*eda14cbcSMatt Macy uintptr_t *na = NODE_ARRAY(pp, elem); 426*eda14cbcSMatt Macy 427*eda14cbcSMatt Macy if (ap->ua_debug) { 428*eda14cbcSMatt Macy /* 429*eda14cbcSMatt Macy * invalidate outstanding uu_avl_index_ts. 430*eda14cbcSMatt Macy */ 431*eda14cbcSMatt Macy ap->ua_index = INDEX_NEXT(ap->ua_index); 432*eda14cbcSMatt Macy } 433*eda14cbcSMatt Macy 434*eda14cbcSMatt Macy /* 435*eda14cbcSMatt Macy * Robust walkers most be advanced, if we are removing the node 436*eda14cbcSMatt Macy * they are currently using. In debug mode, non-robust walkers 437*eda14cbcSMatt Macy * are also on the walker list. 438*eda14cbcSMatt Macy */ 439*eda14cbcSMatt Macy for (wp = ap->ua_null_walk.uaw_next; wp != &ap->ua_null_walk; 440*eda14cbcSMatt Macy wp = wp->uaw_next) { 441*eda14cbcSMatt Macy if (wp->uaw_robust) { 442*eda14cbcSMatt Macy if (elem == wp->uaw_next_result) 443*eda14cbcSMatt Macy (void) _avl_walk_advance(wp, ap); 444*eda14cbcSMatt Macy } else if (wp->uaw_next_result != NULL) { 445*eda14cbcSMatt Macy uu_panic("uu_avl_remove(%p, %p): active non-robust " 446*eda14cbcSMatt Macy "walker\n", (void *)ap, elem); 447*eda14cbcSMatt Macy } 448*eda14cbcSMatt Macy } 449*eda14cbcSMatt Macy 450*eda14cbcSMatt Macy avl_remove(&ap->ua_tree, elem); 451*eda14cbcSMatt Macy 452*eda14cbcSMatt Macy na[0] = POOL_TO_MARKER(pp); 453*eda14cbcSMatt Macy na[1] = 0; 454*eda14cbcSMatt Macy } 455*eda14cbcSMatt Macy 456*eda14cbcSMatt Macy void * 457*eda14cbcSMatt Macy uu_avl_teardown(uu_avl_t *ap, void **cookie) 458*eda14cbcSMatt Macy { 459*eda14cbcSMatt Macy void *elem = avl_destroy_nodes(&ap->ua_tree, cookie); 460*eda14cbcSMatt Macy 461*eda14cbcSMatt Macy if (elem != NULL) { 462*eda14cbcSMatt Macy uu_avl_pool_t *pp = ap->ua_pool; 463*eda14cbcSMatt Macy uintptr_t *na = NODE_ARRAY(pp, elem); 464*eda14cbcSMatt Macy 465*eda14cbcSMatt Macy na[0] = POOL_TO_MARKER(pp); 466*eda14cbcSMatt Macy na[1] = 0; 467*eda14cbcSMatt Macy } 468*eda14cbcSMatt Macy return (elem); 469*eda14cbcSMatt Macy } 470*eda14cbcSMatt Macy 471*eda14cbcSMatt Macy void * 472*eda14cbcSMatt Macy uu_avl_find(uu_avl_t *ap, void *elem, void *private, uu_avl_index_t *out) 473*eda14cbcSMatt Macy { 474*eda14cbcSMatt Macy struct uu_avl_node_compare_info info; 475*eda14cbcSMatt Macy void *result; 476*eda14cbcSMatt Macy 477*eda14cbcSMatt Macy info.ac_compare = ap->ua_pool->uap_cmp; 478*eda14cbcSMatt Macy info.ac_private = private; 479*eda14cbcSMatt Macy info.ac_right = elem; 480*eda14cbcSMatt Macy info.ac_found = NULL; 481*eda14cbcSMatt Macy 482*eda14cbcSMatt Macy result = avl_find(&ap->ua_tree, &info, out); 483*eda14cbcSMatt Macy if (out != NULL) 484*eda14cbcSMatt Macy *out = INDEX_ENCODE(ap, *out); 485*eda14cbcSMatt Macy 486*eda14cbcSMatt Macy if (ap->ua_debug && result != NULL) 487*eda14cbcSMatt Macy uu_panic("uu_avl_find: internal error: avl_find succeeded\n"); 488*eda14cbcSMatt Macy 489*eda14cbcSMatt Macy return (info.ac_found); 490*eda14cbcSMatt Macy } 491*eda14cbcSMatt Macy 492*eda14cbcSMatt Macy void 493*eda14cbcSMatt Macy uu_avl_insert(uu_avl_t *ap, void *elem, uu_avl_index_t idx) 494*eda14cbcSMatt Macy { 495*eda14cbcSMatt Macy if (ap->ua_debug) { 496*eda14cbcSMatt Macy uu_avl_pool_t *pp = ap->ua_pool; 497*eda14cbcSMatt Macy uintptr_t *na = NODE_ARRAY(pp, elem); 498*eda14cbcSMatt Macy 499*eda14cbcSMatt Macy if (na[1] != 0) 500*eda14cbcSMatt Macy uu_panic("uu_avl_insert(%p, %p, %p): node already " 501*eda14cbcSMatt Macy "in tree, or corrupt\n", 502*eda14cbcSMatt Macy (void *)ap, elem, (void *)idx); 503*eda14cbcSMatt Macy if (na[0] == 0) 504*eda14cbcSMatt Macy uu_panic("uu_avl_insert(%p, %p, %p): node not " 505*eda14cbcSMatt Macy "initialized\n", 506*eda14cbcSMatt Macy (void *)ap, elem, (void *)idx); 507*eda14cbcSMatt Macy if (na[0] != POOL_TO_MARKER(pp)) 508*eda14cbcSMatt Macy uu_panic("uu_avl_insert(%p, %p, %p): node from " 509*eda14cbcSMatt Macy "other pool, or corrupt\n", 510*eda14cbcSMatt Macy (void *)ap, elem, (void *)idx); 511*eda14cbcSMatt Macy 512*eda14cbcSMatt Macy if (!INDEX_VALID(ap, idx)) 513*eda14cbcSMatt Macy uu_panic("uu_avl_insert(%p, %p, %p): %s\n", 514*eda14cbcSMatt Macy (void *)ap, elem, (void *)idx, 515*eda14cbcSMatt Macy INDEX_CHECK(idx)? "outdated index" : 516*eda14cbcSMatt Macy "invalid index"); 517*eda14cbcSMatt Macy 518*eda14cbcSMatt Macy /* 519*eda14cbcSMatt Macy * invalidate outstanding uu_avl_index_ts. 520*eda14cbcSMatt Macy */ 521*eda14cbcSMatt Macy ap->ua_index = INDEX_NEXT(ap->ua_index); 522*eda14cbcSMatt Macy } 523*eda14cbcSMatt Macy avl_insert(&ap->ua_tree, elem, INDEX_DECODE(idx)); 524*eda14cbcSMatt Macy } 525*eda14cbcSMatt Macy 526*eda14cbcSMatt Macy void * 527*eda14cbcSMatt Macy uu_avl_nearest_next(uu_avl_t *ap, uu_avl_index_t idx) 528*eda14cbcSMatt Macy { 529*eda14cbcSMatt Macy if (ap->ua_debug && !INDEX_VALID(ap, idx)) 530*eda14cbcSMatt Macy uu_panic("uu_avl_nearest_next(%p, %p): %s\n", 531*eda14cbcSMatt Macy (void *)ap, (void *)idx, INDEX_CHECK(idx)? 532*eda14cbcSMatt Macy "outdated index" : "invalid index"); 533*eda14cbcSMatt Macy return (avl_nearest(&ap->ua_tree, INDEX_DECODE(idx), AVL_AFTER)); 534*eda14cbcSMatt Macy } 535*eda14cbcSMatt Macy 536*eda14cbcSMatt Macy void * 537*eda14cbcSMatt Macy uu_avl_nearest_prev(uu_avl_t *ap, uu_avl_index_t idx) 538*eda14cbcSMatt Macy { 539*eda14cbcSMatt Macy if (ap->ua_debug && !INDEX_VALID(ap, idx)) 540*eda14cbcSMatt Macy uu_panic("uu_avl_nearest_prev(%p, %p): %s\n", 541*eda14cbcSMatt Macy (void *)ap, (void *)idx, INDEX_CHECK(idx)? 542*eda14cbcSMatt Macy "outdated index" : "invalid index"); 543*eda14cbcSMatt Macy return (avl_nearest(&ap->ua_tree, INDEX_DECODE(idx), AVL_BEFORE)); 544*eda14cbcSMatt Macy } 545*eda14cbcSMatt Macy 546*eda14cbcSMatt Macy /* 547*eda14cbcSMatt Macy * called from uu_lockup() and uu_release(), as part of our fork1()-safety. 548*eda14cbcSMatt Macy */ 549*eda14cbcSMatt Macy void 550*eda14cbcSMatt Macy uu_avl_lockup(void) 551*eda14cbcSMatt Macy { 552*eda14cbcSMatt Macy uu_avl_pool_t *pp; 553*eda14cbcSMatt Macy 554*eda14cbcSMatt Macy (void) pthread_mutex_lock(&uu_apool_list_lock); 555*eda14cbcSMatt Macy for (pp = uu_null_apool.uap_next; pp != &uu_null_apool; 556*eda14cbcSMatt Macy pp = pp->uap_next) 557*eda14cbcSMatt Macy (void) pthread_mutex_lock(&pp->uap_lock); 558*eda14cbcSMatt Macy } 559*eda14cbcSMatt Macy 560*eda14cbcSMatt Macy void 561*eda14cbcSMatt Macy uu_avl_release(void) 562*eda14cbcSMatt Macy { 563*eda14cbcSMatt Macy uu_avl_pool_t *pp; 564*eda14cbcSMatt Macy 565*eda14cbcSMatt Macy for (pp = uu_null_apool.uap_next; pp != &uu_null_apool; 566*eda14cbcSMatt Macy pp = pp->uap_next) 567*eda14cbcSMatt Macy (void) pthread_mutex_unlock(&pp->uap_lock); 568*eda14cbcSMatt Macy (void) pthread_mutex_unlock(&uu_apool_list_lock); 569*eda14cbcSMatt Macy } 570