13434Sesaxe /* 23434Sesaxe * CDDL HEADER START 33434Sesaxe * 43434Sesaxe * The contents of this file are subject to the terms of the 53434Sesaxe * Common Development and Distribution License (the "License"). 63434Sesaxe * You may not use this file except in compliance with the License. 73434Sesaxe * 83434Sesaxe * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93434Sesaxe * or http://www.opensolaris.org/os/licensing. 103434Sesaxe * See the License for the specific language governing permissions 113434Sesaxe * and limitations under the License. 123434Sesaxe * 133434Sesaxe * When distributing Covered Code, include this CDDL HEADER in each 143434Sesaxe * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153434Sesaxe * If applicable, add the following below this CDDL HEADER, with the 163434Sesaxe * fields enclosed by brackets "[]" replaced with your own identifying 173434Sesaxe * information: Portions Copyright [yyyy] [name of copyright owner] 183434Sesaxe * 193434Sesaxe * CDDL HEADER END 203434Sesaxe */ 213434Sesaxe /* 22*8906SEric.Saxe@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 233434Sesaxe * Use is subject to license terms. 243434Sesaxe */ 253434Sesaxe 263434Sesaxe #include <sys/systm.h> 273434Sesaxe #include <sys/param.h> 283434Sesaxe #include <sys/debug.h> 293434Sesaxe #include <sys/kmem.h> 303434Sesaxe #include <sys/group.h> 313434Sesaxe 323434Sesaxe 333434Sesaxe #define GRP_SET_SIZE_DEFAULT 2 343434Sesaxe 353434Sesaxe static void group_grow_set(group_t *); 363434Sesaxe static void group_shrink_set(group_t *); 373434Sesaxe static void group_pack_set(void **, uint_t); 383434Sesaxe 393434Sesaxe /* 403434Sesaxe * Initialize a group_t 413434Sesaxe */ 423434Sesaxe void 433434Sesaxe group_create(group_t *g) 443434Sesaxe { 453434Sesaxe bzero(g, sizeof (group_t)); 463434Sesaxe } 473434Sesaxe 483434Sesaxe /* 493434Sesaxe * Destroy a group_t 503434Sesaxe * The group must already be empty 513434Sesaxe */ 523434Sesaxe void 533434Sesaxe group_destroy(group_t *g) 543434Sesaxe { 553434Sesaxe ASSERT(g->grp_size == 0); 563434Sesaxe 573434Sesaxe if (g->grp_capacity > 0) { 583434Sesaxe kmem_free(g->grp_set, g->grp_capacity * sizeof (void *)); 593434Sesaxe g->grp_capacity = 0; 603434Sesaxe } 613434Sesaxe g->grp_set = NULL; 623434Sesaxe } 633434Sesaxe 643434Sesaxe /* 65*8906SEric.Saxe@Sun.COM * Empty a group_t 66*8906SEric.Saxe@Sun.COM * Capacity is preserved. 67*8906SEric.Saxe@Sun.COM */ 68*8906SEric.Saxe@Sun.COM void 69*8906SEric.Saxe@Sun.COM group_empty(group_t *g) 70*8906SEric.Saxe@Sun.COM { 71*8906SEric.Saxe@Sun.COM int i; 72*8906SEric.Saxe@Sun.COM int sz = g->grp_size; 73*8906SEric.Saxe@Sun.COM 74*8906SEric.Saxe@Sun.COM g->grp_size = 0; 75*8906SEric.Saxe@Sun.COM for (i = 0; i < sz; i++) 76*8906SEric.Saxe@Sun.COM g->grp_set[i] = NULL; 77*8906SEric.Saxe@Sun.COM } 78*8906SEric.Saxe@Sun.COM 79*8906SEric.Saxe@Sun.COM /* 803434Sesaxe * Add element "e" to group "g" 813434Sesaxe * 823434Sesaxe * Returns -1 if addition would result in overcapacity, and 833434Sesaxe * resize operations aren't allowed, and 0 otherwise 843434Sesaxe */ 853434Sesaxe int 863434Sesaxe group_add(group_t *g, void *e, int gflag) 873434Sesaxe { 883434Sesaxe int entry; 893434Sesaxe 903434Sesaxe if ((gflag & GRP_NORESIZE) && 913434Sesaxe g->grp_size == g->grp_capacity) 923434Sesaxe return (-1); 933434Sesaxe 943434Sesaxe ASSERT(g->grp_size != g->grp_capacity || (gflag & GRP_RESIZE)); 953434Sesaxe 963434Sesaxe entry = g->grp_size++; 973434Sesaxe if (g->grp_size > g->grp_capacity) 983434Sesaxe group_grow_set(g); 993434Sesaxe 1003434Sesaxe ASSERT(g->grp_set[entry] == NULL); 1013434Sesaxe g->grp_set[entry] = e; 1023434Sesaxe 1033434Sesaxe return (0); 1043434Sesaxe } 1053434Sesaxe 1063434Sesaxe /* 1073434Sesaxe * Remove element "e" from group "g" 1083434Sesaxe * 1093434Sesaxe * Returns -1 if "e" was not present in "g" and 0 otherwise 1103434Sesaxe */ 1113434Sesaxe int 1123434Sesaxe group_remove(group_t *g, void *e, int gflag) 1133434Sesaxe { 1143434Sesaxe int i; 1153434Sesaxe 1163434Sesaxe /* 1173434Sesaxe * Find the element in the group's set 1183434Sesaxe */ 1193434Sesaxe for (i = 0; i < g->grp_size; i++) 1203434Sesaxe if (g->grp_set[i] == e) 1213434Sesaxe break; 1223434Sesaxe if (g->grp_set[i] != e) 1233434Sesaxe return (-1); 1243434Sesaxe 1253434Sesaxe g->grp_set[i] = NULL; 1263434Sesaxe group_pack_set(g->grp_set, g->grp_size); 1273434Sesaxe g->grp_size--; 1283434Sesaxe 1293434Sesaxe if ((gflag & GRP_RESIZE) && 1303434Sesaxe g->grp_size > GRP_SET_SIZE_DEFAULT && 1313434Sesaxe ((g->grp_size - 1) & g->grp_size) == 0) 1323434Sesaxe group_shrink_set(g); 1333434Sesaxe 1343434Sesaxe return (0); 1353434Sesaxe } 1363434Sesaxe 1373434Sesaxe /* 1383434Sesaxe * Expand the capacity of group "g" so that it may 1393434Sesaxe * contain at least "n" elements 1403434Sesaxe */ 1413434Sesaxe void 1423434Sesaxe group_expand(group_t *g, uint_t n) 1433434Sesaxe { 1443434Sesaxe while (g->grp_capacity < n) 1453434Sesaxe group_grow_set(g); 1463434Sesaxe } 1473434Sesaxe 1483434Sesaxe /* 1493434Sesaxe * Upsize a group's holding capacity 1503434Sesaxe */ 1513434Sesaxe static void 1523434Sesaxe group_grow_set(group_t *g) 1533434Sesaxe { 1543434Sesaxe uint_t cap_old, cap_new; 1553434Sesaxe void **set_old, **set_new; 1563434Sesaxe 1573434Sesaxe cap_old = g->grp_capacity; 1583434Sesaxe set_old = g->grp_set; 1593434Sesaxe 1603434Sesaxe /* 1613434Sesaxe * The array size grows in powers of two 1623434Sesaxe */ 1633434Sesaxe if ((cap_new = (cap_old << 1)) == 0) { 1643434Sesaxe /* 1653434Sesaxe * The set is unallocated. 1663434Sesaxe * Allocate a default sized set. 1673434Sesaxe */ 1683434Sesaxe cap_new = GRP_SET_SIZE_DEFAULT; 1693434Sesaxe g->grp_set = kmem_zalloc(cap_new * sizeof (void *), KM_SLEEP); 1703434Sesaxe g->grp_capacity = cap_new; 1713434Sesaxe } else { 1723434Sesaxe /* 1733434Sesaxe * Allocate a newly sized array, 1743434Sesaxe * copy the data, and free the old array. 1753434Sesaxe */ 1763434Sesaxe set_new = kmem_zalloc(cap_new * sizeof (void *), KM_SLEEP); 1773434Sesaxe (void) kcopy(set_old, set_new, cap_old * sizeof (void *)); 1783434Sesaxe g->grp_set = set_new; 1793434Sesaxe g->grp_capacity = cap_new; 1803434Sesaxe kmem_free(set_old, cap_old * sizeof (void *)); 1813434Sesaxe } 1823434Sesaxe /* 1833434Sesaxe * The new array size should be a power of two 1843434Sesaxe */ 1853434Sesaxe ASSERT(((cap_new - 1) & cap_new) == 0); 1863434Sesaxe } 1873434Sesaxe 1883434Sesaxe /* 1893434Sesaxe * Downsize a group's holding capacity 1903434Sesaxe */ 1913434Sesaxe static void 1923434Sesaxe group_shrink_set(group_t *g) 1933434Sesaxe { 1943434Sesaxe uint_t cap_old, cap_new; 1953434Sesaxe void **set_old, **set_new; 1963434Sesaxe 1973434Sesaxe cap_old = g->grp_capacity; 1983434Sesaxe set_old = g->grp_set; 1993434Sesaxe 2003434Sesaxe /* 2013434Sesaxe * The group's existing array size must already 2023434Sesaxe * be a power of two 2033434Sesaxe */ 2043434Sesaxe ASSERT(((cap_old - 1) & cap_old) == 0); 2053434Sesaxe cap_new = cap_old >> 1; 2063434Sesaxe 2073434Sesaxe /* 2083434Sesaxe * GRP_SET_SIZE_DEFAULT is the minumum set size. 2093434Sesaxe */ 2103434Sesaxe if (cap_new < GRP_SET_SIZE_DEFAULT) 2113434Sesaxe return; 2123434Sesaxe 2133434Sesaxe set_new = kmem_zalloc(cap_new * sizeof (void *), KM_SLEEP); 2143434Sesaxe (void) kcopy(set_old, set_new, cap_new * sizeof (void *)); 2153434Sesaxe g->grp_capacity = cap_new; 2163434Sesaxe g->grp_set = set_new; 2173434Sesaxe 2183434Sesaxe ASSERT(((cap_new - 1) & cap_new) == 0); 2193434Sesaxe kmem_free(set_old, cap_old * sizeof (void *)); 2203434Sesaxe } 2213434Sesaxe 2223434Sesaxe /* 2233434Sesaxe * Pack a group's set 2243434Sesaxe * Element order is not preserved 2253434Sesaxe */ 2263434Sesaxe static void 2273434Sesaxe group_pack_set(void **set, uint_t sz) 2283434Sesaxe { 2293434Sesaxe uint_t i, j, free; 2303434Sesaxe 2313434Sesaxe free = (uint_t)-1; 2323434Sesaxe 2333434Sesaxe for (i = 0; i < sz; i++) { 2343434Sesaxe if (set[i] == NULL && free == (uint_t)-1) { 2353434Sesaxe /* 2363434Sesaxe * Found a new free slot. 2373434Sesaxe * Start packing from here. 2383434Sesaxe */ 2393434Sesaxe free = i; 2403434Sesaxe } else if (set[i] != NULL && free != (uint_t)-1) { 2413434Sesaxe /* 2423434Sesaxe * Found a slot to pack into 2433434Sesaxe * an earlier free slot. 2443434Sesaxe */ 2453434Sesaxe ASSERT(set[free] == NULL); 2463434Sesaxe set[free] = set[i]; 2473434Sesaxe set[i] = NULL; 2483434Sesaxe 2493434Sesaxe /* 2503434Sesaxe * Find the next free slot 2513434Sesaxe */ 2523434Sesaxe for (j = free + 1; set[j] != NULL; j++) { 2533434Sesaxe ASSERT(j <= i); 2543434Sesaxe if (j == i) 2553434Sesaxe break; 2563434Sesaxe } 2573434Sesaxe if (set[j] == NULL) 2583434Sesaxe free = j; 2593434Sesaxe else 2603434Sesaxe free = (uint_t)-1; 2613434Sesaxe } 2623434Sesaxe } 2633434Sesaxe } 2643434Sesaxe 2653434Sesaxe /* 2663434Sesaxe * Initialize a group iterator cookie 2673434Sesaxe */ 2683434Sesaxe void 2693434Sesaxe group_iter_init(group_iter_t *iter) 2703434Sesaxe { 2713434Sesaxe *iter = 0; 2723434Sesaxe } 2733434Sesaxe 2743434Sesaxe /* 2753434Sesaxe * Iterate over the elements in a group 2763434Sesaxe */ 2773434Sesaxe void * 2783434Sesaxe group_iterate(group_t *g, group_iter_t *iter) 2793434Sesaxe { 2803434Sesaxe uint_t idx = *iter; 2813434Sesaxe void *data = NULL; 2823434Sesaxe 2833434Sesaxe while (idx < g->grp_size) { 2843434Sesaxe data = g->grp_set[idx++]; 2853434Sesaxe if (data != NULL) 2863434Sesaxe break; 2873434Sesaxe } 2883434Sesaxe *iter = idx; 2893434Sesaxe 2903434Sesaxe return (data); 2913434Sesaxe } 2923434Sesaxe 2933434Sesaxe /* 2943434Sesaxe * Indexed access to a group's elements 2953434Sesaxe */ 2963434Sesaxe void * 2973434Sesaxe group_access_at(group_t *g, uint_t idx) 2983434Sesaxe { 2993434Sesaxe if (idx >= g->grp_capacity) 3003434Sesaxe return (NULL); 3013434Sesaxe 3023434Sesaxe return (g->grp_set[idx]); 3033434Sesaxe } 3043434Sesaxe 3053434Sesaxe /* 3063434Sesaxe * Add a new ordered group element at specified 3073434Sesaxe * index. The group must already be of sufficient 3083434Sesaxe * capacity to hold an element at the specified index. 3093434Sesaxe * 3103434Sesaxe * Returns 0 if addition was sucessful, and -1 if the 3113434Sesaxe * addition failed because the table was too small 3123434Sesaxe */ 3133434Sesaxe int 3143434Sesaxe group_add_at(group_t *g, void *e, uint_t idx) 3153434Sesaxe { 3163434Sesaxe if (idx >= g->grp_capacity) 3173434Sesaxe return (-1); 3183434Sesaxe 3193434Sesaxe if (idx >= g->grp_size) 3203434Sesaxe g->grp_size = idx + 1; 3213434Sesaxe 3223434Sesaxe ASSERT(g->grp_set[idx] == NULL); 3233434Sesaxe g->grp_set[idx] = e; 3243434Sesaxe return (0); 3253434Sesaxe } 3263434Sesaxe 3273434Sesaxe /* 328*8906SEric.Saxe@Sun.COM * Remove the element at the specified index 3293434Sesaxe */ 3303434Sesaxe void 3313434Sesaxe group_remove_at(group_t *g, uint_t idx) 3323434Sesaxe { 3333434Sesaxe ASSERT(idx < g->grp_capacity); 3343434Sesaxe g->grp_set[idx] = NULL; 3353434Sesaxe } 336*8906SEric.Saxe@Sun.COM 337*8906SEric.Saxe@Sun.COM /* 338*8906SEric.Saxe@Sun.COM * Find an element in the group, and return its index 339*8906SEric.Saxe@Sun.COM * Returns -1 if the element could not be found. 340*8906SEric.Saxe@Sun.COM */ 341*8906SEric.Saxe@Sun.COM uint_t 342*8906SEric.Saxe@Sun.COM group_find(group_t *g, void *e) 343*8906SEric.Saxe@Sun.COM { 344*8906SEric.Saxe@Sun.COM uint_t idx; 345*8906SEric.Saxe@Sun.COM 346*8906SEric.Saxe@Sun.COM for (idx = 0; idx < g->grp_capacity; idx++) { 347*8906SEric.Saxe@Sun.COM if (g->grp_set[idx] == e) 348*8906SEric.Saxe@Sun.COM return (idx); 349*8906SEric.Saxe@Sun.COM } 350*8906SEric.Saxe@Sun.COM return ((uint_t)-1); 351*8906SEric.Saxe@Sun.COM } 352