1*fb2f18f8Sesaxe /* 2*fb2f18f8Sesaxe * CDDL HEADER START 3*fb2f18f8Sesaxe * 4*fb2f18f8Sesaxe * The contents of this file are subject to the terms of the 5*fb2f18f8Sesaxe * Common Development and Distribution License (the "License"). 6*fb2f18f8Sesaxe * You may not use this file except in compliance with the License. 7*fb2f18f8Sesaxe * 8*fb2f18f8Sesaxe * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*fb2f18f8Sesaxe * or http://www.opensolaris.org/os/licensing. 10*fb2f18f8Sesaxe * See the License for the specific language governing permissions 11*fb2f18f8Sesaxe * and limitations under the License. 12*fb2f18f8Sesaxe * 13*fb2f18f8Sesaxe * When distributing Covered Code, include this CDDL HEADER in each 14*fb2f18f8Sesaxe * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*fb2f18f8Sesaxe * If applicable, add the following below this CDDL HEADER, with the 16*fb2f18f8Sesaxe * fields enclosed by brackets "[]" replaced with your own identifying 17*fb2f18f8Sesaxe * information: Portions Copyright [yyyy] [name of copyright owner] 18*fb2f18f8Sesaxe * 19*fb2f18f8Sesaxe * CDDL HEADER END 20*fb2f18f8Sesaxe */ 21*fb2f18f8Sesaxe /* 22*fb2f18f8Sesaxe * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23*fb2f18f8Sesaxe * Use is subject to license terms. 24*fb2f18f8Sesaxe */ 25*fb2f18f8Sesaxe 26*fb2f18f8Sesaxe #pragma ident "%Z%%M% %I% %E% SMI" 27*fb2f18f8Sesaxe 28*fb2f18f8Sesaxe #include <sys/systm.h> 29*fb2f18f8Sesaxe #include <sys/param.h> 30*fb2f18f8Sesaxe #include <sys/debug.h> 31*fb2f18f8Sesaxe #include <sys/kmem.h> 32*fb2f18f8Sesaxe #include <sys/group.h> 33*fb2f18f8Sesaxe 34*fb2f18f8Sesaxe 35*fb2f18f8Sesaxe #define GRP_SET_SIZE_DEFAULT 2 36*fb2f18f8Sesaxe 37*fb2f18f8Sesaxe static void group_grow_set(group_t *); 38*fb2f18f8Sesaxe static void group_shrink_set(group_t *); 39*fb2f18f8Sesaxe static void group_pack_set(void **, uint_t); 40*fb2f18f8Sesaxe 41*fb2f18f8Sesaxe /* 42*fb2f18f8Sesaxe * Initialize a group_t 43*fb2f18f8Sesaxe */ 44*fb2f18f8Sesaxe void 45*fb2f18f8Sesaxe group_create(group_t *g) 46*fb2f18f8Sesaxe { 47*fb2f18f8Sesaxe bzero(g, sizeof (group_t)); 48*fb2f18f8Sesaxe } 49*fb2f18f8Sesaxe 50*fb2f18f8Sesaxe /* 51*fb2f18f8Sesaxe * Destroy a group_t 52*fb2f18f8Sesaxe * The group must already be empty 53*fb2f18f8Sesaxe */ 54*fb2f18f8Sesaxe void 55*fb2f18f8Sesaxe group_destroy(group_t *g) 56*fb2f18f8Sesaxe { 57*fb2f18f8Sesaxe ASSERT(g->grp_size == 0); 58*fb2f18f8Sesaxe 59*fb2f18f8Sesaxe if (g->grp_capacity > 0) { 60*fb2f18f8Sesaxe kmem_free(g->grp_set, g->grp_capacity * sizeof (void *)); 61*fb2f18f8Sesaxe g->grp_capacity = 0; 62*fb2f18f8Sesaxe } 63*fb2f18f8Sesaxe g->grp_set = NULL; 64*fb2f18f8Sesaxe } 65*fb2f18f8Sesaxe 66*fb2f18f8Sesaxe /* 67*fb2f18f8Sesaxe * Add element "e" to group "g" 68*fb2f18f8Sesaxe * 69*fb2f18f8Sesaxe * Returns -1 if addition would result in overcapacity, and 70*fb2f18f8Sesaxe * resize operations aren't allowed, and 0 otherwise 71*fb2f18f8Sesaxe */ 72*fb2f18f8Sesaxe int 73*fb2f18f8Sesaxe group_add(group_t *g, void *e, int gflag) 74*fb2f18f8Sesaxe { 75*fb2f18f8Sesaxe int entry; 76*fb2f18f8Sesaxe 77*fb2f18f8Sesaxe if ((gflag & GRP_NORESIZE) && 78*fb2f18f8Sesaxe g->grp_size == g->grp_capacity) 79*fb2f18f8Sesaxe return (-1); 80*fb2f18f8Sesaxe 81*fb2f18f8Sesaxe ASSERT(g->grp_size != g->grp_capacity || (gflag & GRP_RESIZE)); 82*fb2f18f8Sesaxe 83*fb2f18f8Sesaxe entry = g->grp_size++; 84*fb2f18f8Sesaxe if (g->grp_size > g->grp_capacity) 85*fb2f18f8Sesaxe group_grow_set(g); 86*fb2f18f8Sesaxe 87*fb2f18f8Sesaxe ASSERT(g->grp_set[entry] == NULL); 88*fb2f18f8Sesaxe g->grp_set[entry] = e; 89*fb2f18f8Sesaxe 90*fb2f18f8Sesaxe return (0); 91*fb2f18f8Sesaxe } 92*fb2f18f8Sesaxe 93*fb2f18f8Sesaxe /* 94*fb2f18f8Sesaxe * Remove element "e" from group "g" 95*fb2f18f8Sesaxe * 96*fb2f18f8Sesaxe * Returns -1 if "e" was not present in "g" and 0 otherwise 97*fb2f18f8Sesaxe */ 98*fb2f18f8Sesaxe int 99*fb2f18f8Sesaxe group_remove(group_t *g, void *e, int gflag) 100*fb2f18f8Sesaxe { 101*fb2f18f8Sesaxe int i; 102*fb2f18f8Sesaxe 103*fb2f18f8Sesaxe /* 104*fb2f18f8Sesaxe * Find the element in the group's set 105*fb2f18f8Sesaxe */ 106*fb2f18f8Sesaxe for (i = 0; i < g->grp_size; i++) 107*fb2f18f8Sesaxe if (g->grp_set[i] == e) 108*fb2f18f8Sesaxe break; 109*fb2f18f8Sesaxe if (g->grp_set[i] != e) 110*fb2f18f8Sesaxe return (-1); 111*fb2f18f8Sesaxe 112*fb2f18f8Sesaxe g->grp_set[i] = NULL; 113*fb2f18f8Sesaxe group_pack_set(g->grp_set, g->grp_size); 114*fb2f18f8Sesaxe g->grp_size--; 115*fb2f18f8Sesaxe 116*fb2f18f8Sesaxe if ((gflag & GRP_RESIZE) && 117*fb2f18f8Sesaxe g->grp_size > GRP_SET_SIZE_DEFAULT && 118*fb2f18f8Sesaxe ((g->grp_size - 1) & g->grp_size) == 0) 119*fb2f18f8Sesaxe group_shrink_set(g); 120*fb2f18f8Sesaxe 121*fb2f18f8Sesaxe return (0); 122*fb2f18f8Sesaxe } 123*fb2f18f8Sesaxe 124*fb2f18f8Sesaxe /* 125*fb2f18f8Sesaxe * Expand the capacity of group "g" so that it may 126*fb2f18f8Sesaxe * contain at least "n" elements 127*fb2f18f8Sesaxe */ 128*fb2f18f8Sesaxe void 129*fb2f18f8Sesaxe group_expand(group_t *g, uint_t n) 130*fb2f18f8Sesaxe { 131*fb2f18f8Sesaxe while (g->grp_capacity < n) 132*fb2f18f8Sesaxe group_grow_set(g); 133*fb2f18f8Sesaxe } 134*fb2f18f8Sesaxe 135*fb2f18f8Sesaxe /* 136*fb2f18f8Sesaxe * Upsize a group's holding capacity 137*fb2f18f8Sesaxe */ 138*fb2f18f8Sesaxe static void 139*fb2f18f8Sesaxe group_grow_set(group_t *g) 140*fb2f18f8Sesaxe { 141*fb2f18f8Sesaxe uint_t cap_old, cap_new; 142*fb2f18f8Sesaxe void **set_old, **set_new; 143*fb2f18f8Sesaxe 144*fb2f18f8Sesaxe cap_old = g->grp_capacity; 145*fb2f18f8Sesaxe set_old = g->grp_set; 146*fb2f18f8Sesaxe 147*fb2f18f8Sesaxe /* 148*fb2f18f8Sesaxe * The array size grows in powers of two 149*fb2f18f8Sesaxe */ 150*fb2f18f8Sesaxe if ((cap_new = (cap_old << 1)) == 0) { 151*fb2f18f8Sesaxe /* 152*fb2f18f8Sesaxe * The set is unallocated. 153*fb2f18f8Sesaxe * Allocate a default sized set. 154*fb2f18f8Sesaxe */ 155*fb2f18f8Sesaxe cap_new = GRP_SET_SIZE_DEFAULT; 156*fb2f18f8Sesaxe g->grp_set = kmem_zalloc(cap_new * sizeof (void *), KM_SLEEP); 157*fb2f18f8Sesaxe g->grp_capacity = cap_new; 158*fb2f18f8Sesaxe } else { 159*fb2f18f8Sesaxe /* 160*fb2f18f8Sesaxe * Allocate a newly sized array, 161*fb2f18f8Sesaxe * copy the data, and free the old array. 162*fb2f18f8Sesaxe */ 163*fb2f18f8Sesaxe set_new = kmem_zalloc(cap_new * sizeof (void *), KM_SLEEP); 164*fb2f18f8Sesaxe (void) kcopy(set_old, set_new, cap_old * sizeof (void *)); 165*fb2f18f8Sesaxe g->grp_set = set_new; 166*fb2f18f8Sesaxe g->grp_capacity = cap_new; 167*fb2f18f8Sesaxe kmem_free(set_old, cap_old * sizeof (void *)); 168*fb2f18f8Sesaxe } 169*fb2f18f8Sesaxe /* 170*fb2f18f8Sesaxe * The new array size should be a power of two 171*fb2f18f8Sesaxe */ 172*fb2f18f8Sesaxe ASSERT(((cap_new - 1) & cap_new) == 0); 173*fb2f18f8Sesaxe } 174*fb2f18f8Sesaxe 175*fb2f18f8Sesaxe /* 176*fb2f18f8Sesaxe * Downsize a group's holding capacity 177*fb2f18f8Sesaxe */ 178*fb2f18f8Sesaxe static void 179*fb2f18f8Sesaxe group_shrink_set(group_t *g) 180*fb2f18f8Sesaxe { 181*fb2f18f8Sesaxe uint_t cap_old, cap_new; 182*fb2f18f8Sesaxe void **set_old, **set_new; 183*fb2f18f8Sesaxe 184*fb2f18f8Sesaxe cap_old = g->grp_capacity; 185*fb2f18f8Sesaxe set_old = g->grp_set; 186*fb2f18f8Sesaxe 187*fb2f18f8Sesaxe /* 188*fb2f18f8Sesaxe * The group's existing array size must already 189*fb2f18f8Sesaxe * be a power of two 190*fb2f18f8Sesaxe */ 191*fb2f18f8Sesaxe ASSERT(((cap_old - 1) & cap_old) == 0); 192*fb2f18f8Sesaxe cap_new = cap_old >> 1; 193*fb2f18f8Sesaxe 194*fb2f18f8Sesaxe /* 195*fb2f18f8Sesaxe * GRP_SET_SIZE_DEFAULT is the minumum set size. 196*fb2f18f8Sesaxe */ 197*fb2f18f8Sesaxe if (cap_new < GRP_SET_SIZE_DEFAULT) 198*fb2f18f8Sesaxe return; 199*fb2f18f8Sesaxe 200*fb2f18f8Sesaxe set_new = kmem_zalloc(cap_new * sizeof (void *), KM_SLEEP); 201*fb2f18f8Sesaxe (void) kcopy(set_old, set_new, cap_new * sizeof (void *)); 202*fb2f18f8Sesaxe g->grp_capacity = cap_new; 203*fb2f18f8Sesaxe g->grp_set = set_new; 204*fb2f18f8Sesaxe 205*fb2f18f8Sesaxe ASSERT(((cap_new - 1) & cap_new) == 0); 206*fb2f18f8Sesaxe kmem_free(set_old, cap_old * sizeof (void *)); 207*fb2f18f8Sesaxe } 208*fb2f18f8Sesaxe 209*fb2f18f8Sesaxe /* 210*fb2f18f8Sesaxe * Pack a group's set 211*fb2f18f8Sesaxe * Element order is not preserved 212*fb2f18f8Sesaxe */ 213*fb2f18f8Sesaxe static void 214*fb2f18f8Sesaxe group_pack_set(void **set, uint_t sz) 215*fb2f18f8Sesaxe { 216*fb2f18f8Sesaxe uint_t i, j, free; 217*fb2f18f8Sesaxe 218*fb2f18f8Sesaxe free = (uint_t)-1; 219*fb2f18f8Sesaxe 220*fb2f18f8Sesaxe for (i = 0; i < sz; i++) { 221*fb2f18f8Sesaxe if (set[i] == NULL && free == (uint_t)-1) { 222*fb2f18f8Sesaxe /* 223*fb2f18f8Sesaxe * Found a new free slot. 224*fb2f18f8Sesaxe * Start packing from here. 225*fb2f18f8Sesaxe */ 226*fb2f18f8Sesaxe free = i; 227*fb2f18f8Sesaxe } else if (set[i] != NULL && free != (uint_t)-1) { 228*fb2f18f8Sesaxe /* 229*fb2f18f8Sesaxe * Found a slot to pack into 230*fb2f18f8Sesaxe * an earlier free slot. 231*fb2f18f8Sesaxe */ 232*fb2f18f8Sesaxe ASSERT(set[free] == NULL); 233*fb2f18f8Sesaxe set[free] = set[i]; 234*fb2f18f8Sesaxe set[i] = NULL; 235*fb2f18f8Sesaxe 236*fb2f18f8Sesaxe /* 237*fb2f18f8Sesaxe * Find the next free slot 238*fb2f18f8Sesaxe */ 239*fb2f18f8Sesaxe for (j = free + 1; set[j] != NULL; j++) { 240*fb2f18f8Sesaxe ASSERT(j <= i); 241*fb2f18f8Sesaxe if (j == i) 242*fb2f18f8Sesaxe break; 243*fb2f18f8Sesaxe } 244*fb2f18f8Sesaxe if (set[j] == NULL) 245*fb2f18f8Sesaxe free = j; 246*fb2f18f8Sesaxe else 247*fb2f18f8Sesaxe free = (uint_t)-1; 248*fb2f18f8Sesaxe } 249*fb2f18f8Sesaxe } 250*fb2f18f8Sesaxe } 251*fb2f18f8Sesaxe 252*fb2f18f8Sesaxe /* 253*fb2f18f8Sesaxe * Initialize a group iterator cookie 254*fb2f18f8Sesaxe */ 255*fb2f18f8Sesaxe void 256*fb2f18f8Sesaxe group_iter_init(group_iter_t *iter) 257*fb2f18f8Sesaxe { 258*fb2f18f8Sesaxe *iter = 0; 259*fb2f18f8Sesaxe } 260*fb2f18f8Sesaxe 261*fb2f18f8Sesaxe /* 262*fb2f18f8Sesaxe * Iterate over the elements in a group 263*fb2f18f8Sesaxe */ 264*fb2f18f8Sesaxe void * 265*fb2f18f8Sesaxe group_iterate(group_t *g, group_iter_t *iter) 266*fb2f18f8Sesaxe { 267*fb2f18f8Sesaxe uint_t idx = *iter; 268*fb2f18f8Sesaxe void *data = NULL; 269*fb2f18f8Sesaxe 270*fb2f18f8Sesaxe while (idx < g->grp_size) { 271*fb2f18f8Sesaxe data = g->grp_set[idx++]; 272*fb2f18f8Sesaxe if (data != NULL) 273*fb2f18f8Sesaxe break; 274*fb2f18f8Sesaxe } 275*fb2f18f8Sesaxe *iter = idx; 276*fb2f18f8Sesaxe 277*fb2f18f8Sesaxe return (data); 278*fb2f18f8Sesaxe } 279*fb2f18f8Sesaxe 280*fb2f18f8Sesaxe /* 281*fb2f18f8Sesaxe * Indexed access to a group's elements 282*fb2f18f8Sesaxe */ 283*fb2f18f8Sesaxe void * 284*fb2f18f8Sesaxe group_access_at(group_t *g, uint_t idx) 285*fb2f18f8Sesaxe { 286*fb2f18f8Sesaxe if (idx >= g->grp_capacity) 287*fb2f18f8Sesaxe return (NULL); 288*fb2f18f8Sesaxe 289*fb2f18f8Sesaxe return (g->grp_set[idx]); 290*fb2f18f8Sesaxe } 291*fb2f18f8Sesaxe 292*fb2f18f8Sesaxe /* 293*fb2f18f8Sesaxe * Add a new ordered group element at specified 294*fb2f18f8Sesaxe * index. The group must already be of sufficient 295*fb2f18f8Sesaxe * capacity to hold an element at the specified index. 296*fb2f18f8Sesaxe * 297*fb2f18f8Sesaxe * Returns 0 if addition was sucessful, and -1 if the 298*fb2f18f8Sesaxe * addition failed because the table was too small 299*fb2f18f8Sesaxe */ 300*fb2f18f8Sesaxe int 301*fb2f18f8Sesaxe group_add_at(group_t *g, void *e, uint_t idx) 302*fb2f18f8Sesaxe { 303*fb2f18f8Sesaxe if (idx >= g->grp_capacity) 304*fb2f18f8Sesaxe return (-1); 305*fb2f18f8Sesaxe 306*fb2f18f8Sesaxe if (idx >= g->grp_size) 307*fb2f18f8Sesaxe g->grp_size = idx + 1; 308*fb2f18f8Sesaxe 309*fb2f18f8Sesaxe ASSERT(g->grp_set[idx] == NULL); 310*fb2f18f8Sesaxe g->grp_set[idx] = e; 311*fb2f18f8Sesaxe return (0); 312*fb2f18f8Sesaxe } 313*fb2f18f8Sesaxe 314*fb2f18f8Sesaxe /* 315*fb2f18f8Sesaxe * Remove the entry at the specified index 316*fb2f18f8Sesaxe */ 317*fb2f18f8Sesaxe void 318*fb2f18f8Sesaxe group_remove_at(group_t *g, uint_t idx) 319*fb2f18f8Sesaxe { 320*fb2f18f8Sesaxe ASSERT(idx < g->grp_capacity); 321*fb2f18f8Sesaxe g->grp_set[idx] = NULL; 322*fb2f18f8Sesaxe } 323